使用Systemd,把服務(wù)裝進 Linux 心臟里

Linux非常的安全、可靠,而且有一股黑黝黝的妹子味道,這說明她也是柔軟的。
把服務(wù)跑在Linux上,就像男生把女裝藏在密碼箱里一樣讓人放心,它的穩(wěn)定安全可以讓人安穩(wěn)的睡個懶覺。
SPOF,是著名的單點問題。鑒于xjjdog非常討厭賣弄縮寫名詞的特點,我把它的全稱打在這里:single point of failure。
一臺Linux是孤單一臺Linux,所以跑在上面的服務(wù),就會有單點問題。解決單點問題通常可以通過集群,也可以通過奢侈的影子節(jié)點來達到這個目的。
但無論怎么搞,我們都希望跑在Linux上的某個進程,能夠隨著Linux的啟動自動啟動,隨著Linux的關(guān)閉自動關(guān)閉。我們希望自己的應(yīng)用程序,就像是Linux的血肉一樣,就像是安裝在Linux的心臟里。
準(zhǔn)備程序
很長一段時間里,我使用supervisor來做這種事情。但可惜的是,supervisor并不是Linux的預(yù)裝軟件,而且它是python寫的,需要裝一大堆依賴包。在網(wǎng)絡(luò)權(quán)限逐漸收緊的企業(yè)環(huán)境中,使用supervisor會給自己徒添煩惱。
是的,并不是supervisor不好,只不過它太麻煩。頻繁的網(wǎng)絡(luò)權(quán)限申請讓人抓狂,甚至喧賓奪主。
退而求其次,那就是systemd。

為了說明怎么使用它,我們準(zhǔn)備一段小小的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服務(wù)器,每當(dāng)你訪問它的時候,它都會輸出Ojbk!。
curl http://localhost:14000
把程序搞成服務(wù)
要想讓上面的程序成為系統(tǒng)的一部分,需要將其服務(wù)化:
[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,它配置了你確切要執(zhí)行的命令,我們這里當(dāng)然是一個簡單的class文件。
給這個文件起一個名字吧,比如xjjdogfirstjava.service?,然后把文件扔進/etc/systemd/system/目錄里。
要啟動這個服務(wù)的話,直接執(zhí)行下面的命令就好了:
systemctl start xjjdogfirstjava
如果你找不到剛剛創(chuàng)建的服務(wù),記得reload一下:
systemctl daemon-reload
如果你想要它隨著Linux啟動的話,可以執(zhí)行enable創(chuàng)建一個鏈接就可以了:
systemctl enable xjjdogfirstjava
除了這兩者,disable、stop、restart也是標(biāo)配的指令。
注意到配置文件里有這么兩行內(nèi)容:
Restart=always
RestartSec=1
它表明,每當(dāng)程序異常終止的時候,都會自動重啟這個進程,重啟的間隔是1秒。
更多一些的配置
我們注意到,上面的配置文件里,有After=network.target字樣。它表明當(dāng)MySQL啟動完畢的時候,才會啟動xjjdogfirstjava服務(wù),也就是強行指定了一個依賴關(guān)系。
但很多小伙伴在使用上面配置的時候,經(jīng)常發(fā)現(xiàn)服務(wù)自動重啟幾次之后,就再也不會再重啟了。
等等,我們不是使用了Restart=always參數(shù)么?
這是由于systemd默認(rèn)內(nèi)置了兩個閾值:
StartLimitBurst=5
StartLimitIntervalSec=10
當(dāng)你把StartLimitIntervalSec設(shè)置成0的時候,目的就總算達到了,我們的程序可以一直一失敗,一直重啟下去。
雖然這樣,保持一個重啟間隔是一個比較好的習(xí)慣。因為大多數(shù)服務(wù)重啟的時候,都會造成服務(wù)器資源的上升,如果你不想讓你的服務(wù)器報警,那就不要這么壓迫它。
End
這就是systemd,一個Linux內(nèi)置的程序。有了它,你的應(yīng)用程序終于能夠和Linux合為一體,天荒地老的伴隨下去了。

























