Taming the OOM killer Feb 14, 2009

http://lwn.net/Articles/317814/

OOM killer도 역시 embedded에서 hot issue 중의 하나이다.
현재 Linux system의 OOM killer의 가장 큰 문제는 유연성의 부재이다.

Linux kernel은 Out of Memory 상황이 오면 몇가지 heuristic을 사용하여 비교적 시스템에 해가 적게가며, 많은 메모리를 반환할 수 있는 프로세스를 kill하게 된다. 하지만 그 결정은 kernel의 생각이지, 시스템을 운영하는 admin이나 사용하는 user의 의견이 반영된 결정은 아니다.

그렇게 까지 얘기하면 너무 심한가?
사실, User들도 커널의 결정을 거들수는 있다. 그것이 /proc/pid/oom_adj란 knob이다.
이 값은 커널의 여러 heuristic과 같이 각 프로세스의 oom_score의 값을 결정하는 데 기여한다. 커널은 결국 가장 큰 oom_score를 가진 프로세를 kill하게 되므로 사용자의 의견이 어느 정도 반영이 될 수는 있다.

이러한 설비들이 있긴 하지만, 시스템을 admin하는 입장에서 그러한 설비만으로 OOM policy를 구현하기가 그리 만만치가 않다. 생각을 해보아라. 그러한 설비만으로 시스템에 생성되는 모든 프로세스들의 oom_adj를 runtime에 조절하는 것이 과연 얼마나 수월할까? 여러 사람들의 서버로 사용되는 server computer를 생각해보자. 그 안에서 어떤 user가, 어떤 time에, 어떤 job을 어떤 order로 얼마나 많은 memory를 필요로 하며 실행될지...

그러므로 효율적인 OOM policy를 구현하기 위해서는 그 이상의 유연한 설비가 보다 OOM policy를 결정하는데 도움을 줄 것이다.

얼마전 LKML에서는 Alan Cox의 제안에 의해 Nikanth Karthikesan가 cgroup controller를 base로 oom_killer controller를 구현하였었다. cgroup을 사용하였기 때문에 기존보다는 OOM priority별 task들을 grouping하기가 수월해졌다. 하지만 이 approach는 CPU set을 고려하지 않았다.
CPU set A, B가 있다고 가정하자. CPU set A의 한 프로세스가 더 높은 oom.priority를 가지고 있을 경우, CPU set B가 OOM 상황을 만나게 되더라도 결국, CPU set A의 그 프로세스가 죽게 되는 것이다. 여러 토의 끝에, 결국 OOM 상황을 user space에 다루자는 얘기가 나왔다. 커널은 user space로 notify만 해주고 application들이 각자 자신의 cache를 drop한다거나 해서 OOM 상황에 대처하자는 것이다. Application들의 action이 충분한 free memory를 확보하는데 실패하였을 경우에만 커널이 마지막으로 기존의 OOM killer policy를 사용한다는 것이다.

2008년 초 Kosaki-san이 구현했던 mem_notify가 그러한 policy를 구현하기 위한 첫 발걸음이었다. 하지만 이 패치는 현재 mainline에 반영되지 못했다. 그 이유는 여러 이유가 있지만 그 중에서도 가장 큰 것은 2.6.28에서 memory reclaiming이 크게 변경되었기 때문이다. 그 패치의 notify 시점은 커널의 memory reclaim 루틴과 굉장히 밀접하게 관련되어 있었기 때문에 memory reclaiming이 많이 변하게 되면서 mem_notify가 동작할 수 없는 환경이 되버린 것이다. Memory reclaiming을 같이 작업한 Rik과 Kosaki 그리고 약간의 도움을 준 barrios는 이 상황에 대해서 잘 알고 있으며, barrios는 mem_notify 패치의 마지막 메일 또한 기억하고 있다.

마지막 토론에서의 문제는 실제 mem_notify가 필요할 때 notify를 해주지 못한다는 것이다. 즉, user가 notify를 받은 시점은 user가 어떤 action을 취하기에 늦어버렸다는 것이다. 그것은 현재 linux kernel의 문제이기도 하며, android가 별도의 low memory killer를 구현한 이유이기도 하다. 하지만 지금도 mem_notify의 design과 goal들은 여전히 유효하다.

한동안 Android의 Low memory killer가 staging tree에 들어간 것에 대해서 여로 토의가 있었다(http://lkml.org/lkml/2009/1/13/558). barrios 또한 staging tree에 반영되었던 low memory killer의 소스를 보았지만 사실 너무 specific하게 구현되어 있어 질타를 받기 딱 좋은 코드였다. OOM issue는 embedded뿐만이 아닌 server에서도 필요한 이슈이다. 하지만 android 팀의 코드는 embedded 중에서도 자신들의 android 플랫폼만을 위한 specific한 코드를 구현하였고, Greg은 그것을 stating tree에 반영한 것이다. Staging tree의 특성상 앞으로 더욱 발전시키면 되지, staging tree에 들어가질 못할 정도는 아니었음에도 불구하고, barrios의 생각으론 다국적을 가진 사람들이 토의하다보니 영어를 약간 잘못 해석하여 분쟁이 일어나 결국 code를 다시 revert하라는 말까지 나올 정도로 좀 소란스러웠었던 issue이다.

커널 트리에는 low_memory killer만 있고, 그 신호를 어떻게 user에서 처리하는지 잘 몰랐는데 LWN에 쉽게 잘 설명이 되어 있다. 첫번째 threshold에서는 background process들이 자신들의 state를 save하고, 점점 memory pressure가 심해지면 backgroud process 중 state를 save한 critical하지 않은 프로세스들을 kill하고, 마지막으론 foreground process들마저도 kill한다는 것이다. Android 팀이 이러한 설비가 필요했던 것 또한, 현재 linux kernel의 OOM killer의 반응은 너무 늦으며(Android팀은 보다 이른 신호가 필요하였다. 그래서 사전에 application에서 할 수 있는 일을 하려고 했던 것이다) 또한 그리 똑똑하지 못하다는 것을 반증하고 있다.

지금이다. Linux kernel의 OOM killer구조가 재설계되야 할 때는!!

1 개의 덧글:

우건 아빠 said...

민찬이형 안녕하세요^^
좋은글 잘봤어요ㅎㅎ