본문 바로가기
출처 : http://kenial.tistory.com/917 

이 글의 내용을 요약하면, "대량의 TCP / WebSocket 동시 연결(최소 65K 이상, 가능하다면 10M)을 처리하기 위한 환경을 구성하고 Tornado를 사용해 이를 테스트하는 간단한 프로그램을 만들어 보았다”이다. 일반적으로 재미있을만한 주제가 아니므로, 관심이 없는 내용이라면 뒤로 가기 버튼을 눌러 재빨리 빠져나가도록 하자.

 

이 작업을 시작한 이유는, 그 동안 개인 프로젝트(Fountain)를 진행하면서 Scale-up에 대해 생겼던 궁금점을 해결하기 위함이었다. 대량의 웹 트래픽 처리에 관심이 있는 사람이라면 C10K problem(=10,000개 이상의 네트워크 동시 연결Concurrent connection을 지원하는 서버를 구축하는 문제)에 대해 들어본 적이 있겠지만, 사실 유닉스 계열 운영체제에서 이 문제는 시스템에서 사용 가능한 file descriptor 숫자만 늘려주면 된다. 예전에야 컴퓨터의 리소스가 한정되어 있어 극단의 최적화가 필요했겠지만, 어쨌든 요즘 나오는 PC라면 최대 fd 수만 늘려줌으로써 (성능이야 어떻든) 10K 이상의 소켓 연결을 처리할 수 있다.

 

나는 TCP / WebSocket 연결을 지원하는 리얼타임 서버를 만들어야 했었고, Tornado로 이걸 구현하기로 했다. fd 숫자를 늘리고, local port range를 조정하고, 간단한 서버 / 클라이언트 코드를 작성해서 50,000개의 연결이 제대로 생성되고, 메시지를 주고받는 것을 확인하였다. 이게 작년의 이야기. (C10K tuning에 관련된 내용은 구글에 검색해 보면 많이 있으므로 그 내용을 참고하시라)

 

그리고 시간은 흘러서 얼마 전 모 회사에서 인터뷰를 할 일이 있었는데, 리얼타임 서버에 대한 이야기가 나왔다. 이 시점까지 나는 리얼타임 서버가 50K 이상의 연결을 처리할 일이 있을까에 대한 생각 자체를 해보지 않았다. 예를 들어보자면, 안드로이드를 지원하는 Push notification 서버 혹은 Messaging server 같은 경우 실제 트래픽은 상대적으로 적지만 대량의 연결을 계속 유지해야 하는 경우가 있다. 이런 유형의 서버가 있을 때 Scale-up을 어떻게 할지에 대한 질문을 받은 것이었다. inbound traffic을 모니터링하면서 상대적으로 가벼운 인스턴스를 계속 spawn하면 되지 않겠느냐 했지만 그것은 올바른 대답이 아니었다(…)

 

계속 인터뷰는 이어져서 내 개인 프로젝트에 대한 이야기가 나왔을 때, 내 서버가 얼마나 많은 동시 연결을 처리할 수 있냐는 질문에 ’5만개 연결까지는 테스트해봤지만 아직 그 이상 scale-up에 대해서는 아직 고민해보지 않았는데요’고 대답하니 ‘5만개요? (시무룩)’이라는 반응이 돌아왔다. 여기서 좀 당황했는데, 이때까지 나는 5만 개 이상의 동시 연결을 처리하는 서버를 구현할 일이 있을까라는 생각 자체를 해 본 적이 없기 때문이었다. 아니 이제 5만 개 동시 연결을 처리하는 걸로도 부족한 시대가 되었단 말인가!

 

새삼 궁금해져서 집에 돌아와 관련 내용을 검색해보니 이런 아티클을 찾을 수 있었다:

Whatsapp은 어떻게 5억 명의 사용자, 11,000개의 cpu 코어, 초당 7천만개의 메시지 처리까지 성장하였나 (영문) http://highscalability.com/blog/2014/3/31/how-whatsapp-grew-to-nearly-500-million-users-11000-cores-an.html

 

위 글을 읽어보면 알겠지만, 해당 글이 쓰인 시점에서 Whatsapp은 150대의 챗 서버로 1억 5천만 개의 동시 연결을 처리하고 있었다. 챗 서버 한 대당 1백만 개의 동시 연결을 처리하고, peak time에는 150만개 연결을 처리하기도 했다고.

 

이걸 읽고 나서 처음 든 생각은, ‘그래, 그런 서버를 구현한다고 치고, 테스트는 어떻게 하지?’ 였다. OS가 개별 소켓을 식별하는 방법을 알고 있는 사람이라면 금방 이해하겠지만, 소켓은 보통 local address와 remote address 두 값의 쌍으로 식별되며 (address는 192.168.0.10:8080처럼 ip:port 형태로 표현된다), 이 두 값이 중복되는 소켓은 존재할 수가 없다. 만약 한 개의 호스트 내에서 8080 포트를 listen하는 서버를 실행하고, 클라이언트를 실행해서 여러 개의 소켓을 생성해 이 포트에 연결하면 다음과 같은 주소를 갖는 소켓들이 생성된다:

 

