systemd socket 实现按需启动

本篇文章所使用的的环境为:

CentOS Linux release 7.9.2009 (Core)

systemd乃是一款极为强大之"工具箱",具备众多卓越功能,例如以PID 为1初始化操作系统,以及管理系统中的进程服务,涵盖的范围包括但不仅限于,启动、停止、重启、设定开机自启动等操作。此外,它还兼顾了其他多种功能,如维护挂载点及自动挂载,根据需求启动守护进程服务,设定主机名、时间、时区等,以及管理系统中的账户等。本文将着重解析其中的一个非常小的功能:按需启动,我们也称之为systemd socket。

什么是按需启动

不知道你们是否曾遭遇过如此困境,即在系统上存在着一项服务,然其必须对外开放访问权限,然而,此服务启动极其缓慢且访问效率极度低下,可能系统开机后,可能相当长时间也不会访问该服务。

在此情况下,身为系统管理员的我们,是否需要将该服务设定为开机自启动呢?这确实可以满足需求,但却会延长开机时间,甚至在无需对外提供访问的时刻,仍占据服务器资源。

那么,我们能否设想利用一个附加服务来完成这项工作呢?具体方法就是,由该额外服务来对外监测套接字,每当有连接建立时,首先接管该服务,在后台启动真正的服务,然后将请求转发到真实的服务之上,是用完毕后,systemd再销毁该服务。这样既可以完成请求,又能够节约系统资源。

当使用systemd按需启动某套接字进程后,其图示大致如下:

当需要访问该服务时候,systemd会接收请求流量,而后启动后端真实的服务,最后转发该流量,并且关闭原始套接字,图示如下:

实现一个socket步骤

所谓的按需启动,其实是systemd下的socket配置单元,其命名规则以.socket为后缀,主要服务于套接字模式的启动。

我们配置socket后,systemd会替我们监听端口,当访问该端口的时候,systemd会启动后端实例,并且将请求转发至该实例,后端完成需求后,由systemd销毁该实例。已达到按需启动的效果。

注意,我们想接入socket,编写的业务要符合该就不能再对外监听套接字了,虽然systemd不会卡这个,但是不符合按需启动的逻辑,所以,我们自己写的业务,想要接入systemd需要修改其代码,修改为符合systemd socket规则的,换句话说,服务器监听由systemd来替我们做了,我们只用关心其业务逻辑即可。甚至要从文件或者标准输入中获取客户端发送的数据。

创建简单的socket

所以,我们不仅需要配置socket,还需要配置其后端模板实例,先来创建一个socket,例如:

ini 复制代码
[Unit]
Description=a test sample web socket

[Socket]
ListenStream=9999
Accept=yes

我们将其命名为 testSampleWeb.socket,并且存放到/usr/lib/systemd/system目录下。

这段配置文件意思是:

  • Description: 该服务的简介
  • ListenStream: 对外监听的tcp端口
  • Accept: 为true表示为每个连接传入单独的服务

在此,我们仅需reload下systemd配置档:

bash 复制代码
systemctl daemon-reload

在使用systemctl status testSampleWeb.socket查看当前状态:

可以看到,目前状态是关闭状态的,可以使用start操作先开启该服务:

此时,若查看9999端口占用情况,会发现是systemd占用的,且pid为1,例如:

创建后端实例

注意,此时我们还没有编写属于该socket背后的实例,所以,请求该端口,会抛错,例如:

而在systemd日志中,会详细的描述,找不到该socket的后端实例配置,如:

所以,我们需要在此目录下,创建后端实例配置文件@.service结尾,如socket配置文件为: testSampleWeb.socket, 则该实例service的配置文件是testSampleWeb@.service,其内容如下:

ini 复制代码
[Unit]
Description=sample python webs %i

[Service]
ExecStart=-/usr/bin/python3 /root/sampleWeb.py
StandardInput=socket

