clash verge rev 某不存在的软件更新到 2.0 后,启动时会安装 systemd 服务用于 TUN 网络代理。但升级后每次都需要重新执行 uninstall-serviceinstall-service, 且必定会卡死一段时间。这里记录一下排查过程。

检查为何要执行 uninstall-serviceinstall-service

查看源码得知,service 安装由这个函数执行,检查调用他的 check_service 函数发现对 “SERVICE_URL/get_clash” 发 GET 请求来检测服务是否运行。 “SERVICE_URL” 是一个常量,为 “http://127.0.0.1:33211

lsof 看看是什么进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
❯ sudo lsof -i :33211
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
clash-ver 738 root 9u IPv4 5515 0t0 TCP localhost:33211 (LISTEN)
❯ sudo lsof -p 738
lsof: WARNING: can't stat() fuse.portal file system /run/user/1001/doc
Output information may be incomplete.
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
clash-ver 738 root cwd DIR 259,6 4096 2 /
clash-ver 738 root rtd DIR 259,6 4096 2 /
clash-ver 738 root txt REG 259,6 1068272 4667021 /usr/bin/clash-verge-service
clash-ver 738 root mem REG 259,6 2014520 4590980 /usr/lib/libc.so.6
clash-ver 738 root mem REG 259,6 14280 4590996 /usr/lib/libdl.so.2
clash-ver 738 root mem REG 259,6 973144 4591006 /usr/lib/libm.so.6
clash-ver 738 root mem REG 259,6 14288 4591034 /usr/lib/libpthread.so.0
clash-ver 738 root mem REG 259,6 14352 4591039 /usr/lib/librt.so.1
clash-ver 738 root mem REG 259,6 915712 4591699 /usr/lib/libgcc_s.so.1
clash-ver 738 root mem REG 259,6 228376 4590929 /usr/lib/ld-linux-x86-64.so.2
clash-ver 738 root 0r CHR 1,3 0t0 4 /dev/null
clash-ver 738 root 1u unix 0x000000005430ea85 0t0 17938 type=STREAM (CONNECTED)
clash-ver 738 root 2u unix 0x000000005430ea85 0t0 17938 type=STREAM (CONNECTED)
clash-ver 738 root 3u a_inode 0,16 0 2087 [eventpoll:4,8,9]
clash-ver 738 root 4u a_inode 0,16 0 2087 [eventfd:0]
clash-ver 738 root 5u a_inode 0,16 0 2087 [eventpoll:4,8,9]
clash-ver 738 root 6u unix 0x00000000cb59cf7b 0t0 2387 type=STREAM (CONNECTED)
clash-ver 738 root 7u unix 0x00000000093de046 0t0 2388 type=STREAM (CONNECTED)
clash-ver 738 root 8u unix 0x00000000cb59cf7b 0t0 2387 type=STREAM (CONNECTED)
clash-ver 738 root 9u IPv4 5515 0t0 TCP localhost:33211 (LISTEN)

检查服务状态

看看装了哪些服务

❯ systemctl list-units|grep clash
clash-verge-service.service

使用 systemctl status clash-verge-service.service 查看服务状态和文件位置,打开后如下

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=Clash Verge Service helps to launch Clash Core.
After=network-online.target nftables.service iptables.service

[Service]
Type=simple
ExecStart=/usr/bin/clash-verge-service
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Systemd serive 定义中,After=network-online.target nftables.service iptables.service 表明至少一个服务完成启动后才会启动 clash-verge-service。
我的系统使用 firewalld 作为防火墙,它会作为上层服务自动启用 nftables.serviceiptables.service 作为底层服务,所以 nftables.service iptables.service 两个服务不会启动,因此只需要等待 network-online.target 启动完成即可。

测试 network-online.target

执行 systemctl start network-online.target,发现会卡死将近 2 min。使用 systemd-analyze critical-chain network-online.target 检查依赖和耗时,发现实际执行(CPU 时间)正常,但是启动前经过了长时间等待。

接下来查了下 network-online.target 的依赖和被依赖,没什么问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
❯ systemctl list-dependencies network-online.target --after
network-online.target
○ ├─NetworkManager-wait-online.service
● └─network.target
● ├─dhcpcd.service
● ├─NetworkManager.service
● ├─systemd-networkd.service
● ├─wpa_supplicant.service
● └─network-pre.target
● ├─firewalld.service
○ ├─ip6tables.service
○ ├─iptables.service
○ ├─nftables.service
● └─systemd-network-generator.service

❯ systemctl list-dependencies network-online.target --before
network-online.target
○ ├─archlinux-keyring-wkd-sync.service
● ├─clash-verge-service.service
○ ├─docker.service
○ └─shutdown.target
○ ├─systemd-halt.service
○ ├─systemd-kexec.service
○ ├─systemd-poweroff.service
○ ├─systemd-reboot.service
○ ├─systemd-soft-reboot.service
○ └─final.target
○ ├─systemd-halt.service
○ ├─systemd-kexec.service
○ ├─systemd-poweroff.service
○ ├─systemd-reboot.service
○ └─systemd-soft-reboot.service

同样,执行任何依赖于 network-online.target 的服务都会卡死将近 2 min(我就说我 docker.service 为什么启动慢)

参考 systemd.io,可以知道在使用 systemd 的系统中,network-online.target 一般会在网络连接成功后启动,用于确保服务在网络连接成功后启动来。如需要进行远程磁盘挂载、远程数据库连接等操作,可以将服务依赖于 network-online.target
network-online.target 主要通过 NetworkManager-wait-online.servicesystemd-networkd-wait-online.service 来启动。我使用的是 NetworkManager,所以应该是 NetworkManager-wait-online.service
在 “To verify that the right service is enabled (usually only one should be):” 章节中提到了可以使用如下命令验证 service 正常配置:

$ systemctl is-enabled NetworkManager-wait-online.service systemd-networkd-wait-online.service
disabled
enabled

经排查发现同时启用了 NetworkManager-wait-online.servicesystemd-networkd-wait-online.service,导致了问题。禁用 systemd-networkd-wait-online.service 后,network-online.target 启动正常。