NONBLOCK 모드에서 usleep 오버헤드가 커졌다.

|

CentOS 5.x를 쓰다가 새로 CentOS 6.x를 쓰기 시작했는데, 기존의 nonblock system call들 처리 후 sleeping 하는 부분에서 usleep(0)의 오버헤드가 갑자기 커져버렸다.

이거 usleep(x)의 x 값을 250에서 400 정도로 조절해서 어떻게 cputime은 맞춰봤는데, 여전히 cpu load는 기대보다 크다. (기존에는 거의 0에 수렴하던 로드가 갑자기 11, 12로 뛰면, 이러면 안되는것 아닌가)


찾아보니 원인은 CentOS 6.x에 있다. 더 정확히 말하자면 Tickless Kernel(NoHz라고도 불린다)이라는 놈 때문에 그렇다. CentOS 6.x가 2010년에 나왔지만, Tickless Kernel은 2000년대 중반부터 개발되어 linux kernel에 들어있던 놈이라고 한다.


참고 사이트 : https://access.redhat.com/documentation/ko-KR/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/tickless-kernel.html (틱리스 커널이란 이런 놈이다.)


linux kernel은 원래 HZ마다 timer interrupt를 콜하게 되고, 이 timer interrupt가 주기적으로 행해져야 하는 일들을 처리하는 구조였다. 이 HZ는 1000 혹은 250으로 세팅되어 있고, 일반적으로 1000, 그러니까 1000 usec (1/1000 sec) 마다 타이머 인터럽트를 부르게 된다.

일반적으로 usleep(x)를 부르면 x usec 만큼 sleep 해야 하나 실제로는 x usec ~ 1000 usec 만큼 sleep 하게 된다. 그러므로 기존 커널에서는 usleep(0)을 부르면 0 usec ~ 1000 usec 만큼, 기대값으로는 500 usec 만큼 sleep 하는 셈이다.


근데 이것이 바뀐거다. 이제 usleep(x)를 부르면 정확히 x usec 만큼 sleep 하게 된다.


참고 사이트 : http://lwn.net/Articles/455044/ (Tickless Kernel, 다른 말로는 NoHz로 불리는 이놈의 아키텍쳐 설명이다.)

참고 사이트 : https://www.kernel.org/doc/Documentation/timers/NO_HZ.txt (NoHz의 kernel 오리지널 도큐먼트이다. 하지만 이것은 CentOS 6.x의 커널에 대응하지 않고 CentOS 7.x의 커널에 대응한다. CentOS 6.x의 커널은 이 문서에서 말하는 Older Kernel 이다.)


Tickless Kernel, 그러니까 kernel config 상으로는 CONFIG_NO_HZ 인 이 놈의 존재 의미는 저전력과 전력 효율에 있다고 한다. 기존에는 시스템이 아무것도 하지 않는 상황에서도 timer interrupt는 1/1000 초마다 불려야 하고, cpu는 계속 동작하게 된다. 이게 마음에 안들었던 거지. 그래서 timer interrupt를 원할때마다 부르고 싶어졌던거다. 이건 2000년대 중반부터 Intel이나 Microsoft 역시 주력했던 저전력 이슈를 반영한게 아닌가 싶다. (근데 이건 데스크탑 이야기 아닌가? 서버도.. 물론 저전력이면 이득이 없지는 않지만 퍼포먼스가 우선이지 않나 싶은데.)


뭐 명시적으로 효율적이니 (usleep(250)이 정확히 250 usec만큼을 sleep 해준다고 생각하면 뭐 모든게 명확하

긴 하다) 다른 문제가 없다면 감사하긴 한데, 문제는 이것이 퍼포머스 문제가 있다는 거다. 정확히 말하자면 sleep 후 wake-up 할때 latancy가 발생한다. (물론 cpu도 좀 잡아먹더라.)

정확히 얼마 정도의 퍼포먼스 문제가 있는지는 모르겠지만 확실한건 테스트 환경에서 system call을 blocking으로 설정하여 interrupt를 받아 wake-up 시키는 만큼의 overhead가 있는 것으로 보인다. 이럴거면 nonblocking 할 필요가 없는거다.


이것이 문제라면 시도해 볼 만한 것은 네가지가 있다.


1) CentOS 5.x로 내린다. (당연한 결론이라고 본다. 안되면 돌아가라.)


2) CentOS 6.x를 사용하되, 커널 파라미터로 nohz=off 옵션을 준다. (dyntick-idle 모드를 끄는 것인데, sleep-wake latancy를 제거할 수 있을 것으로 기대된다. 물론 기존처럼 HZ 마다 timer interrupt를 콜하는 방식으로 돌아가는 것은 아닌 것으로 보인다.)


3) CentOS 7.x를 사용한다. (이 버전의 kernel에서는 kernel NoHz가 업데이트 되어 Full-NoHz 모드로 동작할 수 있다고 한다. 과연 CentOS 7.x에서 Full-NoHz 모드를 쓸 수 있는지, 이것이 sleep-wake latancy를 제거할 수 있는가는 테스트 해봐야 한다.)


4) 입맛대로 컴파일한 커널을 쓴다. (빙고!)


현재 이것저것 테스트 해 볼 수 있는 환경은 아니라 일단 기록으로만 남겨둔다.


끗.


And