local address remote address
192.168.0.10:20001 192.168.0.10:8080
192.168.0.10:20002 192.168.0.10:8080
192.168.0.10:20003 192.168.0.10:8080
192.168.0.10:20004 192.168.0.10:8080

 

이게 뭐가 문제냐면, 포트 번호는 0~65,535까지로 한정되어 있기 때문에, 이 범위의 포트 번호를 전부 사용하고 나면 더 이상 local address를 위한 포트 번호를 할당할 수 없게 된다. 그러므로 이상적인 상황을 가정할 때 로컬에서 실행한 서버에 연결할 수 있는 최대 연결 수는 65,536개라는 이야기. (물론 실제로는 이런저런 제약 때문에 그 숫자가 더 작아진다) 물론, 서버 한 대와 클라이언트 여러 대가 포함된 테스트 환경을 구축한다면 이 문제는 피할 수 있다. local address에 여러 IP를 사용할 수 있다면 그 IP 개수 만큼 전체 연결 개수를 늘릴 수 있으니까. 하지만 서버 하나 테스트 하겠다고 그런 환경을 구축한다는 건 좀 에러고...

 

그래서 이를 피하기 위해 이용한 꼼수는, 서버가 여러 포트를 listen하게 하는 것. 그렇게 하면 이런 식으로 소켓을 생성할 수 있다:

 

local address remote address
192.168.0.10:20001 192.168.0.10:8080
192.168.0.10:20001 192.168.0.10:8081
192.168.0.10:20002 192.168.0.10:8080
192.168.0.10:20002 192.168.0.10:8081

 

위와 같이, local address가 같더라도 remote address가 다르면 소켓을 식별할 수 있으므로, 서버에 할당한 listen port 수 * 50K 만큼의 연결을 만들어 테스트할 수 있는 것이다. 천만 개의 소켓을 테스트하고 싶다? 서버에 listen port를 200개 할당하면 된다. 즉, 200 * 50,000 = 10,000,000 (10M). 호스트에 여러 IP를 할당하는  것도 한 가지 방법이기는 하지만, 네트워크 설정을 수동으로 변경해야 하므로 귀찮다.

 

 

어쨌든 이런 방법을 사용하면 개발 환경에서도 10M 연결을 테스트할 수 있다. 하지만 주의사항이 있는데, 어떤 이유에서인지 모르겠지만 OS X에서는 이 방법을 사용해도 65K 이상의 연결을 생성할 수 없다. netstat으로 확인한 결과 OS X에서는 remote address가 서로 다르더라도 local address가 중복되는 경우가 없으며, 무조건 local address를 사용하여 소켓을 식별하는 것으로 추정된다. (추정일 뿐이라 정확하지 않을 수 있다. 이 방식을 변경할 수 있는 설정이 어딘가 있을 것 같기도 한데, 불행하게도 찾지 못했다) Ubuntu Server 14.10에서는 확실히 동작하는 것을 확인했으므로, 삽질이 귀찮다면 Ubuntu Server 14.10를 사용하시기를 권한다. 뭔가 잘못되어도 내가 도울 수 있는 부분이 없다;

 

그러면 이제 OS 튜닝으로 넘어가야 하는데… 사실 이 튜닝에 대한 방법은 OS마다 서로 다르고, 어떤 종류의 서버를 구현하느냐에 따라 필요한 설정이 달라지는 관계로 스스로 검색하면서 필요한 내용을 찾아보는 수 밖에 없다. 내 경우만 해도 Ubuntu와 OS X를 같이 세팅해야 했던 상황이라 설정 내용을 공유하기도 그렇고… 이 작업을 하면서 도움이 되었던 링크 몇 개를 공유하는 것으로 대신한다 (모두 영문):

 

The C10K problem

http://www.kegel.com/c10k.html

 

Performance Tuning the Network Stack on Mac OS X Part 2

https://rolande.wordpress.com/2014/05/17/performance-tuning-the-network-stack-on-mac-os-x-part-2/

 

Linux TCP/IP tuning for scalability

http://www.lognormal.com/blog/2012/09/27/linux-tcpip-tuning/

 

RED HAT ENTERPRISE LINUX 7 PERFORMANCE TUNING GUIDE (CentOS에도 적용 가능)

https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Performance_Tuning_Guide/index.html

 

The C10M(!) problem

http://c10m.robertgraham.com/p/manifesto.html

 

 

 

그리고 이를 테스트하기 위해 급조한 코드를 여기 공유한다:

https://github.com/kenial/tornado-test-c10m

 

위 코드는 TCP / WebSocket을 지원하는 Echo 서버와 클라이언트로 구성되어 있는데, 클라이언트에는 대량의 소켓을 생성하거나 메시지를 전송할 수 있는 기능이 구현되어 있다. Python으로 작성되어 있고, 사용하려면 Tornado를 설치해야 한다. PyPy를 사용할 경우 성능 향상이 있기는 한데, 이 프로그램이 하는 일은 대부분 I/O에 관련된 작업이다보니 패킷 전송에는 그다지 성능 향상이 없었고, 연결 생성에는 상당한 성능 향상이 있었다.

 

 

 

