목차
접기
개요
Kafka는 설계할 때 Commit Log 개념을 시스템 전체 아키텍처에 적용함
- 토픽의 파티션 = 일종의 Commit Log : 메시지가 오면 뒤에 차곡차곡 추가(Append)만 하고, 절대 지우거나 덮어쓰지 않음
- 오프셋(Offset) = 커서(cursor): 메시지를 읽는 소비자(Consumer)는 “내가 어디까지 읽었는지”를 오프셋으로 기억함
(데이터는 그대로 두고, 읽는 쪽 위치만 바꾸는 구조) - 재처리(Replay): 소비자가 오프셋을 옛날로 되돌리면, 같은 로그를 다시 읽으면서 과거 이벤트를 재현할 수 있음
(데이터 파이프라인이나 장애 복구에 매우 유용) - 내구성과 복제
Commit Log는 보통 분산 시스템에서 “진실의 원본(Source of Truth)” 역할을 함
Kafka도 여러 브로커에 파티션을 복제(Replication)해서, 장애가 나도 Commit Log처럼 메세지를 안전하게 보존함
다만, Kafka의 시작은 Commit Log 개념을 시스템 전체 아키텍처에 적용함으로서 시작했지만,
대규모 분산 환경에 맞게 확장한 형태임
- 파티션을 여러 개 두어 병렬성과 확장성 제공
- 데이터 보존 기간(retention)을 설정해서 오래된 메시지는 삭제 가능
- 단순한 로그 저장을 넘어서 “실시간 스트리밍 플랫폼” 역할 수행
카프카 주요 개념
| 메시지 | Kafka에서 주고받는 데이터의 기본 단위. (e.g. 편지) 각 메시지는 키(key), 값(value), 타임스탬프로 구성되어있음 |
| 배치 | 네트워크 효율성을 위해 메시지를 묶어서 한 번에 처리하는 것 메세지를 배치단위로 모아서 쓰는것으로, 네트워크 오버헤드를 줄일 수 있음 단, 지연(latency)와 처리량(throughput)t사이의 트레이드 오프 있음 |
| 스키마 | 메시지의 구조를 정의하는 규칙 Kafka에서는 주로 Avro, Protobuf, JSON Schema 같은 포맷을 사용하며, Schema Registry를 이용해 관리함 |
| 토픽 | 메시지가 저장되는 카테고리나 폴더 같은 개념 (e.g. 데이터베이스의 테이블/ 파일시스템의 폴더) "주문", "결제", "사용자 로그" 같은 주제별로 분류할 수 있음 |
| 파티션 | 나의 토픽을 여러 개의 작은 통으로 나누는 것 큰 창고를 여러 구역으로 나누어서 물건을 분산 저장하는 것과 같고, 여러 서버에서 동시에 처리할 수 있어서 성능이 좋아짐 파티션 내에서는 메시지 순서가 보장됨 |
| 프로듀서 | 메시지를 생산하여 Kafka에 보내는 애플리케이션 (Publisher/Writer) |
| 컨슈머 | Kafka에서 메시지를 읽어가는 애플리케이션 (Subscriber/Reader) |
| 컨슈머 그룹 | 여러 컨슈머가 하나의 팀처럼 협력해서, 토픽의 메시지를 나눠 처리하도록 하는 장치 메세지 순서는 파티션이 보장함, 각 파티션이 어떤 컨슈머가 처리할 수 있도록 매핑(ownership)해주는 역할을 컨슈머 그룹이 담당함 여러 컨슈머가 일을 분담해서 처리 속도가 빨라지며, 컨슈머를 수평 확장할 수 있기때문에 부하분산, 장애 대응이 자동으로 이루어짐 추가로, 파티션 개수 이상으로 컨슈머를 늘려도 성능 향상없음 (컨슈머 놀게됨) |
| 브로커 | Kafka 서버 하나를 의미함 브로커는 프로듀서로부터 메세지를 받아 오프셋을 할당한 뒤 디스크 저장소에 쓰고, 컨슈머의 읽기(fetch) 요청을 처리하고 발행된 메세지를 보냄 |
| 클러스터 | 브로커 여러 대를 묶어 놓은 집합 토픽의 파티션들이 여러 브로커에 분산 저장될 수 있도록 하며, 분산저장으로 안정성과 성능을 높임 파티션 리더 (Leader) • 메시지를 실제로 처리하는 주인 역할 • 프로듀서(Producer)가 메시지를 보낼 때 → 항상 리더 파티션에 기록 • 컨슈머(Consumer)가 메시지를 읽을 때 → 항상 리더 파티션에서 읽음 팔로워 (Follower) • 리더가 받은 메시지를 그대로 복제(Replication)해서 보관 • 평소에는 요청을 직접 처리하지 않고, 리더를 따라가기만 함 • 리더에 장애가 생기면, 팔로워 중 하나가 자동으로 승격되어 새로운 리더가 됨 → 고가용성(HA) 보장 컨트롤러(Controller) • 클러스터의 메타데이터를 관리하고 리더 선출 등을 담당 • 컨트롤러의 역할: - 어떤 브로커가 살아있는지 감시 (헬스 체크) - 리더 브로커가 죽으면 → 팔로워 중 하나를 새로운 리더로 지정 - 파티션과 리더의 할당(assignment)을 관리 |
Broker 주요 파라메터들
* 참고링크: https://docs.confluent.io/platform/current/installation/configuration/index.html
| broker.id | 클러스터 내에서 브로커를 구분하는 ID(정수)임 KRaft 모드 도입 이후에는 점차 node.id로 대체되는 중 • node.id KRaft 모드(Zookeeper 없는 Kafka 모드)에서 추가된 개념 • node.id = universal identifier (브로커 + 컨트롤러) • broker.id = 브로커 프로세스 전용 identifier (과거 호환성 때문에 남아있음) |
| listener | listeners → 브로커가 실제로 바인드(bind) 해서 네트워크를 수신하는 주소 (내부 바인드 인터페이스). advertised.listeners → 브로커가 클러스터 메타데이터에 알리고, 클라이언트가 접속할 때 쓰라고 알려주는 주소. # 브로커가 내부적으로 바인드할 주소 listeners=PLAINTEXT://0.0.0.0:9092 # 클러스터 메타데이터에 알릴 주소 (외부에서 접속 가능한 주소) advertised.listeners=PLAINTEXT://broker1.mycompany.com:9092 |
| log.dir | Kafka는 토픽 파티션의 실제 데이터(로그 세그먼트)를 이 디렉터리들 안에 저장한다. 브로커는 새 파티션을 생성할 때 , 디렉토리 별 저장된 파티션 수를 비교해서 가장 적은 파티션을 가진 디렉토리에 새 파티션을 저장한다. (디스크 용량을 기준으로 하지 않고, 파티션 개수 기준으로 균등 분산) • log.dir → 단일 디렉터리 경로만 지정할 때 사용 (예전 설정 방식) • log.dirs → 여러 디렉터리를 지정할 때 사용 (콤마로 구분) 하나의 파티션은 여러 개의 로그 세그먼트 파일(.log, .index, .timeindex 등)로 쪼개져서 저장됨. 같은 파티션의 세그먼트들은 반드시 같은 디렉토리에 모여 저장됨. 파티션은 리더/팔로워 동기화 단위라서, 데이터가 한 디렉토리에 모여 있어야 함. |
| num.recovery. threads.per. data.dir |
Kafka 브로커 재시작/종료 시 로그 복구 작업에 쓰는 스레드 개수. (디렉터리당 병렬 스레드 개수) log.dirs 에 지정한 디렉터리 1개당 몇 개의 스레드를 쓸지 결정. • 총 스레드 수 = log.dirs 개수 × num.recovery.threads.per.data.dir • 스레드가 많으면 복구 속도↑ (재기동 빠름)/ 과하면 CPU·디스크 경합↑ (오히려 느려짐). Kafka 브로커가 재시작할 때는 각 log.dirs 안의 모든 파티션 로그 세그먼트를 검증하고 인덱스를 재생성하기때문에 설정에 따라 몇시간 차이날수도있음 |
| auto.create. topics.enable |
브로커가 자동으로 토픽을 생성할 수 있는지 여부를 설정. • true (기본값): 클라이언트(Producer, Consumer, get metadata 등)가 없는 토픽에 대해 요청을 보내면 Kafka 브로커가 자동으로 새 토픽을 생성 • false: 없는 토픽에 대해 요청하면 에러 반환하고, 토픽을 만들땐 명시적으로 만들어주어야 함 |
| auto.leader. rebalance.enable |
리더 파티션 자동 재분배 여부 설정 Kafka에서 각 파티션은 여러 개의 복제본(replica)을 가지며, 그 중 하나가 리더(leader) 역할을 하며, 리더 파티션이 특정 브로커에 몰리면 트래픽 불균형이 생기기 때문에 자동으로 리더를 다른 브로커로 옮기는 설정 • 리더 파티션 → 클라이언트(Producer/Consumer)의 모든 read/write 트래픽 처리 • 팔로워(follower) 파티션 → 리더를 복제만 수행 • leader.imbalance.check.interval.seconds (기본 300초 = 5분) 마다 체크 |
| num.partitions | Kafka에서 새 토픽을 자동 생성할 때 기본으로 몇 개의 파티션을 만들지 정하는 브로커 단위 설정임 (default:1) 토픽을 생성할 때 파티션 개수를 명시하지 않으면 이 값이 기본으로 사용됨 • 파티션 수는 Kafka의 병렬 처리 단위 • 파티션이 많을수록 Consumer Group이 더 많은 Consumer 인스턴스를 병렬로 돌릴 수 있음 → 처리량↑ • 하지만 파티션이 많을수록 메타데이터 관리, 파일 핸들, 리더 선출 → 오버헤드↑ • num.partitions는 운영 환경에서의 디폴트 안전값일 뿐, 실제 토픽은 필요에 맞게 직접 파티션 수를 정해야 함 • 이미 생성된 토픽의 파티션 수는 늘릴수만있고 줄일수없음. (데이터 재배치 문제 때문) • 파티션을 늘릴때 기존 메시지는 그대로 있고, 새 메시지만 새로운 파티션에 배치되기때문에 컨슈머 처리 순서에 영향을 준다 (메세지 리벨런싱 이런거 없음), 운영에 영향을 줄수있기때문에 신중!주의!해야한다. • 카프카는 “키 → 파티션”으로 보냄, ( partition = hash(key) % (파티션 개수) ) 같은 키의 메시지는 항상 같은 파티션으로 가므로, 그 파티션 안에서는 순서가 보장되는것. • 그런데 파티션 개수가 늘리면 예전 파티션이 아닌 다른 파티션으로 가게 됨 특정 키의 메시지가 두 파티션에 흩어져 도착하고, 컨슈머 그룹은 파티션 단위로 읽으니 키 단위 순서가 깨짐 |
| default. replication.factor |
파티션의 복제본 수를 말한다. 복제본수와 최소 동기 replica수(min.insync.replicas)를 함께 고려해야하며, replication.factor 값은 min.insync.replicas보다 항상 1이상 크게 설정해야한다. Replication Factor (RF) default.replication.factor, min.insync.replicas 는 데이터 내구성(durability)과 가용성(availability) 에 직결되는 핵심 설정임 • default.replication.factor → 토픽 생성 시 기본 복제본 개수 (내구성 수준) • min.insync.replicas → acks=all 시 “성공”으로 인정할 최소 동기 replica 수 (데이터 안전성) |
| log.retention.ms | 메세지 보존 주기 설정 (default: 168) log.retention.ms, log.retention.minutes, log.retention.hours 옵션값이 제공되나 항상 가장 작은 단위의 설정값이 우선권을 갖기때문에 log.retention.ms을 설정하는것이 좋다. • 시간기준 보존은 디스크에 저장된 각 로그 세그먼트 파일의 마지막 수정시간(mtime)을 기준으로 작동한다. |
| log.retention.bytes | 메세지 보존 용량 설정 (default: -1) 파티션 단위로 적용된다. (예, 8개의 파티션을 가진 토픽에 값이 1GB라면, 토픽의 최대 저장용량은 8GB임 • 만약 log.retention.ms/log.retention.bytes두개 다 설정했다면 두 조건 중 하나만 성립해도 메세지 삭제됨 |
| log.segment.bytes | 단일 로그 파일의 최대 크기 (default: 1073741824 (1 gibibyte)) 주의할점은 위에서 말한 로그 보존설정은 로그 세그먼트(파일)에 적용되는것이지 각 로그 메세지에 적용되는것이 아니다. 즉, log.segment.bytes에 지정된 크기에 다 다르지 않는다면 계속해서 로그 세그먼트를 닫지않고 사용한다. log.segment.bytes값이 너무 작으면, 파일을 너무 자주 닫고 새로 생성해야한다 (디스크 쓰기 효율성 감소) log.segment.bytes값이 너무 크면, log.retention 설정에 영향을 미친다. (예, 하루에 100M 메세지가 쓰이는 경우 1G까지 10일이 소요됨, retiontion이 1주일로 잡혀져있다면 17일분의 메세지가 저장되어있는것) 로그 세그먼트의크기는 타임스탬프 기준으로 요프셋을 찾는 기능에도 영향을 미친다. 클라이언트가 특정 타임스탬프를 기준으로 파티션의 오프셋을 요청하면 카프카는 해당 시각에쓰여진 로그 세그먼트를 찾고, 로그 세그먼트 맨 앞에 있는 오프셋이 응답으로 리턴된다. • 세그먼트가 너무 크면 → 하나의 세그먼트가 긴 시간(며칠, 몇 주) 동안 데이터를 담음. 그러면 “특정 시각”을 찾을 때 granularity(정밀도)가 떨어짐 예: 1GB 세그먼트에 10일치 메시지가 들어 있다면, “8월 5일”을 요청해도 Kafka는 세그먼트 맨 앞 오프셋(예: 8월 1일)을 반환할 수 있음. • 세그먼트가 작으면 → 파일은 자주 생기지만, 타임스탬프 기반 오프셋 조회가 더 정밀해짐. |
| log.roll.ms log.roll.hours |
새로운 로그 세그먼트가 롤아웃되기까지의 최대 시간 (default: null) 세그먼트 용량(log.segment.bytes)에 도달하지 않아도, 지정 시간이 지나면 세그먼트를 닫고 새 세그먼트를 만듦 log.roll.ms(밀리초 단위)가 우선 적용됨 retention 정책 적용을 보장하기 위해 설정하는 것이며, 값이 너무 짧으면 세그먼트가 과도하게 쪼개져 성능 저하 발생 가능. 브로커가 해당 세그먼트를 연 시각부터 타이머가 시작되며, 대부분 브로커 시작(재기동) 시점에 여러 파티션이 동시에 새 세그먼트를 열기 때문에 동시롤링 (파일 flush + 인덱스 파일 sync + 새 파일 오픈)에 부하가 있을 수 있음 짧은 시간 안에 엄청난 I/O burst 발생 → 디스크 성능 스파이크 |
| min.insync.replicas | 쓰기가 성공적으로 완료되기 위해 최소한 몇 개의 복제본이 쓰기를 확인해야 하는지 지정하는 옵션 메시지는 모든 동기화된 복제본에 복제되고 min.insync.replicas 조건이 충족될 때까지 소비자에게 표시되지 않음 min.insync.replicas와 acks를 함께 사용하면 더 강력한 내구성 보장을 강제할 수 있음 • acks=all 과 min.insync.replicas=2 (RF=3일 때) → 메시지가 최소 2개 replica에 성공적으로 쓰여야 성공 응답 → 브로커 1대 죽어도 데이터는 안전 다만, 이 값을 늘림으로써 추가적인 오버헤드가 발생하면서 성능이 떨어질 수 있고, 데이터 일부 유실은 가능하지만 높은 처리량이 필요하다면 기본값인 1에서 변경하지 않는 구성도 가능함 *acks 는 프로듀서(producer)가 메시지를 보낸 후 “성공”으로 간주할 때 브로커 쪽에서 몇 개의 replica가 응답해야 하는지를 정하는 옵션 |
| message.max.bytes | Kafka에서 허용되는 최대 레코드 배치 크기(압축이 활성화된 경우 압축 후 크기) (default: 1048588 (1M) 메세지 크기가 커지면 네트워크 연결과 요청을 처리하는 브로커 스레드의 요청당 작업 시간 및 I/O처리량이 증가하기 때문에 성능에 큰 영향을 미친다. message.max.bytes 값은 fetch.message.max.bytes(컨슈머), replica.fetch.max.byte(브로커) 값과 설정이 맞아야 한다. |
하드웨어 선택 기준
1. 디스크
| 처리량 | 브로커 디스크의 처리량은 프로듀서 클라이언트 성능에 가장 큰 영향을 미친다. (브로커 로컬 저장소에 커밋되기때문) 즉, 디스크 쓰기속도가 빨라지면 쓰기 지연이 줄어든다. |
| 용량 | 필요한 디스크 용량은 특정 시점에 얼마나 많은 메세지가 보존되어야 하는지에 따라 결정된다. 예를들어 하루 1TB의 트래픽을 받고, 1주일 보존해야 한다면, 브로커는 최소 7TB가 필요하다. 이때, 트래픽 변동 및 저장해야할 다른 파일들을 고려하여 최소 10%의 오버헤드를 고려해야한다. 또한 복제방식에 따라서도 달라진다. |
2. 메모리
- Kafka 힙 메모리 (JVM Heap)
- Kafka 자체는 힙 메모리를 많이 쓰지 않음
- 초당 150,000 메시지, 200MB/s 처리량을 다루는 브로커도 5GB 힙 정도면 충분
- 따라서 브로커 JVM 옵션은 보통 4~8GB 사이에서 안정적으로 설정
- 페이지 캐시 (OS Page Cache)
- 핵심 성능 포인트는 JVM 힙이 아니라 운영체제 페이지 캐시
- 컨슈머는 보통 “프로듀서가 막 쓴 메시지를 바로 읽는” 패턴 → OS 페이지 캐시에 남아 있는 로그 세그먼트를 바로 읽음
- 디스크에서 읽는 게 아니라 메모리 캐시에서 읽기 때문에 성능이 크게 향상됨
- 즉, Kafka 성능 = 가용한 페이지 캐시 메모리 크기에 크게 좌우됨
- 총 시스템 메모리 배분
- VM 힙: 4~8GB (너무 크게 잡을 필요 없음)
- 나머지 대부분: OS 페이지 캐시 용도로 확보
- 프로덕션 최소 체감선: RAM 16GB(아주 낮은 트래픽), 권장 32GB+
- 운영 고려사항
- Kafka 브로커와 다른 애플리케이션을 같은 서버에서 돌리지 않는 것이 권장
- 이유: OS 페이지 캐시 메모리를 서로 뺏어 쓰게 되면 Kafka가 캐시 효율을 잃음 → 컨슈머 성능 저하
- 따라서 전용 서버(전용 VM/노드) 위에 Kafka를 올려야 안정적인 처리량을 확보할 수 있음
3. 네트워크
- 네트워크 대역폭은 Kafka가 처리할 수 있는 트래픽 최대치를 결정하는 핵심 자원
- 디스크 용량과 함께 클러스터 크기 산정의 가장 중요한 요소
- 주요 고려사항
- 프로듀서 → 브로커 유입 트래픽보다, 다수 컨슈머가 동시에 가져가는 아웃바운드 트래픽이 훨씬 클 수 있음
- 클러스터 내부의 복제/미러링도 모두 네트워크를 소모 → 네트워크 사용량은 예측보다 커질 수 있음
- 네트워크가 포화 상태가 되면 → 복제 지연 → ISR(In-Sync Replicas) 축소 → 리더 선출 지연 → 장애 위험으로 이어짐
- 예 RF=3, min.insync.replicas=2 환경
- 원래 ISR={Leader, F1, F2} → 정상 (ISR, Leader와 동기화된 replica 집합)
- F1이 지연되면 ISR={Leader, F2} → ISR 축소 발생
- 만약 Leader까지 장애 나면 → F1은 뒤처져 있어서 데이터 유실 위험
- 더 심각하게는 ISR이 min.insync.replicas보다 작아지면 acks=all 쓰기가 실패해서, Producer가 계속 에러를 보게 됨.
4. CPU
CPU는 다른 자원보다는 성능에 영향을 덜 미친다.
하지만, 메세지 체크섬 확인, 오프셋 부여 등을 위해 메세지의 압축의 해제하며, 이때 CPU가 쓰인다.
운영체제 튜닝
가상 메모리(Virtual Memory) 튜닝
1. 페이지 캐시(Page Cache) 활용
- 정의: 리눅스 커널이 디스크 I/O를 빠르게 하기 위해 파일 데이터를 메모리에 캐싱하는 영역
- 운영 권장: Kafka 브로커 JVM 힙은 4~8GB로 작게 두고, 나머지 물리 메모리를 페이지 캐시로 최대 확보
2. Dirty Page 관리
- Dirty Page: 페이지 캐시에 있지만 아직 디스크에 flush되지 않은 데이터
- 관련 커널 파라미터:
- vm.dirty_background_ratio
- 백그라운드 flush를 시작하는 비율
- 10 미만 권장
- 단, 0으로 두면 디스크에 계속 즉시 쓰려 하기 때문에 성능 스파이크 발생 가능 → ❌
- vm.dirty_ratio
- 시스템 메모리 대비 허용할 최대 dirty page 비율
- 보통 60~80 권장 (너무 낮으면 flush 잦아지고, 너무 높으면 flush 몰림으로 I/O burst 발생)
- vm.dirty_background_ratio
3. Swap 설정
- 권장: Kafka 브로커 서버는 swap off
- 이유: 스왑 발생 시 I/O 지연이 급격히 증가하여 Kafka 지연·ISR 축소 발생
4. 파일 디스크립터(File Descriptor)
- Kafka는 파티션·세그먼트·네트워크 연결 수만큼 FD를 소모
- 필요량 = 파티션 수 × (파티션당 세그먼트 개수) + 브로커 네트워크 연결 수
- 따라서 ulimit -n (open files) 값을 충분히 크게 설정해야 함 (수십만 단위 권장)
5. 기타 VM 관련 커널 파라미터
- vm.max_map_count
- mmap 가능한 영역 개수 제한
- Kafka는 세그먼트를 파일 단위로 mmap 하므로 매우 큰 값 권장 (예: 1,000,000 이상)
- vm.overcommit_memory
- 메모리 오버커밋 정책
- 0(기본): Heuristic 모드, 일반적으로 안전 → Kafka 운영 시 권장
############################################
# /etc/sysctl.conf 예시
############################################
# Dirty Page 관리
vm.dirty_background_ratio = 5 # 백그라운드 flush 시작 비율 (10 미만 권장)
vm.dirty_ratio = 70 # 최대 dirty page 비율 (60~80 권장)
# mmap 가능한 영역 수 (Kafka 세그먼트 파일이 많아질 때 필요)
vm.max_map_count = 1048576 # 1,000,000 이상 권장
# 메모리 오버커밋 정책
vm.overcommit_memory = 0 # 기본 heuristic 모드 (Kafka 운영에 안전)
# Swap 관련 (swapoff -a 로 꺼두는 것이 일반적)
vm.swappiness = 1 # 혹시 swap을 켠 상태라면 최소화
############################################
# /etc/security/limits.conf 예시
############################################
# Kafka 브로커 유저 (예: kafka) 기준
kafka soft nofile 500000
kafka hard nofile 500000
디스크 튜닝
- 파일시스템은 XFS 사용
- noatime 옵션 지정
- largeio 옵션 지정
# /etc/fstab 예시
/dev/nvme1n1 /data/kafka xfs noatime,nodiratime,largeio,inode64 0 0
네트워크 튜닝
* 소켓 버퍼 (Socket Buffer) 설정
net.core.wmem_default = 131072 # 송신 버퍼 기본값 (128KB)
net.core.rmem_default = 131072 # 수신 버퍼 기본값 (128KB)
net.core.wmem_max = 2097152 # 송신 버퍼 최대값 (2MB)
net.core.rmem_max = 2097152 # 수신 버퍼 최대값 (2MB)
* TCP 소켓 설정
# 송수신 버퍼 자동 조정 범위
net.ipv4.tcp_wmem = 4096 65536 2097152 # [최소, 기본, 최대]
net.ipv4.tcp_rmem = 4096 87380 2097152 # [최소, 기본, 최대]
# TCP 윈도우 스케일 (65KB 이상의 윈도우 크기를 지원 (고대역폭 환경 필수))
net.ipv4.tcp_window_scaling = 1
# TCP SYN 백로그
# 동시에 처리 가능한 미완성 연결(half-open) 큐 크기
# Kafka 브로커에 다수 클라이언트 연결 시 1024 이상 권장
net.ipv4.tcp_max_syn_backlog = 4096
# NIC 수신 대기열 (Network Device Backlog)
# NIC 드라이버가 커널 네트워크 스택으로 패킷을 전달하기 전의 큐 크기
# Kafka는 burst 트래픽이 많으므로 기본값(1000)을 10배 이상 늘려주면 안전
net.core.netdev_max_backlog = 10000
728x90