초당 100만건의 로그를 filebeat -> logstash -> Kafka로 유실 없이전달하기

안녕하세요, NAVER BIZ CIC의 NDP Dev 입니다. 저희 조직은 네이버 서비스 전통적인 CPM(cost per 1000 impressions)배너 광고 플랫폼 역할을 하고 있습니다.

오늘은 저희 조직의 광고 전송서버를 k8s 기반의 n2c라는 사내 클라우드 플랫폼으로 이전하면서 구성했던 구조를 기반으로 한 대용량 트래픽 처리 테스트 사례를 소개하려고 합니다.

목차

- 초당 100만건의 트래픽을 처리하는 서버 및 로그 전달 프로세스

- NDP(Naver Reservation Display AD Platform) 전송 플랫폼

- 100만/s 처리를 위한 pod 구성

- 100만/s 트래픽 생성

- kafka 물리서버 가용량

- 100만/s 처리 kafka 전달 테스트

- kafka 물리서버 down 테스트

초당 100만건의 트래픽을 처리하는 서버 및 로그 전달 프로세스

초당 100만건의 트래픽은 네이버 서비스 지면 거의 대부분의 트래픽을 받고 있는 광고 전송 서버 기준으로도 매우 큰 수치이지만, 다행히도 큰 리소스를 필요로 하지 않은 로깅성 트래픽으로 비교적 적은 수의 서버로도 수용이 가능합니다.

다만 평소 처리량의 10배가 넘는 100만/s의 이벤트성 트래픽 처리를 위해 구조를 2개로 나누지 않고, 운영의 비효율성을 최소화하는 일반 트래픽과 이벤트성 트래픽 처리를 단일화 하는 구조로 구성하기 위해 100만/s 의 테스트를 진행했습니다.

트래픽을 받는 서버와 서버에서 수집한 로그를 kafka에 전달하는 구조 2개가 저희 부서에서 다뤘던 프로세스입니다.

100만/s 가용량 산정의 근거 사례
네이버 생중계 플레리어의 동접자수

NDP(Naver Reservation Display AD Platform) 전송 플랫폼

네이버 NDP 광고 전송 플랫폼은 여러 종류의 DA(Display AD) 광고를 송출하고, 그에 상응하는 로그를 수집하고 있습니다. 로그 수집은 광고가 사용자에게 정상적으로 노출되었는지를 광고주에게 보여주기 위한 주요한 절차 입니다.

PC 뉴스홈 우측 배너

1. 네이버 서비스 지면을 기반으로 광고주가 원하는 광고 선출

2. 선출된 광고에 대한 노출 여부, 광고의 확장/스크롤 등에 대한 로깅

3. 사용자가 click 한 내역에 대한 광고주 url redirect

NDP 전송서버가 하는 역할은 위와 같습니다.

로그 전달 프로세스

1. 선출/노출/이벤트/클릭에 대한 로그 로깅

2. 로깅된 로그를 실시간으로 filebeat -> logstash -> kafka로 전달

이후 로그 처리 플랫폼까지 전달하기 위해 위와 같은 과정을 거칩니다

100만/s 처리를 위한 pod 구성

k8s 의 pod은 여러개의 container 들로 구성될 수 있고, container 들은 같은 emptyDir를 공유할 수 있습니다. pod running시에만 보존되는 emptyDir path에 트래픽을 처리하고 로깅하는 container와 저장된 로그를 읽어 전달하는 container로 분리할 수 있으며, 이러한 구조를 통해 물리 서버의 cpu, memory, storage 등의 자원을 좀 더 효율적으로 제약해 사용할 수 있습니다.

실제 NDP 광고전송 서버의 n2c 구조

NDP 전송서버는 nginx와 golang 기반 dndl_go 서버를 통해 100만/s의 트래픽을 처리할 수 있도록 n2c의 pod 개수를 scale 하였으며, 그에 맞는 logstash pod의 개수도 scale 하였습니다. 각 pod는 운영에 필요한 로그를 추가적으로 처리 및 저장합니다.

100만/s 트래픽 생성

100만/s의 트래픽을 생성하기 위해 기존의 물리 서버 60대를 사용하여 트래픽을 생성하였고, 약 110만/s 수준의 트래픽을 발생시켜 테스트에 활용하였습니다

물리 장비의 트래픽을 트래픽 테스트에 활용하는 구조

tcpdump로 물리서버로 유입되는 트래픽을 캡쳐, golang으로 개발된 트래픽 relay app을 통해 json 형태로 저장후 60개의 서버에서 트래픽 relay app을 통해 1대당 1.83만/s의 트래픽을 만들어 약 110만/s의 트래픽을 생성하였습니다.