这个要注意,为什么不是创建.service结尾的配置呢,这是因为此前创建socket的时候,Accept设置为True,所以要创建以@.service结尾的配置文件。

该配置的含义是:

  • ExecStart: 执行的命令
  • StandardInput: 标准输入方式为socket

接着,我们需要编写该后端服务代码,其内容如下:

python 复制代码
import sys

msgData = ""

while True:
    datas = sys.stdin.read(1)
    msgData += datas

    if msgData.endswith("\r\n\r\n"):
        break

httpInfo = msgData.split("\r\n")

rHeader = httpInfo[0]

httpDicts = {}
if 1 < len(httpInfo):
    httpDicts = dict([x.split(":",1) for x in httpInfo[1:] if ":" in x])

contentLen = 0
if "Content-Length" in httpDicts:
    contentLen = int(httpDicts["Content-Length"])

body = sys.stdin.read(contentLen)

sys.stdout.write("请求报文为:\n")
sys.stdout.write("\n请求行:\n" + str(httpInfo[0]))
sys.stdout.write("\n\n首部行:\n")
[print(k,":",httpDicts[k]) for k in httpDicts]
sys.stdout.write("\n\n报文主体:\n")
sys.stdout.write(body)
sys.stdout.write("\n\n")

上述代码,是一个简单的拆分http报文协议的代码,你可能很好奇,为什么没有调用socket呢?从哪儿来的客户端信息呢?正如上面所述,systemd socket已经帮我们把台架子搭好了,我们仅需要从标准输入流获取数据,要想发送给客户端,只需要往标准输出吐出信息即可。

测试

需要先加载配置文件,而后重启socket,命令如下:

bash 复制代码
systemctl daemon-reload
systemctl start testSampleWeb.socket 

使用netstat查看端口为9999的监听信息

bash 复制代码
netstat -tulnp | grep 9999

使用curl工具,向该接口发送一个post请求,例如:

bash 复制代码
curl -X POST -d "site=juejin,name=pdudo" 127.0.0.1:9999

输出的结果是我们预测的分析http报文的结果:

总结

systemd提供了非常多的功能,其中socket只是其中的一小块,但是确实是非常有意思的,试想一下,服务器上有一个对外的服务,非常重要,但是访问的很少,可能一年也访问不了几次,如果有这样一个工具,当监听到有客户端进行访问的时候,再启动服务,进而响应客户端需求,处理完毕后,再销毁该后端服务,这样既能够解决业务访问需求,又能够避免占用过多的资源,恰恰好。

sshd就是一个非常好的例子,你可以在虚拟机上安装一个centos 7,先将sshd服务先关闭,而后在终端中输入:

sql 复制代码
systemctl start sshd.socket

恭喜你,你已经学会了systemd socket了。

相关推荐
虎头金猫5 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
AI职业加油站5 天前
AI智能体应用工程师证书:政策红利下的职业新风口
大数据·运维·人工智能·学习·职场发展
此冬歌咏5 天前
K8s 节点故障实战:优雅驱逐 31 秒,硬故障 331 秒,以及那个永远 Pending 的 Pod
运维·k8s
-梅5 天前
linux(8) 软硬链接
linux·运维·服务器
张洛闻Eren5 天前
k8s云原生【第十课】:水平 Pod 自动扩缩容
运维·数据库·云原生·kubernetes·github
其实防守也摸鱼5 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
布裘5 天前
【银河麒麟】V4桌面图标消失,右击鼠标没反应排查
运维·银河麒麟·桌面环境
懂软件的胡子个哥5 天前
微信机器人为什么需要“回复候选”而不是所有 AI 内容直接发送
运维·微信·自动化·wechatapi·个人微信号二次开发
云贝贝贝5 天前
腾讯云 TDSQL(MySQL 版)性能优化与慢查询排障实战 6 招
运维·腾讯云
Lsetea5 天前
证书没到期却报certificate has expired:OpenSSL定位中间证书与系统时间
运维·https·ssl证书·openssl·证书链