imhamburger 님의 블로그

데이터엔지니어 부트캠프 - nGrinder로 Nginx 로드밸런서 분산 처리 테스트해보기 (with Docker) (9주차) 본문

데이터엔지니어 부트캠프

데이터엔지니어 부트캠프 - nGrinder로 Nginx 로드밸런서 분산 처리 테스트해보기 (with Docker) (9주차)

imhamburger 2024. 9. 6. 15:46

*사전에 준비되어야 할 사항

 

1. nginx 로드밸런서만 실행시킬 EC2 인스턴스 1개

2. API를 실행시킬 EC2 인스턴스 5개 (같은 API 기능을 5개의 인스턴스에 1개씩 실행)

3. 성능테스트를 진행할 nGrinder 를 실행시킬 EC2 인스턴스 1개

4. API 기능 도커 이미지 build 

5. nginx 로드밸런서 도커 이미지 build 

6. nGrinder용 EC2를 제외한 각각의 EC2 인스턴스에 Docker 설치

 

따라서, 총 7개의 EC2 인스턴스가 필요하다.

 

 

전체적인 그림은 다음과 같다.

 

사용자들은 nGrinder를 이용해 Virtual user로 세팅할 것이며, nginx를 이용한 로드밸런서가 사용자들을  분산하여 한쪽 서버에만 과부하되지 않게 처리한다.

 

이때, 주의해야할 것은 각 기능을 서버에 다 세팅하고 로드밸런서를 연결해야 한다.

로드밸런서를 먼저 실행하고 기능들을 하나씩 연결하면 로드밸런서는 먼저 연결된 기능에만 처리하게끔 하기 때문에 과부하가 오고.. 그렇게되면 서버가 다운될 수 있다. 그럼 다음 서버를 연결해도 그 서버에 또 같은 일이 일어난다.

그러니 각 기능을 서버에 먼.저 세팅을 하고 로드밸런서를 나중에 연결시켜야 한다.

 

 

 

단계 1: API 기능을 도커 이미지로 build하여 EC2에서 실행

 

로드밸런서를 먼저 실행시키지 않고 기능을 실행시키는 이유는 로드밸런서를 먼저 켜고 

 

나는 이미 도커 허브에 API 기능이 담긴 도커이미지를 push해놓았다. 그래서 EC2에서 바로 도커를 실행하고 도커이미지를 pull 받아 run 하였다. (내가 push한 도커이미지)

*push해놓은 이미지가 없다면, 만들어놓은 기능을 git clone하여 받아오고 이미지를 build하여 사용하면 된다.

 

도커 pull 명령어

docker pull <이미지 이름>:<TAG>

 

도커 run 명령어

docker run -d -p <외부에 보여질 PORT> :8080 --name <컨테이너 이름 지정> <이미지 이름>:<TAG>

#예시
docker run -d -p 8081:8080 --name ml-1 hamsunwoo/fishmlserv:1.2.1

 

도커 실행중인 컨테이너 확인

docker ps

 

이 과정을 5개의 인스턴스에 똑같이 해주되 <외부에 보여질 PORT>번호만 달리 주면 된다.

나는 참고로 포트번호를 각각 8081 / 8082 / 8083 / 8084 / 8085 로 주었다.

 

 

 

단계 2: 위에서 작업한 IP주소와 포트번호를 이용하여 nginx 로드밸런서에 연결

 

nginx 로드밸런서에 위에서 도커로 띄운 API 기능들을 연결시키려면 각 API를 띄운 EC2 Private IP 주소와 각각 <외부에 보여질 PORT> 를 default.conf에 적어주면 된다.

 

나는 LB라는 폴더 안에 Dockerfile과 default.conf 를 만들었다.

Dockerfile을 만든 이유는 로드밸런서도 도커이미지로 build하여 실행시킬 것이기 때문이다.

 

Dockerfile

FROM nginx:1.25.1

COPY default.conf /etc/nginx/conf.d/

 

default.conf

upstream ml_servers {
        server <프라이빗 IP주소>:<PORT>; #8081
        server <프라이빗 IP주소>:<PORT>; #8082
        server <프라이빗 IP주소>:<PORT>; #8083
        server <프라이빗 IP주소>:<PORT>; #8084
        server <프라이빗 IP주소>:<PORT>; #8085
}

server {
        listen 80;

        location / {
                proxy_pass http://ml_servers;
        }
}

 

만들어놓은 LB 를 로컬에서 실행할 것이 아니기 때문에 EC2로 복사하여 가져온다.

굳이 복사해서 가져올 필요없이 깃허브에 있던 것을 EC2에서 git clone하여 가져와도 된다.

 

여기서 Private IP 주소로 설정해주는 이유는 보안 때문이다. 퍼블릭 IP 주소로 넣으면 위험이 따를 수 있다!! DDos 공격같은...

 

만약, server를 도커로 띄었다면 아래와 같이 server를 지정할 수도 있다.

server <Docker 컨테이너 이름>:80;

 

 

위에서 했던 방식 그대로 LB도 이미지로 build하여 run해보자.

 