kafka 물리서버 가용량

kafka를 설치& 운용하는 서버는 12코어 CPU 2장으로 총 24코어, ssd 8개가 raid 5로 장착된 물리 서버입니다. kafka는 병목이 주로 disk에서 발생하므로 SSD 속도가 주요 성능 지표로 보고 disk 사용량을 주로 모니터링 하였습니다.

110만/s 처리시 kafka 서버의 iostat 지표로 약 330MB/s sequential write peak

위 이미지는 실제 110만/s 의 트래픽 처리시 쓰기 성능에 대한 지표로, 실제 서버 SSD 성능의 1/5 이하로도 처리 가능함을 확인하였습니다.

kafka broker는 물리서버 10대로 구성하여 4 replication, 2 replicas, retention hour 8, acks all 등으로 설정되어 있습니다. 물리장비 10대 중 2 대까지 down되어도 data 유실 없이 복구가 가능합니다.

100만/s 처리 kafka 전달 테스트

앞서 구성한 트래픽 relay app을 통해 초당 약 110만 수준의 트래픽을 생성하였고, 광고 전송서버는 수초내 scale up이 어려운 k8s의 HPA를 활용하지 않고, 한계치 부근에서 수용 가능하도록 정확한 용량산정을 통해 pod의 scale을 조정해놓았습니다.

110만/s의 생성된 트래픽을 처리하는 nginx container 지표

dndl golang app 서버가 처리하는 트래픽의 수준은 111만/s 수준인 그래프와 같고, 처리 시점에 총 3개의 로그가 남게 되어 filebeat -> logstash 까지 330만/s의 로그가 전달되고 logstash -> kafka는 다시 1개만 전달되어 110만/s의 로그가 실시간으로 전달되었습니다.

filebeat가 전달해준 110만/s의 로그를 kafka로 보내는 지표

kafka 까지 전달되는 트래픽은 batch_size 설정으로 한번에 여러개의 로그가 전달되는 구조입니다. 그에 따라 connection 등의 네트워크 리소스가 상대적으로 적어지며 빠르고 효율적인 처리가 가능해집니다.

kafka 물리서버 down 테스트

실제 서비스 중 각종 이슈로 인해 서버가 다운되는 경우가 발생합니다. 해당 상황의 테스트를 위해 kafka 서버를 임의로 kill 하여 로그 지연 전송를 지원하는 filebeat -> logstash의 back-pressure protocol의 동작을 확인하고, 로그 유실이 발생하지 않는지도 확인하였습니다.

1대 down시 kafka가 leader 선출 시까지 write이 금지되는 시간(10초) 동안 back-pressure 동작

110만/s 의 트래픽을 처리중에 kafka 서버가 down 되면, 약 10초간 leader 선출을 위해 kafka에서는 write이 금지되며, 해당 시간 동안 logstash는 kafka에 로그를 전달하지 못하고, filebeat에 해당 상황을 알려 back-pressure protocol이 동작합니다. kafka write이 가능해진 이후 미처리된 트래픽들은 평균 트래픽에 더해져서 전달되며 약 10분 이후 평소 처리 트래픽으로 돌아왔습니다.

2대 down 시 처리 트래픽이 상대적으로 적어 약 1분만에 밀린 트래픽 전달 완료

27만/s의 트래픽을 처리하는 중에 2대의 kafka 서버가 down 되면, 마찬가지로 leader 선출에 약 10초간 write가 금지되고, 그동안 쌓인 로그 처리에 약 1분 정도가 소요되었습니다.

실제 장애 상황에서 filebeat-logstash 간 back-pressure 동작

위 이미지는 실제 kafka 물리장비가 down되는 상황에서의 filebeat가 logstash의 ack을 받은 그래프로, back-pressure protocol이 동작하고 로그 유실은 발생하지 않는것으로 보여집니다. 약 5분 이내에 복구되었고, 결론적으로 테스트와 실제 상황의 경향성이 거의 비슷함을 확인할 수 있었습니다.

마치며

대용량 트래픽을 처리하는 것은 서버 개발자에게 요구되는 기본적인 과제이지만 실제 이벤트성 peak 트래픽에 의해 서버가 다운되는 등의 상황이 드물지 않게 발생합니다. 저희 부서에서는 이런 상황에 대비하여 app을 개발하고, 가용량을 정확하게 산정하며 여유있지만 효율적인 서버 운영을 하고 있습니다.

오늘 포스팅을 통해 새로운 기술을 리서치하고, 테스트와 도입 및 튜닝 후 전체 전환 등의 과제를 통해 안정적인 서비스 운영을 하는 사례를 소개해드렸습니다.

--

--