Heesung Yang
Linux Kernel Tuning
개념 잡기
- tcp receive window size
- 수신자가 한 번에 버퍼링할 수 있는 최대 데이터 크기(bytes)
- 송신자는 수신자의 window size만큼 ACK를 기다리지 않고 데이터 송신 가능
- ack 를 받기 전에 보낼 수 있는 패킷 수를 의미
- tcp 는 ack 패킷을 받은 후에 다음 패킷을 보낼 수 있음
- 이 값은 유동적으로 변경됨
- ack 패킷을 timer 안에 수신할 경우 window size 늘림
- 반대로 ack 패킷을 timer 안에 수신못할 경우 window size 줄임
- 데이터 수신 측에서 buffer 가 꽉찰 경우 이를 송신측에 알림
Packet 수신
The NIC ring buffer
- ring buffer 는 device driver 와 NIC 간에 공유함
- NIC card 는 TX / RX ring buffer 를 할당함
- ring buffer 는 circular buffer
- overflow 발생 시 기존 data 를 덮어씀
- NIC 에서 kernel 로 데이터를 가져오는 방법은 2가지
- hardware interrupts
- software interrupts ( SoftIRQs )
- RX ring buffer 는 들어오는 packet을 (kernel driver 가 처리하기 전까지 ) 저장하는 용도임
- kernel driver는 SoftIRQs 를 이용하여 ring buffer 로부터 packet 을 가져옴
- ring buffer -> kernel data structure “sk_buff”
- TX ring buffer 는 밖으로 나가는 packet 을 hold
Interrupts and Interrupt Handlers
- NIC 가 packet 을 받으면 DMA를 이용하여 kernel buffer 로 복사함
- NIC 는 kernel 에게 hardware interrupt 를 이용하여 알려줌
- 이러한 interrupt 는 interrupt handler 에 의해 처리됨
- as they have already interrupted another task and cannot be interrupted themselves
- hard interrupt 는 CPU 를 많이 사용할 수 있음 ( 특히 when holding kernel locks )
- hard interrupt 는 /proc/interrupts 에서 확인 가능 (1st column)
- 이 값은 시스템 재부팅 또는 NIC driver load 시 초기화 됨
Interrupt coalescence
-
rx-frames : packet 을 얼마나 받은 후 rx interrupt 를 발생시킬 것인지 설정
-
rx-usecs : packet 을 받은 후 rx interrupt 를 발생시키기 전까지 기다리는 시간
# IBM recommendation rx-frames : 5-10 rx-usecs : 1-5 # Oracle recommendation rx-frames : 512 rx-usecs : 20 rx-frames-irq : 512 rx-usecs-irq : 0
-
예를 들어
rx-usecs = 10
,rx-frames = 100
일 경우 패킷 100개가 1 usec 안에 들어오면 interrupt 발생 -
패킷 1개가 들어온 후 10 usecs 동안 더 이상 패킷이 안들어올 경우 interrupt 발생
-
당연한 얘기지만 두 값을 증가시키면 interrupt 수가 줄어드므로 CPU 사용량 Down, 실시간성 Down
-
변경 방법
~$ ethtool -C eth8 rx-usec 5 ~$ ethtool -C eth8 rx-frames 10
RSS (Receive Side Scaling)
RPS (Receive Packet Steering)
-
RSS 를 소프트웨어로 구현한 것
~$ cat /sys/class/net/eth8/queues/rx-0/rps_cpus 00000000 # cpu 1,2,3,4 코어 할당 ~$ echo 2 > /sys/class/net/eth8/queues/rx-0/rps_cpus ~$ echo 4 > /sys/class/net/eth8/queues/rx-1/rps_cpus ~$ echo 8 > /sys/class/net/eth8/queues/rx-2/rps_cpus ~$ echo 10 > /sys/class/net/eth8/queues/rx-3/rps_cpus ~$ echo 2 > /sys/class/net/eth8/queues/rx-4/rps_cpus ~$ echo 4 > /sys/class/net/eth8/queues/rx-5/rps_cpus ~$ echo 8 > /sys/class/net/eth8/queues/rx-6/rps_cpus ~$ echo 10 > /sys/class/net/eth8/queues/rx-7/rps_cpus ~$ echo 2 > /sys/class/net/eth8/queues/rx-8/rps_cpus ~$ echo 4 > /sys/class/net/eth8/queues/rx-9/rps_cpus ~$ echo 8 > /sys/class/net/eth8/queues/rx-10/rps_cpus ~$ echo 10 > /sys/class/net/eth8/queues/rx-11/rps_cpus ~$ echo 2 > /sys/class/net/eth8/queues/rx-12/rps_cpus ~$ echo 4 > /sys/class/net/eth8/queues/rx-13/rps_cpus ~$ echo 8 > /sys/class/net/eth8/queues/rx-14/rps_cpus ~$ echo 10 > /sys/class/net/eth8/queues/rx-15/rps_cpus
-
큐 개수는 아래 명령어로 확인 및 변경 가능
# 변경 전 큐 개수 : 32 ~$ ethtool -l eth8 Channel parameters for eth8: Pre-set maximums: RX: 0 TX: 0 Other: 1 Combined: 63 Current hardware settings: RX: 0 TX: 0 Other: 1 Combined: 32 # 큐 개수 16개로 변경 # 변경 시 smp_affinity 설정이 무효화 되므로 재설정 필요 ~$ ethtool -L eth8 combined 16 # 변경된 큐 개수는 /proc/interrupts 에서도 확인 가능 # 변경 후 큐 개수 : 16 ~$ ethtool -l eth8 Channel parameters for eth8: Pre-set maximums: RX: 0 TX: 0 Other: 1 Combined: 63 Current hardware settings: RX: 0 TX: 0 Other: 1 Combined: 16
-
tx/rx 큐가 따로 있을 경우
/proc/interrupts
파일에서eth8-rx-0 / eth8-tx-0
으로 보임 -
큐가 분리되어 있어야
ethtool -L
명령어로 RX/TX 큐 개수를 각각 지정할 수 있음 -
분리 안되어 있을 경우
eth8-TxRx-14
처럼 보임
커널 설정
- net.core.dev_weight = 64
- queue drain rate
Context Switch
- voluntary context switch : 사용할 수 없는 자원을 요청해서 task 가 block 될 경우 발생
- involuntary context switch : 주어진 cpu time 을 모두 사용했을 경우 발생
Numa 아키텍쳐에서의 Large Memory 사용 시 알아야 할 것
-
Node 별로 메모리를 각각 사용함
-
예를 들어 Node 0,1 이 32GB 씩 총 64GB 의 메모리가 설치된 서버가 있음
-
mysqld 프로세스가 50GB 의 메모리를 사용함
-
이 때, 14GB 의 여유가 있음에도 Swap 이 발생할 수 있음
-
https://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/
참고 사이트
- http://balodeamit.blogspot.kr/2013/10/receive-side-scaling-and-receive-packet.html
- http://d2.naver.com/helloworld/47667
- https://communities.intel.com/thread/27731
- https://blog.cloudflare.com/how-to-receive-a-million-packets/
- https://www.mjmwired.net/kernel/Documentation/networking/scaling.txt#99
- https://www.cnblogs.com/sammyliu/articles/5085371.html
- http://egloos.zum.com/uamyd/v/4041541
~$ ethtool -X eth8 weight 0 1 1 1 1
RX flow hash indirection table for eth8 with 16 RX ring(s):
0: 1 1 1 1 1 1 1 1
8: 1 1 1 1 1 1 1 1
16: 1 1 1 1 1 1 1 1
24: 1 1 1 1 1 1 1 1
32: 2 2 2 2 2 2 2 2
40: 2 2 2 2 2 2 2 2
48: 2 2 2 2 2 2 2 2
56: 2 2 2 2 2 2 2 2
64: 3 3 3 3 3 3 3 3
72: 3 3 3 3 3 3 3 3
80: 3 3 3 3 3 3 3 3
88: 3 3 3 3 3 3 3 3
96: 4 4 4 4 4 4 4 4
104: 4 4 4 4 4 4 4 4
112: 4 4 4 4 4 4 4 4
120: 4 4 4 4 4 4 4 4