도커이미지 build

docker build -t <이미지 이름 입력>:<TAG 입력> LB/ #LB/ 폴더안에 Dockerfile이 존재

 

 

도커 run 명령어

docker run -p <외부에 보여질 PORT>:80 -d --name <컨테이너 이름 입력> <이미지 이름>:<TAG>

#예시
docker run -p 8892:80 -d --name lb-1 hamsunwoo/lb:1.2.5

 

내가 사용하는 로드밸런서는 nginx 인데, nginx의 포트번호는 80이다. 따라서, 내부의 포트번호는 도커 포트번호 8080이 아닌 80으로 지정해줘야 한다.

 

 

 

로컬에서 서로 같은서버를 사용할 때랑은 방법이 다르다!

 

원래 로컬에서 --link <컨테이너 이름> 을 줘서 실행되고 있는 도커 컨테이너를 연결시켰었는데, 서로 다른 서버로 연결하여 사용할 때에는 도커 --link 를 주지않고 포트번호를 별도로 줘야한다.

 

같은 서버로 연결할 경우: --link 를 사용할 수 있다.

docker run -d -p <외부에 보여질 PORT>:80 --link <연결할 컨테이너이름> --link <연결할 컨테이너이름> --name <이름 입력> <이미지 이름>:<TAG>

#예시
docker run -d -p 8892:80 --link ml-1 --link ml-2 --name lb-2 ml-lb:1.2.5

 

다만, 로드밸런서를 제외한 연결될 도커컨테이너는 run을 할 때 포트번호를 안줘야 한다.

 

 

 

단계 3: nGrinder로 성능테스트 진행하기

 

nGrinder가 뭔지 모른다면 이전글 참고!

nGrinder 용 EC2 서버에 nGrinder를 설치 후 실행해준 후, 접속하여 테스트할 주소를 적어 성능테스트를 진행하면 끄-읕!

기능 5개가 연결된 로드밸런서를 nGrinder에서 성능테스트를 할 때 <프라이빗 IP 주소>:<포트번호> 로 해야 한다.

<퍼블릭 IP 주소>로 하면 에러난다!!!

 

docker stats 를 이용하여 CPU와 메모리 사용량을 실시간으로 확인할 수 있다.

docker stats

 

 

혹은,

 

datadog 이라는 플랫폼을 사용하여 확인할 수 있다.

 

 

결과

 

서버를 4개로 분산처리

 

서버를 3개로 분산처리

 

서버를 1개로 분산처리

 

확실히 서버를 1개로만 처리하였을 때 에러율이 높았다!!

 

 

 

서버 상태 확인 방법

 

nGrinder 성능 테스트를 하기 전에 터미널에서 서버가 정상적으로 동작하는지 확인하려면:

$ curl http://<프라이빗 IP 주소>:<PORT>

 

만약 URL에 ?, & 같은 특수 문자가 포함되어 있다면, **역슬래시(\)**를 추가해 확인해야 한다.

curl http://<프라이빗 IP주소>:<PORT>/fish\?l=25\&w=150

 

 

 

일주일을 보내면서...

 

이번 주에는 성능 테스트를 돌리면서 다양한 시나리오를 만들어보고, 예상치 못한 문제들도 해결해가며 꽤나 바쁜 시간을 보냈다. 기능을 개발하는 것만큼이나 중요한 것이, 실제 유저들이 대거 몰렸을 때에도 시스템이 원활하게 작동하는지 확인하는 과정이다. 이 부분이 잘 준비되지 않으면 아무리 좋은 기능이라도 유저들에게 제대로 전달되지 않을 수 있기 때문에 더욱 신경을 써야 한다는 것을 알았다.

이 과정에서 여러 번의 수정과 테스트를 반복하면서 초당 처리가능한 수, 에러율, 지연시간 등에 대해 조금은 익숙해진 것 같다. 그러나 다양한 시나리오를 생각해내는 과정이 어려웠던 것 같다.

 


앞으로 나아갈 방향


팀 프로젝트가 끝난 후, 잠시 여유를 찾을 수 있었다. 이 틈을 타서 새로운 도전으로 공모전을 준비하고 있다. 처음 도전하는 공모전이라 어떻게 준비해야 할지 막막하지만, 차근차근 계획을 세워나가며 최선을 다해보고자 한다. 공모전 준비 과정에서 새로운 경험과 지식을 쌓을 수 있을 거라는 기대가 크다.

이번 기회를 통해 좀 더 다양한 스킬을 배우고, 프로젝트 관리 능력도 키우고 싶다. 나 혼자만의 프로젝트가 아니라 여러 사람과 협력하면서 서로의 강점을 최대한 발휘할 수 있도록 이끌어가는 것도 중요한 부분일 것이다. 이 모든 과정이 나에게 있어 큰 성장의 발판이 될 것이라 믿으며, 앞으로의 도전에 열심히 임할 생각이다.

무엇보다, 실패를 두려워하지 않고 계속해서 도전하는 자세를 잃지 않고자 한다.