32 czy 64 bity? 21
Parafrazując tytuł jednego z poprzednich postów, ten powinien brzmieć “64 bitom mówimy papa”.
Nie jest żadną tajemnicą, że w Gronie używamy Linuxa. Niczym nowym też nie jest, że serwis stoi na frameworku Django. Podobno jesteśmy największym serwisem używającym tej technologii.
Jednak nie dla wszystkich jest jasne jak wygląda Django od strony serwerowej…
Podczas surfowania po Gronie, Twoje żądanie dotyczące strony grona (request) trafia do jednego z naszych serwerów. Następnie serwer przypisuje obsługę Twojego requesta jednemu z wielu procesów Django. Pojedynczy proces generuje stronę Grona, ale może obsługiwać tylko jedno żądanie na raz. Linuxowcy mogą znaleźć podobieństwo w tym modelu z modelem “prefork” z konfiguracji Apache. Po wygenerowaniu strony proces jest znów dostępny i czeka na kolejne kliknięcia użytkowników.
Wynika z tego, że na pojedynczym serwerze możemy obsłużyć na raz tylko tyle żądań, ile mamy uruchomionych procesów Django1. Niestety, pojedynczy proces zużywa dość dużo pamięci. Aby móc obsługiwać jak najwięcej użytkowników na raz, wypadałoby mieć możliwie dużo uruchomionych procesów. Jednak ich ilość jest limitowana wielkością pamięci operacyjnej.
Aby zwiększyć wydajność (czyli ilość stron które możemy wygenerować), staramy się w miarę możliwości zmniejszać wielkość pojedynczego procesu. W tym celu możemy zmniejszać ilość linii kodu lub optymalizować zużycie pamięci operacyjnej przez proces. Niestety oba zadania są bardzo trudne.
Ostatnio wpadliśmy na inny pomysł.
Nasze serwery używają 64 bitowej wersji linuxa. Administratorzy zdecydowali się na to już dawno temu. Głównym argumentem było to, że zamierzaliśmy używać większej ilości RAMu niż 4GB, oraz lepsza wydajność tej architektury.
Padł pomysł, żeby sprawdzić ile RAMu zaoszczędzimy przenosząc się na “stare” 32 bity. W sumie to w Pythonie całkiem sporo pamięci zajętej jest przez wskaźniki, a właśnie zmniejszenie jej dałoby największy zysk.
Efekt okazał się dużo lepszy niż przewidywaliśmy. W pełni załadowany proces Django na 32 bitach zajmuje około 60MB, czyli o 30% mniej niż na 64 bitach, gdzie jest to 95MB.
Oto przykład “topa” z maszyny 64 bitowej. Kolumna RES pokazuje orientacyjne zużycie pamięci przez proces:VIRT RES SHR S %CPU TIME+ COMMAND 212m 96m 3832 S 0 1:49.61 django '/gallery/3329236/0/' 203m 96m 3120 S 0 1:37.78 django '/gallery/4871149/6/0/' 211m 95m 3832 S 0 1:38.74 django '/mailbox/box/1/' 210m 95m 3824 S 0 1:45.45 django '/gallery/photo/40328359/' 210m 95m 3844 S 0 1:48.43 django '/users/index/' 210m 94m 3848 S 0 1:33.94 django '/users/'A oto, dla porównania, analogiczny z maszyny 32 bitowej:
VIRT RES SHR S %CPU TIME+ COMMAND 68396 62m 3484 S 0 2:06.94 django '/users/433317/' 67716 61m 3488 S 0 1:50.23 django '/gallery/photo/42009962/' 66264 60m 3488 S 0 2:01.94 django '/pub/join/' 65312 59m 3484 S 0 2:08.75 django '/users/' 65148 59m 3508 S 0 1:48.02 django '/users/1533943/friendlist/' 64884 59m 3508 S 0 1:51.48 django '/'
Podsumowując, możemy powiedzieć, że stosowane 64 bitów może nie być takie wspaniałe. Architektura x86_64 niewątpliwie ma wiele zalet, jednak w naszej sytuacji, gdzie ilość zajętego RAMu zaczyna mieć znaczenie, zaczynamy odczuwać jej wady.
Teoretycznie, po całkowitej migracji na 32 bity bylibyśmy w stanie obsługiwać o 1/3 więcej ruchu niż obecnie. Mamy więc o co walczyć.
1 W praktyce nie jest to takie proste, bo mamy także inne ograniczenia, jak na przykład moc procesora.
