SOP — FlexLM 双实例 systemd 化(31.29)¶
变更日期:2026-09-28 | 类型:C 类(生产变更) 交付目录:
flexlm_systemd_20260928/涉及主机:192.168.31.29(license 主机) 备份台账:backup/README.md
目录¶
1. 背景¶
31.29 上同时运行两套 FlexLM 许可服务:
| 服务 | 目录 | 端口 | 上线时间 |
|---|---|---|---|
Cadence(cdslmd) |
/opt/FlexLM/Cadence/ |
5280 / 5281 | 2026-09-26 |
Synopsys(snpslmd) |
/opt/FlexLM/Synopsys/ |
2700 / 2701 | 2026-09-28 |
两套原先都用 setsid nohup ./lmgrd … & 拉起的裸进程,带来三个问题:
- 无开机自启——主机重启后许可服务全丢,且无人察觉;
- 无自愈——lmgrd 异常退出后不会拉起;
- 停服靠按 PID 手工 kill,而机器上有两个 lmgrd,按名 kill 会误杀另一套(RED 线风险)。
本次把两套服务纳入 systemd 托管。
2. 目标¶
| 目标 | 可验证状态 |
|---|---|
| 两套服务由 systemd 托管 | systemctl is-active 均为 active,MainPID 指向各自的 lmgrd |
| 开机自启 | systemctl is-enabled 均为 enabled,multi-user.target.wants 下有符号链接 |
| cgroup 隔离 | 停一套不影响另一套(实测) |
| 停止后状态干净 | systemctl stop 后为 inactive (dead),而非 failed |
| 自动重启 | 非正常退出时 Restart=on-failure 在 10s 后拉起 |
不在本次范围:探活告警脚本与告警通道(用户决定暂不做,见第 9 章待办)。
3. 前置条件¶
- 31.29 root 免密 SSH 可达;systemd 252;Python 3.9.25(本次未用)
- 两套服务当前以裸进程运行,且需确认可接受中断窗口
- 执行前检查:
ssh root@192.168.31.29 'systemctl --version | head -1; pgrep -ax lmgrd; ss -lntp | grep -E ":5280|:5281|:2700|:2701"'
预期:systemd 版本可用;两条 lmgrd;四个端口 LISTEN。
4. 影响范围¶
| 项 | 内容 |
|---|---|
| 主机 | 192.168.31.29 |
| 是否停服 | 是——切换需停掉两套裸进程再交由 systemd 拉起 |
| 实际中断时长 | Cadence 约 64 秒、Synopsys 约 40 秒(⚠️ 远高于事前预估的 5–10 秒,原因见第 8 章风险 1) |
| 在跑业务 | 切换时无 Cadence/Synopsys 作业;Synopsys 工具此时因运行期兼容问题尚不可用 |
| 窗口 | 无特殊要求,但应避开 Cadence 作业时段 |
| 回滚代价 | 低:systemctl disable --now + 恢复裸进程启动命令 |
5. 分步操作¶
步骤 1:编写 unit 并投放¶
两个 unit 内容见 units/。Cadence 版如下(Synopsys 版仅路径不同):
[Unit]
Description=FlexNet License Server - Cadence (cdslmd)
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/opt/FlexLM/Cadence
ExecStart=/opt/FlexLM/Cadence/lmgrd -z -c /opt/FlexLM/Cadence/cds.license.dat -l /opt/FlexLM/Cadence/lmgrd.log
Restart=on-failure
RestartSec=10
SuccessExitStatus=15
TimeoutStopSec=30
KillMode=control-group
LimitNOFILE=8192
[Install]
WantedBy=multi-user.target
scp units/flexlm-cadence.service units/flexlm-synopsys.service root@192.168.31.29:/etc/systemd/system/
ssh root@192.168.31.29 'chmod 644 /etc/systemd/system/flexlm-*.service && systemctl daemon-reload'
关键设计点与坑:
-z+Type=simple:实测现有 lmgrd 进程pid≠sid(setsid后仍不一致),说明 lmgrd 会自行 fork,直接用Type=simple会让 systemd 立刻判定"主进程已退出"。加-z(前台运行)后 lmgrd 不再 fork,systemd 才能正确跟踪。-z由lmgrd -help实测确认受支持。SuccessExitStatus=15:实测 lmgrd 收到 SIGTERM 后exit(15)(journal 记status=15/n/a)。不声明则systemctl stop后单元状态显示failed,运维会误判为故障。KillMode=control-group(默认):停止时杀整个 cgroup,连带清掉 vendor daemon;这正是取代"按 PID 手工 kill"的关键。StartLimitIntervalSec/StartLimitBurst:防止 license 损坏导致 lmgrd 秒退时无限重启。
步骤 2:停止裸进程¶
⚠️ 必须按 PID 精确识别,机器上有两个 lmgrd:
ssh root@192.168.31.29 '
for p in $(pgrep -x lmgrd); do
cmd=$(tr "\0" " " < /proc/$p/cmdline 2>/dev/null || true)
case "$cmd" in
*Cadence/cds.license.dat*) echo "[STOP] cadence bare pid=$p"; kill "$p" ;;
*Synopsys/Synopsys.dat*) echo "[STOP] synopsys bare pid=$p"; kill "$p" ;;
esac
done'
坑:用 pgrep -x lmgrd(按进程名精确匹配),不要用 pgrep -f 或 pkill -f——SSH 脚本自身命令行含这些路径字符串,-f 会把脚本自己匹配进来并杀掉会话。
步骤 3:交由 systemd 启动¶
ssh root@192.168.31.29 'systemctl daemon-reload && systemctl enable --now flexlm-cadence.service flexlm-synopsys.service'
预期:两个 Created symlink … multi-user.target.wants/…,随后 is-active 为 active。
坑(端口占用):切换瞬间 lmgrd 会在日志里报
The TCP port number in the license, 5280, is already in use.
… Retrying for about 5 more minutes
这是正常现象:被 kill 的旧 lmgrd 持有过客户端连接,socket 进入 TIME-WAIT(实测 ss -ant 可见),而 lmgrd 未使用 SO_REUSEADDR,无法立即 bind。lmgrd 会自行重试,实测约 60–70 秒后自动绑上,无需干预。此行为与 systemd 无关,裸进程重启同样存在。
步骤 4:等待就绪(不要用固定 sleep 判定)¶
就绪判据是端口真正 LISTEN,而非进程存在:
ssh root@192.168.31.29 '
for i in $(seq 1 30); do
ss -lnt 2>/dev/null | grep -q ":5280" && ss -lnt 2>/dev/null | grep -q ":2701" && break
sleep 5
done
ss -lntp | grep -E ":5280|:5281|:2700|:2701"'
预期:四个端口 LISTEN,且 lmgrd 与各自的 vendor daemon 并列在同一行(说明 vendor daemon 已被拉起)。
6. 验证¶
| 验证项 | 命令 | 本次实测结果 |
|---|---|---|
| 单元状态 | systemctl is-active flexlm-cadence flexlm-synopsys |
active / active ✅ |
| 开机自启 | systemctl is-enabled flexlm-cadence flexlm-synopsys |
enabled / enabled ✅ |
| cgroup 归属 | systemctl status <unit> -n 0 \| grep -A3 CGroup |
lmgrd 与 vendor daemon 同属一个 slice ✅ |
| 服务端 Cadence | lmutil lmstat -c 5280@192.168.31.29 |
server UP (MASTER) v11.16.4 ✅ |
| 服务端 Synopsys | lmutil lmstat -c 2700@192.168.31.29 |
server UP (MASTER) v11.14.1 ✅ |
| cgroup 隔离 | 停 Synopsys 后查 Cadence | Cadence 端口/进程/许可全程未受影响 ✅ |
| stop 状态 | systemctl stop 后查状态 |
inactive (dead)、Result=success ✅ |
| 幂等复跑 | 重跑 systemctl enable --now |
无变更,enabled 保持 ✅ |
| 客户端(Cadence) | .18 上 lmdiag -c 5280@… -n Assura_DRC |
正常 ✅ |
| 客户端(Synopsys) | .18 上 lmdiag -c 2700@… -n Verdi |
This license can be checked out ✅ |
| 重启恢复耗时 | stop 后 start 并轮询端口 |
约 70 秒(TIME-WAIT 等待) |
7. 回滚¶
触发判据(任一达标即回滚):单元持续 failed 且自动重启无效;lmstat 报 server 不可达;
Cadence 许可在切换后长时间不恢复。
回滚步骤¶
# 1) 停用并禁用单元(不会误伤另一套,cgroup 隔离)
ssh root@192.168.31.29 'systemctl disable --now flexlm-cadence.service flexlm-synopsys.service'
# 2) 确认端口与进程已清空
ssh root@192.168.31.29 'pgrep -ax lmgrd; ss -lnt | grep -E ":5280|:5281|:2700|:2701"'
# 3) 恢复裸进程(原启动方式,两套各一条)
ssh root@192.168.31.29 'cd /opt/FlexLM/Cadence && setsid nohup ./lmgrd -c /opt/FlexLM/Cadence/cds.license.dat -l /opt/FlexLM/Cadence/lmgrd.log </dev/null >/dev/null 2>&1 &'
ssh root@192.168.31.29 'cd /opt/FlexLM/Synopsys && setsid nohup ./lmgrd -c /opt/FlexLM/Synopsys/Synopsys.dat -l /opt/FlexLM/Synopsys/lmgrd.log </dev/null >/dev/null 2>&1 &'
# 4) 移除 unit 文件(确认无需保留后)
ssh root@192.168.31.29 'rm -f /etc/systemd/system/flexlm-cadence.service /etc/systemd/system/flexlm-synopsys.service && systemctl daemon-reload'
回滚后验证¶
ssh root@192.168.31.29 'pgrep -ax lmgrd; pgrep -ax cdslmd; pgrep -ax snpslmd; ss -lntp | grep -E ":5280|:5281|:2700|:2701"'
预期:两条 lmgrd + 两个 vendor daemon;四个端口 LISTEN。
注意回滚后 lmgrd 恢复为前台 fork 模式(去掉 -z),与 systemd 版本行为不同,属预期。
8. 风险说明¶
| # | 风险 | 缓解 / 实测结论 |
|---|---|---|
| 1 | 中断时长被低估:事前预估 5–10 秒,实测 Cadence 约 64 秒、Synopsys 约 40 秒 | 根因是 TIME-WAIT 阻塞 bind(见步骤 3 的坑),lmgrd 重试后才绑上。下次同类变更应按 60–90 秒预留窗口 |
| 2 | 停一套误杀另一套 | 实测已消除:两个 unit 各自独立 cgroup,systemctl stop flexlm-synopsys 全程未触及 Cadence 的进程与端口 |
| 3 | 裸进程残留导致端口冲突 | 步骤 2 按 PID 精确停止,并显式清理孤儿 vendor daemon |
| 4 | unit 行为不符预期导致服务起不来 | 首次上线时确实出现"端口被占用"告警,确认为 TIME-WAIT(非配置错误);已备完整回滚路径 |
| 5 | Restart=on-failure 遇 license 损坏时无限重启 |
StartLimitIntervalSec=300 + StartLimitBurst=5 限制 |
| 6 | lmgrd 以 root 运行(安全提示) | 沿用原部署方式(FlexLM 传统以 root 运行),未改变既有安全姿势 |
| 7 | 无告警:服务挂了无人知 | 本次未做(用户决定);systemd 的自动重启是当前唯一自愈手段,见第 9 章待办 |
9. 附录¶
交付物清单¶
| 文件 | 说明 |
|---|---|
docs/SOP.md |
本文件 |
docs/RUNBOOK.md |
FlexLM systemd 单元运维手册 |
units/flexlm-cadence.service |
Cadence 许可服务单元(投放至 /etc/systemd/system/) |
units/flexlm-synopsys.service |
Synopsys 许可服务单元(同上) |
backup/README.md |
回滚方式台账 |
变更清单(31.29)¶
| 项 | 变更前 | 变更后 |
|---|---|---|
/etc/systemd/system/ |
无 flexlm 单元 | 新增 flexlm-cadence.service、flexlm-synopsys.service |
| 服务启动方式 | setsid nohup … & 裸进程 |
systemd 托管(-z 前台 + Type=simple) |
| 开机自启 | 无 | multi-user.target.wants 下已 enable |
| 自动重启 | 无 | Restart=on-failure,RestartSec=10 |
| Cadence license/二进制 | — | 未改动 |
| Synopsys license/二进制 | — | 未改动 |
| firewalld | — | 未改动 |
待办¶
- 探活告警(用户本次决定暂不做):systemd 只能自愈"进程退出",无法发现"进程活着但不发许可"。
后续可加
systemd timer+lmstat探活脚本,异常时写 journal / 发 Webhook。31.29 已实测可出网。 systemctl restart的 TIME-WAIT 等待:可考虑在内核侧调net.ipv4.tcp_tw_reuse(对 listen socket 无效, 实用性待评估),或接受 60–70 秒恢复。- lmgrd 日志无限增长:
-l <file>每次启动截断重写,进程长跑期间日志会持续增长,后续可纳入 logrotate。
来源:
/home/rain/Documents/eda_tools_ins/Synopsys/flexlm_systemd_20260928/docs/SOP.md| 最后更新:2026-09-28 13:25(由build/sync.py同步,请勿在站点侧修改)