관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[네트워크] locust를 사용하여 다중 클라이언트 연결 웹 서버 구조와 성능 테스트(feat. select) 본문

네트워크

[네트워크] locust를 사용하여 다중 클라이언트 연결 웹 서버 구조와 성능 테스트(feat. select)

막무가내막내 2019. 12. 18. 02:49
728x90

 

 

테스트를 위해 Locust라는 서버 테스트 도구를 사용하도록 한다. 그리고 도커 컨테이너 안에 서버를 두도록 한다. 서버는 단일 프로세스, 멀티 프로세스, 멀티 스레드 소켓 서버가 있다. python 코드로 구현하였다. 각 소 켓 서버의 성능을 테스트하고 차이점을 알아보았다.

 

 

가장 먼저 도커 안에 단일 프로세스, 멀티 프로세스, 멀티 스레드 소켓 서버를 만들고 클라이언트에서 locust를 사용해서 도커의 서버에 접속했다. 테스트환 경은 내 노트북 윈도우의 vmware 리눅스 안에 도커 서버를 두고 같은 와이 파이 환경인 친구의 맥북을 클라이언트로 사용하였다. 도커에서는 포트 8000번을 열고 외부에서는 1234 포트로 접속하면 된다. (포 트 포워딩)

 

참고로 locust 는 다운받고 locust 테스트할 파일을 만들어줘야한다.

pip3 install locustio
locustfile.py 파일 생성
locust -f locustfile.py --host=http://myIP.address:port
locust 접속 ->  http://locust.ip.address:8089

 

모든 테스트의 기준은 위와 같이 하였다. 각각 가상 유저 수와 초당 실행 수를 의미한다.

 

 

 

 

 

ifconfig 결과는 다음과 같다. ip:172.30.1.53으로 접속하면 된다

 

 

사용한 파일을 먼저 첨부한다. 

multiProcessServer.py
0.00MB
multiThreadServer.py
0.00MB
singleProcessServer.py
0.00MB

 

들어가기 앞서 주의점.

P.S 정확한 결과를 알고싶으면 join()의 위치를 다음과 같이 while문 밖으로 뺴야한다. 즉 인터럽트 즉 예외가 발생하면 join()을 실행하게 수정해야한다. (밑에 나온다)

 

1. 단일 프로세스 소켓 서버

단일 프로세스는 데이터가 send/recv가 완료될 때까지  block되고, 다른 프로세스에게 자원을 넘긴다. 즉 동시에 처리하지 못한다. 응답메세지도 200 OK 로 보내준다.

 

단일 프로세스의 locust 결과는 다음과 같다.

클라이언트에서 get 요청을 단일 프로세스 소켓 서버에게 보낸다.  RPS(requests per second) 가 765.7이다. 18367번의 요청을 했을 시 failure가 발생한다. failure는 단일 프로세스가 처리할 수 있는 양을 넘어서 발생하게 된다. 평균 응답시간은 83ms이다.

 

 

 

 

 

2. 멀티 프로세스 소켓 서버

멀티프로세스는 클라이언트를 동시에 처리할 수 있다. fork()를 통해 클라이언 트가 accept되면 process를 복사한다. 다수의 프로세스로 클라이언트의 요청 을 처리한다. 그리고 200 OK 응답 메세지를 보내준다.

 

 

멀티프로세스의 locust 테스트 결과는 다음과 같다.

클라이언트에서 get 요청을 단일 프로세스 소켓 서버에게 보낸다.  RPS 가 768이다. 19221번의 요청을 했을 시 failure가 발생한다. failure는 멀티 프로 세스가 처리할 수 있는 양을 넘어서 발생하게 된다. 평균 응답시간은 90ms이다.

 

 

 

3. 멀티 스레드 소켓 서버

멀티 스레드도 클라이언트를 동시에 처리할 수 있다. 하나의 프로세스 안에서 스레드를 이용해서 클라이언트의 요청을 처리한다. 그리고 클라이언트에게 200 OK 응답 메시지를 보내준다.

 

멀티 스레드의 locust 테스트 결과는 다음과 같다.

 

클라이언트에서 get 요청을 단일 프로세스 소켓 서버에게 보낸다.  RPS 가 554.3이다. 10727번의 요청을 했을 시 failure가 발생한다. failure는 멀티 스 레드가 처리할 수 있는 양을 넘어서 발생하게 된다. 평균 응답시간은 151ms이다.

 

 

 

비교 (단일 프로세스 vs 멀티 프로세스 vs 멀티 스레드 소켓 서버)
1. Failure 뜰 때까지의 최대 RPS 멀티 스레드(554.3) < 단일 프로세스(765.7) < 멀티 프로세스(768) 
2. 평균 응답 시간(ms) 단일 프로세스(83) < 멀티 프로세스(90) < 멀티 스레드(151) 
3. Failure 뜰 때까지의 요청 수 멀티 스레드(10727)  < 단일 프로세스(18367) < 멀티 프로세스(19221)

 

P.S 정확한 결과를 알고싶으면 join()의 위치를 다음과 같이 while문 밖으로 뺴야한다. 즉 인터럽트 즉 예외가 발생하면 join()을 실행하게 수정해야한다.

 

(멀티스레드)

(멀티프로세스)

 

 

 


[SELECT 사용]

위에서 했던거에서 join() 의 위치를 수정하고 HTTP Server를 구현하는데 Select를 이용한 Multiplexing을 추가하였다. 결론적으로 총 구현 방법은 SingleProcess, MultiProcess, MultiThread, Select이다. Select란 하나 이상의 file descriptor가 가 I/O에 대해서 ‘ready'상태가 될때 까지 기다리면서 여러 파일 디스크립터를 모니터 하는 것이다. Select Multiplexing(다중화)을 사용하여 select가 여러 socket descriptor를 관리하고 스레드,  프로세스와 달리 context switching이 발생하지 않아 효율적이다. 

 

수용 가능한(locust 실행 후Fail이 뜰때까지의) 최대 RPS와 다중 클라이언트 환경에서 평균 응답시간에 초점을 맞추어 결과를 확인했다.

 

 

4. select 서버 코드

selectServer.py
0.00MB

select를 사용한 서버의 코드이다. 클라이언트가 소켓을 select가 관리한다. r_list(리스트)에 클라이언트 소켓들이 저장이 된다. 그리고 처리한 클라이언트 소켓은 리스트에서 제거된다.

 

다음은 locust 실행결과이다.

 

 

 

 

 

 

[총정리 결과]

RPS는 Select > Multi Process > Multi Thread > Single Process 순이고 평균응답속도를 빠른 순으로 적으면 다음과 같다. Select, Multi Process, Multi Thread, Single Process 전체적으로 Select가 성능이 우수하다는 것을 볼 수 있다.

 

 

728x90
Comments