2013-06-18 7 views
39

Ruby 2.0 wprowadza przyjazny dla śmieci sposób na przechowywanie śmieci. Wydaje się, że moje procesy utrzymują pamięć współużytkowaną przez więcej niż kilka minut - wydaje się, że dość szybko przenosi się z shared_dirty na private_dirty.Jak poprawić współużytkowanie pamięci między procesami jednorożca z Ruby 2.0 na Linuksie

Niektórzy inni mieli sukces uzyskiwanie to do pracy:

Ten program może być używany do sprawdzania statystyk pamięci w systemie Linux: https://gist.github.com/kenn/5105061

Moje jednorożca konfiguracja: https://gist.github.com/inspire22/f82c77c0a465f1945305

Z jakiegoś powodu moje aplikacje jednorożca, również z preload_app = true, mają znacznie mniej pamięci współdzielonej. Ruby 2.0-p195, szyny 3.2, Linux 2.6.18 (CentOS)

[[email protected] script]# ruby memstats.rb 4946 
Process:    4946 
Command Line:  unicorn_rails worker[4] -c /u/apps/newap/current/lib/unicorn.rb -E production -D 
Memory Summary: 
    private_clean     0 kB 
    private_dirty    56,324 kB 
    pss      60,256 kB 
    rss      83,628 kB 
    shared_clean    4,204 kB 
    shared_dirty    23,100 kB 
    size      108,156 kB 
    swap       68 kB 

Jeśli shutdown proces mistrz całości (a nie tylko HUP), a następnie uruchomić go ponownie i natychmiast sprawdzić pracownika zanim jakiekolwiek wnioski zostały w kolejce, ja lepiej historię:

[[email protected] script]# ruby memstats.rb 5743 
Process:    5743 
Command Line:  unicorn_rails worker[4] -c /u/apps/newap/current/lib/unicorn.rb -E production -D 
Memory Summary: 
    private_clean     0 kB 
    private_dirty    21,572 kB 
    pss      27,735 kB 
    rss      66,296 kB 
    shared_clean    2,484 kB 
    shared_dirty    42,240 kB 
    size      91,768 kB 
    swap       0 kB 

Ale w ciągu 5 sekund od chwili rozruchu, są one z powrotem do ~ 20 MB shared_clean + shared_dirty.

Podejrzewałem, że przyczyną problemu może być zamiana, ale po obniżeniu swapalności i upewnieniu się, że ani proces macierzysty, ani potomny nie zostaną zamienione (przy użyciu metody swapstats.rb), problem będzie nadal występował.

Nie rozumiem dokładnie, czym jest shared_dirty i jak zmienia się w pamięć prywatną. Chciałbym również sugestie dotyczące poprawy długowieczności i ilości mojej wspólnej pamięci. Dzięki!

+0

Nadal nie mam na to rozwiązania. Teraz uważam, że jest to problem a) 32-bitowej wersji Linuksa, oraz b) środowiska o ograniczonej pamięci (choć nawet przy odrzuconej swapie nadal występuje) – Kevin

+0

Mam ten komentarz od autora istotki: https: // świergot.com/kenn/status/402832587007086592 –

+0

niesamowite, dziękuję :) – Kevin

Odpowiedz

7

Według this answer, który można już zauważyć, że jest to linia, która brzmi:

Zauważ, że strona „akcja-stanie” jest liczony jako prywatny odwzorowania aż jest rzeczywiście wspólna. tj. jeśli jest tylko jeden proces aktualnie używający biblioteki libfoo, ta sekcja biblioteki będzie wyświetlana w prywatnych mapowaniach procesu . Będzie on rozliczany we wspólnych mapowaniach (i usunięty z prywatnych) tylko wtedy, gdy/inny proces rozpocznie używając tej biblioteki.

Co zrobić, aby sprawdzić, czy otrzymujesz korzyści outlined in this article, jest umieszczany plik xml 10MX jako literał ciąg bezpośrednio w kodzie źródłowym. Następnie, jeśli uruchomisz 20 pracowników, będziesz w stanie sprawdzić, czy korzystasz z 200 MB pamięci, czy tylko 10 MB, jak można się spodziewać po nowej funkcji odśmiecania.

UPDATE:

Szukałem przez the unicorn source i znaleźć odniesienie do this wonderful article.

Podsumowując, stwierdza, że ​​w celu dostosowania aplikacji do skorzystania z Ruby Enterprise Edition na kopiowanie przy zapisie przyjazną śmieciarza, trzeba zestaw GC.copy_on_write_friendly true zanim bulić.

if GC.respond_to?(:copy_on_write_friendly=) 
    GC.copy_on_write_friendly = true 
end 

Na podstawie dostarczonego pliku konfiguracyjnego jednorożca wygląda na to, że brakuje przydziału.

Również I cieszył się czytanie tych Pokrewne artykuły:

Według fork man page:

Pod Linuksem fork() jest implementowany za pomocą stron kopiowania na zapis, więc jedyną karą, jaką się nakłada jest , jest czas i pamięć wymagana do powielenia tabel stron nadrzędnych i utworzenia unikalnego zadania dla struktury dla dziecka .

Od wersji 2.3.3, zamiast wywoływania jądra fork() Układ wezwanie, widelca glibc (opakowanie), który jest przewidziany jako część NPTL gwintowania realizacji powołuje clone (2) z flagami, które zapewniają ten sam efekt co tradycyjne wywołanie systemowe. (Wywołanie fork() to równoważne wywołaniu klonowania (2) określanie flag jako tylko SIGCHLD.) Opakowanie glibc wywołuje wszelkie procedury obsługi forków, które zostały ustanowione przy użyciu pthread_atfork (3).

I według clone man page:

przeciwieństwie fork (2), te połączenia umożliwiają proces dziecko do dzielenia części kontekstu wykonania z procesu wywołującego, takich jak miejsca pamięci , tabelę deskryptorów plików i procedur obsługi tabel .

Więc, mam na myśli to: linuxowe kopie na piśmie, które jest cechą, na której opiera się jednorożec, aby zaimplementować dzielenie pamięci, nie zostało zaimplementowane do czasu wydania biblioteki libc 2.2.3 (proszę, ktoś poprawny mnie, jeśli się mylę w tej interpretacji).

Aby sprawdzić wersję biblioteki używasz, można wpisać:

ldd --version 

Albo znaleźć glibc i uruchomić go bezpośrednio. W moim systemie plik znalazł się w następującej lokalizacji:

locate libc.so 
/lib/x86_64-linux-gnu/libc.so.6 
+0

Interesujący pomysł na test, dzięki! Teoretycznie powyższy program memstats.rb powinien to wyjaśnić, ale nigdy nie wiadomo. – Kevin

+0

Im bardziej na to patrzę, jest to raczej złe pytanie, ponieważ jest "otwarte". Bez dostępu do systemu niemożliwe byłoby "przybicie" odpowiedzi. Twoja odpowiedź stanowi świetny sposób na dalsze debugowanie, co może być nie tak. Ostatecznie podejrzewam, że ma to coś wspólnego ze starszą wersją Linuksa w systemie 32-bitowym, z łagodnymi ograniczeniami pamięci/zamianą. Twój test jest świetnym pomysłem, chociaż może zostać powielony przy pomocy skryptu memstats.rb. – Kevin

+0

@Kevin Dodano aktualizację, która wydaje się być przyczyną problemu. Daj mi znać, jeśli Ci się uda. – Homer6