Podczas pisania aplikacji internetowych, często potrzebuję odciążyć ciężkie obliczeniowo zadania do asynchronicznego skryptu robotniczego, zaplanować zadania na później, lub nawet napisać demona, który nasłuchuje gniazda, aby komunikować się bezpośrednio z klientami.
Choć czasami mogą istnieć lepsze narzędzia do wykonania tego zadania – zawsze najpierw rozważ użycie istniejącego oprogramowania, takiego jak serwer kolejki zadań – napisanie własnej usługi może dać ci poziom elastyczności, którego nigdy nie uzyskasz, będąc związanym ograniczeniami oprogramowania firm trzecich.
Ciekawe jest to, że stworzenie usługi dla Linuksa jest dość proste: użyj swojego ulubionego języka programowania, aby napisać długo działający program i zamień go w usługę za pomocą systemd.
Ztwórzmy mały serwer używając PHP. Już widzę, jak podnoszą się Twoje brwi, ale działa to zaskakująco dobrze. Będziemy nasłuchiwać na porcie UDP 10000, a każdą otrzymaną wiadomość będziemy zwracać z transformacją ROT13:
Uruchommy go:
$ php server.php
I przetestujmy go w innym terminalu:
$ nc -u 127.0.0.1 10000
Hello, world!
Uryyb, jbeyq!
Cool, działa. Teraz chcemy, aby ten skrypt działał przez cały czas, był restartowany w przypadku awarii (nieoczekiwanego wyjścia), a nawet przetrwał restart serwera. To jest miejsce gdzie systemd wchodzi do gry.
Zamieniamy go w usługę
Utwórzmy plik o nazwie /etc/systemd/system/rot13.service
:
Description=ROT13 demo service
After=network.target
StartLimitIntervalSec=0
Type=simple
Restart=always
RestartSec=1
User=centos
ExecStart=/usr/bin/env php /path/to/server.php
WantedBy=multi-user.target
Będziesz potrzebował:
- ustawić swoją rzeczywistą nazwę użytkownika po
User=
- ustawić właściwą ścieżkę do swojego skryptu w
ExecStart=
To wszystko. Możemy teraz uruchomić usługę:
$ systemctl start rot13
I automatycznie uruchomić ją przy starcie:
$ systemctl enable rot13
Dalej
Teraz, gdy twoja usługa (miejmy nadzieję) działa, ważne jest, aby zagłębić się nieco w opcje konfiguracyjne i upewnić się, że zawsze będzie działać tak, jak tego oczekujesz.
Start we właściwej kolejności
Możesz się zastanawiać, co robi dyrektywa After=
. Oznacza ona po prostu, że twoja usługa musi zostać uruchomiona po tym, jak sieć będzie gotowa. Jeśli twój program oczekuje, że serwer MySQL będzie gotowy do pracy, powinieneś dodać:
After=mysqld.service
Restart przy wyjściu
Domyślnie systemd nie uruchamia ponownie twojej usługi, jeśli program kończy pracę z jakiegokolwiek powodu. To zazwyczaj nie jest to, czego chcesz dla usługi, która musi być zawsze dostępna, więc instruujemy ją, aby zawsze restartowała się przy wyjściu:
Restart=always
Możesz również użyć on-failure
aby restartować tylko wtedy, gdy status wyjścia nie jest 0
.
Domyślnie, systemd próbuje restartować system po 100ms. Możesz określić liczbę sekund, które należy odczekać przed próbą ponownego uruchomienia, używając:
RestartSec=1
Unikanie pułapki: limit startu
Ja osobiście wpadłem w tę pułapkę więcej niż raz. Domyślnie, gdy skonfigurujesz Restart=always
tak jak my, systemd rezygnuje z ponownego uruchomienia twojej usługi, jeśli nie uda się jej uruchomić więcej niż 5 razy w odstępie 10 sekund. Na zawsze.
Istnieją dwie opcje konfiguracyjne odpowiedzialne za to:
StartLimitBurst=5
StartLimitIntervalSec=10
Dyrektywa RestartSec
również ma wpływ na wynik: jeśli ustawisz ją na ponowne uruchomienie po 3 sekundach, wtedy nigdy nie możesz osiągnąć 5 nieudanych prób w ciągu 10 sekund.
Prostą poprawką, która zawsze działa, jest ustawienie StartLimitIntervalSec=0
. W ten sposób systemd będzie próbował zrestartować twoją usługę na zawsze.
Dobrym pomysłem jest ustawienie RestartSec
na co najmniej 1 sekundę, aby uniknąć zbyt dużego stresu na twoim serwerze, gdy rzeczy zaczynają iść źle.
Jako alternatywę możesz pozostawić ustawienia domyślne i poprosić systemd o ponowne uruchomienie serwera, jeśli limit startu zostanie osiągnięty, używając StartLimitAction=reboot
.
Czy to naprawdę wszystko?
.