Pracuję nad kodem Pythona wzorowanym na serwerze prefabrykacji MPM Apache. Jestem bardziej programistą aplikacji niż programistą sieciowym i minęło 10 lat, odkąd przeczytałem Stevensa, więc staram się szybko zrozumieć kod.accept() z gniazdami współdzielonymi między wieloma procesami (w oparciu o prefinging Apache)
Znalazłem krótki opis how Apache's prefork code works, by Sander Temme.
Proces macierzysty, który zwykle działa jako pierwiastka, wiąże się z gniazdem (zwykle portu 80 lub 443). Tworzy potomka, który dziedziczy otwarty deskryptor pliku dla gniazda i zmienia identyfikator UID oraz gid na nieprzyznawalnego użytkownika i grupę . Dzieci konstruują zestaw zbiorczy deskryptorów plików detektorów (jeśli jest więcej niż jeden detektor) i obserwują aktywność na nim/nich. Jeśli zostanie znaleziona aktywność, dziecko wywoła accept() na aktywnym gnieździe i obsługuje połączenie. Kiedy zostanie to zrobione, powraca do oglądania zestawu danych pollset (lub listenera deskryptora).
Ponieważ wiele dzieci jest aktywnych i wszystkie odziedziczyły te same deskryptory plików gniazd, będą one oglądać ten sam zestaw pytań. Akceptowany muteks pozwala tylko jednemu dziecku oglądać zestaw ankiet, , a po znalezieniu aktywnego gniazda odblokuje muteksa, aby następne dziecko mogło zacząć oglądać zestawienie. Jeśli istnieje tylko jeden detektor , akceptowany muteks nie jest używany i wszystkie dzieci będą zawieszone w accept().
W ten sposób kod, na który patrzę, działa, ale nie rozumiem kilku rzeczy.
1) Jaka jest różnica między "dzieckiem" a "słuchaczem"? Myślałem, że każde dziecko jest słuchaczem, co jest zgodne z kodem, którego szukam, ale w opisie Temme może być "jeden słuchacz" i "dzieci". Kiedy dziecko ma wielu słuchaczy?
2) (w odniesieniu do 1) Czy jest to mutex dla jednego procesu lub system mutex? Jeśli o to chodzi, dlaczego mam muteks? Nie przyjmuje (2) własnego muteksu dla wszystkich słuchaczy? Moje badania mówią, że potrzebuję muteksu i że muteks musi być w całym systemie. (Stado, semaforów itp)
Temme mówi dalej:
rekordDzieci w pamięci współdzielonej obszaru (tabela wyników), gdy trwają serwowane żądanie. Bezczynne dzieci mogą zostać zabite przez proces nadrzędny na spełniające MaxSpareServers. Jeśli zbyt mało dzieci będzie w stanie bezczynności, rodzic będzie odradzać dzieci w celu zaspokojenia MinSpareServers.
3) Czy istnieje dobry kod odniesienia dla tej implementacji (najlepiej w języku Python)? Znalazłem Perla w wersji Net::Server::Prefork, która używa potoków zamiast pamięci współdzielonej do tablicy wyników. Znalazłem artykuł napisany przez Randal Schwartz, który wykonuje tylko preforking, ale nie robi tablicy wyników.
pre-fork example from the Perl Cookbook nie ma żadnego rodzaju blokady wokół select, a Chris Siebenmann's Python example mówi, że jest oparty na Apache, ale używa sparowanych gniazd do tablicy wyników, a nie wspólnej pamięci i używa gniazd dla kontroli, zawiera kontrolę dla danego dziecka do 'zaakceptować. To w ogóle nie pasuje do opisu Apache.
Czy używasz czegoś w stylu 'mod_wsgi' jako interfejsu między Apache i Python? Jeśli tak, to powinno załatwić to wszystko dla ciebie. –
To jest dla czystego serwera WSGI z prefixingiem Pythona. Mój klient chce lekkiego rozwiązania dla miejsc, które nie chcą Apache i mod_wsgi, lub odpowiednika. Jedynym serwerem WSGI tylko dla Pythona, który znalazłem, było Rozrastanie się, a to wymaga zdarzenia. ... Chociaż teraz stwierdziłem, że flup ma implementację taką jak Siebenmanna, która używa potoków dla tablicy wyników zamiast pamięci współdzielonej i z dopuszczalną licencją dla mojego klienta. –