Ubuntu Server 14.10에서 실행해 본 소감은, 메모리를 무지하게 먹는다. 위 프로그램을 실행해보면 TCP는 연결당 10.5KB, WebSocket은 연결당 15.5KB 정도가 할당된다. 이는, 만약 1백만 개의 연결을 생성하면 TCP 연결의 경우 1,000,000 * 2 * 10,500 = 21,000,000,000B = 21GiB의 메모리를 사용한다는 의미. (중간에 2를 곱한 것은 소켓이 생성될 때 서버에서 한 개, 클라이언트에서 한 개가 생성되기 때문이다) WebSocket의 경우에는 오버헤드가 더 있어서 31GiB 정도를 사용한다는 계산이 나온다. 1천만 개의 연결이라면? 각각 210GiB, 310GiB가 될 것이다. 케냘 소유의 PC 중에서는 21GB가 넘는 메모리를 가진 시스템이 없기 때문에 1백만 개의 연결 생성조차 테스트할 수가 없었고(…) EC2에 인스턴스를 생성해서야 테스트가 가능했다. 테스트에는 r3.4xlarge 타입의 인스턴스(122GiB memory)가 사용되었다.

 

실행 결과 화면을 첨부하는 것으로 이 글을 마무리할까 한다.

 

 

 

List of Articles
제목 글쓴이 날짜 조회 수
공지 PC/모바일을 제조/유통하는 업체 관계자분을 모십니다 file 가브리엘조 2015-12-15 2216
CPU/MB/RAM M.2타입의 NVMe SSD가 4장 탑재할 수 있는 RAID카드 file 김말이님 2017-08-02 19
CPU/MB/RAM 소형 PC 그래픽카드 ZOTAC GeForce GTX 1080 Ti Mini 성능을 알아보자 file 김말이님 2017-08-02 33
소프트웨어 뉴스/소식] 카스퍼스키 무료 백신 선언 "세계를 안전하게?" file 김현철 2017-08-01 14
우분투 소켓 접속 제한 풀어 소켓 갯수 늘리기 file 평가단 2017-07-28 19
Tornado-test-c10m: 대규모 TCP / WebSocket 동시 연결 테스트 file 평가단 2017-07-28 6
네트워크 포렌식 자료파일입니다 file 김현철 2017-07-27 20
네트워크 디지털 메모리 포렌식 방법 file 김현철 2017-07-27 26
소프트웨어 리믹스 Remix OS for PC 버전 안드로이드 설치 file 라이진 2017-07-27 437
iptime 공유기로 WOL(Wake On Lan) 원격부팅 사용하기 file 알파원 2017-07-27 46
CPU/MB/RAM PPPoE ( PPP Over Ethernet ) 란 무엇인가? 정보 알파원 2017-07-27 133
네트워크 암호화, 전자서명, 인증서와 SSL file 굿모닝 2017-07-21 104
소프트웨어 MP3에 공식 '사망선고'..특허 만료·기술계약 종료 file 나잘스프레이 2017-05-18 86
CPU/MB/RAM 요즘 중량급 게임은 멀티 쓰레드 성능이 중요 file 김말이님 2017-05-14 157
CPU/MB/RAM 마이크론, 2017년 중 1Xnm DRAM과 64층 3D NAND를 출하 file 잭팟 2017-02-07 154
Gmail, Windows XP와 Vista의 지원을 2017년에 중단 file 잭팟 2017-02-07 69
CPU/MB/RAM 비디오 카드에 콜라를 뿌려보았다 file 잭팟 2017-02-07 194
CPU/MB/RAM Core i7-6950X 할인들어갔나봅니다 file 잭팟 2016-12-17 635
CPU/MB/RAM 삼성 NVMe SSD 960 PRO 읽기최대 3,500MB 출시 file 잭팟 2016-12-17 270
소프트웨어 더 똑똑해진 구글 번역, 실제로 써보니 file 댄디보이 2016-12-01 149
ARM의 새로운 보안 아키텍처 "ARMv8-M TrustZone" file 잭팟 2016-11-25 98
소프트웨어 마이크로 소프트가 개발한 인공지능 번역기 file 잭팟 2016-11-25 170
CPU/MB/RAM GeForce GTX 1050 기본정보 file [1] 잭팟 2016-10-31 260
CPU/MB/RAM 인텔 최신 SoC 아톰Atom A3900 시리즈 발표 file 잭팟 2016-10-31 207
CPU/MB/RAM 인텔, 3D XPoint를 사용한 '옵테인 8000P' 유출 file 잭팟 2016-10-21 213
CPU/MB/RAM 인텔 카비레이크 펜티엄은 2코어4스레드이다? file [1] 잭팟 2016-10-21 249
서버에 요청 중입니다. 잠시만 기다려 주십시오...