使用Systemd,把服務裝進 Linux 心臟里
Linux非常的安全、可靠,而且有一股黑黝黝的妹子味道,這說明她也是柔軟的。
把服務跑在Linux上,就像男生把女裝藏在密碼箱里一樣讓人放心,它的穩定安全可以讓人安穩的睡個懶覺。
SPOF,是著名的單點問題。鑒于xjjdog非常討厭賣弄縮寫名詞的特點,我把它的全稱打在這里:single point of failure。
一臺Linux是孤單一臺Linux,所以跑在上面的服務,就會有單點問題。解決單點問題通常可以通過集群,也可以通過奢侈的影子節點來達到這個目的。
但無論怎么搞,我們都希望跑在Linux上的某個進程,能夠隨著Linux的啟動自動啟動,隨著Linux的關閉自動關閉。我們希望自己的應用程序,就像是Linux的血肉一樣,就像是安裝在Linux的心臟里。
準備程序
很長一段時間里,我使用supervisor來做這種事情。但可惜的是,supervisor并不是Linux的預裝軟件,而且它是python寫的,需要裝一大堆依賴包。在網絡權限逐漸收緊的企業環境中,使用supervisor會給自己徒添煩惱。
是的,并不是supervisor不好,只不過它太麻煩。頻繁的網絡權限申請讓人抓狂,甚至喧賓奪主。
退而求其次,那就是systemd。
為了說明怎么使用它,我們準備一段小小的Java程序:
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpServer;
import java.io.OutputStream;
import java.net.InetSocketAddress;
public class Runner {
public static void main(String[] args) throws Exception{
HttpServer server = HttpServer.create(new InetSocketAddress(14000), 0);
HttpContext context = server.createContext("/");
context.setHandler(exchange -> {
try {
String response = "Ojbk!";
exchange.sendResponseHeaders(200, response.getBytes().length);
OutputStream os = exchange.getResponseBody();
os.write(response.getBytes());
os.close();
} catch (Exception ex) {
ex.printStackTrace();
}
});
server.start();
}
}
這段代碼將在14000端口開啟一個Http服務器,每當你訪問它的時候,它都會輸出Ojbk!。
curl http://localhost:14000
把程序搞成服務
要想讓上面的程序成為系統的一部分,需要將其服務化:
[Unit]
Description=My First Java Service
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=root
ExecStart=/usr/bin/env java /opt/Runner
[Install]
WantedBy=multi-user.target
比較重要的就是ExecStart,它配置了你確切要執行的命令,我們這里當然是一個簡單的class文件。
給這個文件起一個名字吧,比如xjjdogfirstjava.service?,然后把文件扔進/etc/systemd/system/目錄里。
要啟動這個服務的話,直接執行下面的命令就好了:
systemctl start xjjdogfirstjava
如果你找不到剛剛創建的服務,記得reload一下:
systemctl daemon-reload
如果你想要它隨著Linux啟動的話,可以執行enable創建一個鏈接就可以了:
systemctl enable xjjdogfirstjava
除了這兩者,disable、stop、restart也是標配的指令。
注意到配置文件里有這么兩行內容:
Restart=always
RestartSec=1
它表明,每當程序異常終止的時候,都會自動重啟這個進程,重啟的間隔是1秒。
更多一些的配置
我們注意到,上面的配置文件里,有After=network.target字樣。它表明當MySQL啟動完畢的時候,才會啟動xjjdogfirstjava服務,也就是強行指定了一個依賴關系。
但很多小伙伴在使用上面配置的時候,經常發現服務自動重啟幾次之后,就再也不會再重啟了。
等等,我們不是使用了Restart=always參數么?
這是由于systemd默認內置了兩個閾值:
StartLimitBurst=5
StartLimitIntervalSec=10
當你把StartLimitIntervalSec設置成0的時候,目的就總算達到了,我們的程序可以一直一失敗,一直重啟下去。
雖然這樣,保持一個重啟間隔是一個比較好的習慣。因為大多數服務重啟的時候,都會造成服務器資源的上升,如果你不想讓你的服務器報警,那就不要這么壓迫它。
End
這就是systemd,一個Linux內置的程序。有了它,你的應用程序終于能夠和Linux合為一體,天荒地老的伴隨下去了。