lac_agent自愈链路下篇——从systemd托管到真正的自愈

文章目录



兼容 是对前人努力的尊重 是确保业务平稳过渡的基石 然而 这仅仅是故事的起点


上篇说了crontab守护lac_agent的那些坑,说实话写完上篇的时候我自己都有点后怕------在那之前我一直觉得crontab每5分钟拉起一次已经够用了,直到凌晨三点被叫醒才知道这套机制有多脆弱。

这篇文章接着聊,怎么从crontab迁移到systemd托管,以及怎么搭建一套真正靠谱的健康检查和自动恢复体系。

为什么crontab不够用

先简单回顾一下上篇提到的crontab的几个硬伤:

  1. 进程僵死(Z状态/D状态)时,crontab以为"还活着",不会重新拉起
  2. PID文件残留导致start命令误判进程仍在运行
  3. crond自身异常时整个守护机制失效
  4. 没有失败重试的退避策略(每次都是固定5分钟)
  5. 没有告警通知机制(拉不起来也不会告诉你)

这些问题归结到一点:crontab是个"定时触发器",不是"服务管理器"。它没有状态感知、没有重启策略、没有依赖管理、没有日志聚合。这些能力,systemd都有。

所以结论很明确:生产环境的lac_agent,应该用systemd来托管。

lac_agentd.sh:官方提供的systemd注册脚本

官方其实已经想到了这一点。在安装完LAC客户端之后,bin目录下会有一个 lac_agentd.sh 脚本,专门用来把lac_agent注册成systemd服务。

先看看这个脚本怎么用:

bash 复制代码
# 查看帮助
$ /home/kingbase/Server/bin/lac_agentd.sh --help

# 注册为systemd服务(需要root权限)
$ su -
# lac_agentd.sh

# 注册完之后,服务名是lac_agentd
$ systemctl status lac_agentd
$ systemctl start lac_agentd
$ systemctl stop lac_agentd
$ systemctl restart lac_agentd

注意两个要点:

第一,注册systemd服务需要root权限 。这个在官方文档里也写了。原因是systemd的unit文件要写到 /etc/systemd/system/ 目录下,普通用户没有这个权限。

第二,注册之前要确保lac_agent.conf配置正确,因为systemd服务启动时会读取这个配置文件。如果配置不对,服务启动了也会马上挂掉。

那我们先看看 lac_agentd.sh 到底做了什么。打开这个脚本看看:

bash 复制代码
cat /home/kingbase/Server/bin/lac_agentd.sh

不同版本内容可能不一样,但核心逻辑就是生成一个systemd unit文件,写到 /etc/systemd/system/lac_agentd.service,然后执行 systemctl daemon-reload

systemd unit文件详解

如果官方脚本生成的unit文件不能满足你的需求(比如你想自定义重启策略、资源限制等),你可以手动编辑这个unit文件。

这里面有几个关键的点我要展开说一下。

Type=simple vs Type=forking

lac_agent start 命令会把进程fork到后台然后退出,这种模式对应 Type=forking。但是这种模式有个问题------systemd只能跟踪主进程的PID,如果lac_agent自己又fork了子进程,systemd就不太容易管住了。

我推荐的做法是用 Type=simple,ExecStart直接执行 lac_agent(不带start参数),让lac_agent作为前台进程运行。这样systemd能完全掌控它的生命周期:进程退出了systemd立刻知道,进程僵死了systemd也能通过watchdog检测到。

但这里有个前提:lac_agent 不加start参数时的行为,根据文档是"手动执行一次授权检查",执行完就退出了。这就尴尬了------我们需要的是常驻进程。

所以下面这个方式更稳妥:

ini 复制代码
# 用start参数 + Type=forking + PIDFile
Type=forking
ExecStart=/home/kingbase/Server/bin/lac_agent start -n
PIDFile=/home/kingbase/Server/var/run/lac_agent.pid

方案A比较简单,但PIDFile的路径你得确认对,不同版本可能不一样。方案B需要自己写一个wrapper脚本,但控制力更强。

从crontab迁移到systemd的完整步骤

这是很多DBA问我的问题------我现在跑的crontab守护,怎么安全地切到systemd?

关键是顺序,别搞错了,不然可能出现两套守护同时拉起的混乱局面。

bash 复制代码
#!/bin/bash
# 从crontab迁移lac_agent到systemd的完整流程
# 以kingbase用户操作,部分步骤需要root

KB_HOME="/home/kingbase/Server"
LAC_BIN="${KB_HOME}/bin"

echo "=== Step 1: 停止当前的lac_agent进程和crontab守护 ==="
# 使用stop命令,会同时停止进程并清除crontab
${LAC_BIN}/lac_agent stop

# 确认crontab已经清除
echo "当前crontab内容:"
crontab -l 2>/dev/null || echo "(空)"

# 确认lac_agent进程已经停止
if pgrep -f "${LAC_BIN}/lac_agent" > /dev/null; then
    echo "[WARN] lac_agent进程仍在运行,手动停止"
    pkill -9 -f "${LAC_BIN}/lac_agent"
    sleep 2
fi

echo ""
echo "=== Step 2: 切换到root,注册systemd服务 ==="
echo "请执行: su - 然后运行 lac_agentd.sh"
echo "或者手动创建unit文件(参考上面的配置)"

# 下面是root执行的部分
# su - <<'ROOT_SCRIPT'
# /home/kingbase/Server/bin/lac_agentd.sh
# systemctl daemon-reload
# systemctl enable lac_agentd
# systemctl start lac_agentd
# ROOT_SCRIPT

echo ""
echo "=== Step 3: 验证systemd服务状态 ==="
# systemctl status lac_agentd
# journalctl -u lac_agentd -f  # 实时查看日志

echo ""
echo "=== Step 4: 清理旧的crontab残留(如果有)==="
# crontab -l | grep -v lac_agent | crontab -

echo ""
echo "=== Step 5: 确认授权状态正常 ==="
# ${LAC_BIN}/lac_agent status
# ksql -USYSTEM -dTEST -c "SELECT * FROM V\$LICENSE;"

注意Step 1里面用了 lac_agent stop(不带-n),这样会同时清除crontab条目。如果你用了 lac_agent stop -n,crontab还会保留,后续需要手动清理。

systemd方式下的日志管理

用systemd托管之后,lac_agent的日志就自动接入journalctl了。这比看crontab的输出日志方便太多。

bash 复制代码
# 查看lac_agentd服务的实时日志
journalctl -u lac_agentd -f

# 查看最近1小时的日志
journalctl -u lac_agentd --since "1 hour ago"

# 查看今天的日志
journalctl -u lac_agentd --since today

# 查看指定时间段的日志
journalctl -u lac_agentd --since "2026-06-20 03:00" --until "2026-06-20 04:00"

# 查看所有lac_agent相关的日志(包括手动执行的)
journalctl SYSLOG_IDENTIFIER=lac_agent --since today

但有个问题需要注意:journalctl的日志是二进制格式,而且默认有大小限制(通常几百MB),太老的日志会被自动清理。如果你需要长期保留lac_agent的日志(比如为了审计),最好还是配置log_file,让lac_agent自己写日志文件:

bash 复制代码
# 在lac_agent.conf中配置
log_file = /home/kingbase/lac/lac_agent.log
log_level = INFO

然后配合logrotate做日志轮转:

bash 复制代码
# /etc/logrotate.d/lac_agent
/home/kingbase/lac/lac_agent.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}

这样systemd journal + lac_agent自己的日志文件,双保险。

进阶:搭建完整的自愈体系

systemd解决了"进程挂了自动重启"这个问题,但一个完整的自愈体系还需要:

  1. 健康检查------进程在不代表工作正常
  2. 告警通知------恢复了也要知道发生了什么
  3. 审计日志------事后复盘需要数据支撑
  4. 升级机制------自动恢复失败时要升级到人工

先说健康检查。systemd有个 ExecStartPost 和 watchdog 机制,但lac_agent本身如果不支持sd_notify协议,systemd就很难知道它是不是真的在正常工作。

我的做法是写一个独立的健康检查脚本,用systemd timer或者单独的crontab来定期执行:

bash 复制代码
#!/bin/bash
# /home/kingbase/lac/lac_healthcheck.sh
# lac_agent深度健康检查脚本

KB_HOME="/home/kingbase/Server"
LAC_BIN="${KB_HOME}/bin"
HEALTH_LOG="/home/kingbase/lac/healthcheck.log"
ALERT_WEBHOOK=""  # 填你的告警webhook地址

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$HEALTH_LOG"
}

send_alert() {
    local level=$1
    local msg=$2
    log "[ALERT-${level}] ${msg}"
    if [ -n "$ALERT_WEBHOOK" ]; then
        curl -s -X POST "$ALERT_WEBHOOK" \
            -H 'Content-Type: application/json' \
            -d "{\"level\":\"${level}\",\"msg\":\"${msg}\",\"host\":\"$(hostname)\"}" \
            > /dev/null 2>&1
    fi
}

check_health() {
    # 1. 检查systemd服务状态
    local SVC_STATUS=$(systemctl is-active lac_agentd 2>/dev/null)
    if [ "$SVC_STATUS" != "active" ]; then
        send_alert "CRITICAL" "lac_agentd服务状态异常: ${SVC_STATUS}"
        # 尝试重启
        systemctl restart lac_agentd
        sleep 5
        SVC_STATUS=$(systemctl is-active lac_agentd 2>/dev/null)
        if [ "$SVC_STATUS" != "active" ]; then
            send_alert "CRITICAL" "lac_agentd重启失败,需人工介入"
            return 1
        else
            send_alert "INFO" "lac_agentd重启成功"
        fi
    fi
    
    # 2. 检查lac_agent status命令的响应
    local AGENT_STATUS=$(${LAC_BIN}/lac_agent status 2>&1)
    if echo "$AGENT_STATUS" | grep -qi "not responding\|error\|failed"; then
        send_alert "WARNING" "lac_agent状态异常: ${AGENT_STATUS}"
        systemctl restart lac_agentd
        return 1
    fi
    
    # 3. 检查license.dat文件的时效性
    local LIC_FILE=$(find ${KB_HOME} -name "license.dat" -type f 2>/dev/null | head -1)
    if [ -n "$LIC_FILE" ] && [ -f "$LIC_FILE" ]; then
        local LIC_AGE=$(( ( $(date +%s) - $(stat -c %Y "$LIC_FILE") ) / 3600 ))
        if [ $LIC_AGE -gt 168 ]; then  # 超过7天没更新
            send_alert "WARNING" "license.dat已${LIC_AGE}小时未更新,可能授权同步异常"
        fi
    fi
    
    # 4. 检查lac_agent日志中的错误
    local LAC_LOG="${KB_HOME}/share/lac_agent.conf"
    # 从配置中获取实际日志路径(简化处理,直接检查常见位置)
    local LOG_PATH="/home/kingbase/lac/lac_agent.log"
    if [ -f "$LOG_PATH" ]; then
        local ERROR_COUNT=$(grep -c "ERROR\|CRIT\|EMERG\|ALERT" "$LOG_PATH" 2>/dev/null || echo 0)
        local RECENT_ERRORS=$(tail -100 "$LOG_PATH" | grep -c "ERROR\|CRIT" 2>/dev/null || echo 0)
        if [ "$RECENT_ERRORS" -gt 5 ]; then
            send_alert "WARNING" "lac_agent日志中最近发现${RECENT_ERRORS}条错误"
        fi
    fi
    
    log "[OK] 健康检查通过"
    return 0
}

check_health

然后用systemd timer来定期执行:

ini 复制代码
# /etc/systemd/system/lac-healthcheck.timer
[Unit]
Description=LAC Agent Health Check Timer

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
AccuracySec=30s

[Install]
WantedBy=timers.target
ini 复制代码
# /etc/systemd/system/lac-healthcheck.service
[Unit]
Description=LAC Agent Health Check

[Service]
Type=oneshot
User=kingbase
ExecStart=/home/kingbase/lac/lac_healthcheck.sh
bash 复制代码
systemctl enable lac-healthcheck.timer
systemctl start lac-healthcheck.timer

这样每5分钟做一次深度健康检查,比单纯靠systemd的Restart机制要可靠得多。

与外部监控系统的集成

如果你用Zabbix/Prometheus做监控,可以把lac_agent的状态做成监控指标。

Zabbix方式,写一个自定义监控项:

bash 复制代码
# /etc/zabbix/scripts/check_lac_agent.sh
#!/bin/bash
KB_HOME="/home/kingbase/Server"
STATUS=$(${KB_HOME}/bin/lac_agent status 2>&1)
if echo "$STATUS" | grep -qi "running\|active\|ok"; then
    echo 1
else
    echo 0
fi

然后在Zabbix Agent配置里加:

复制代码
UserParameter=lac.agent.status,bash /etc/zabbix/scripts/check_lac_agent.sh

Prometheus方式,可以写一个简单的exporter脚本,或者用textfile collector:

bash 复制代码
#!/bin/bash
# /opt/prometheus/lac_agent_metrics.sh
KB_HOME="/home/kingbase/Server"
METRICS_FILE="/var/lib/node_exporter/textfile/lac_agent.prom"

STATUS=$(${KB_HOME}/bin/lac_agent status 2>&1)
if echo "$STATUS" | grep -qi "running\|active\|ok"; then
    VALUE=1
else
    VALUE=0
fi

cat > "$METRICS_FILE" <<EOF
# HELP lac_agent_running Whether lac_agent is running (1=running, 0=not running)
# TYPE lac_agent_running gauge
lac_agent_running ${VALUE}
EOF

这样你就能在监控大盘上看到lac_agent的运行状态了,配合告警规则,能做到比crontab方式更及时的故障发现。

完整架构总结

把上面说的东西串起来,一套完整的lac_agent自愈体系是这样的:

复制代码
┌──────────────────────────────────────────────────────┐
│                  第一层:systemd托管                    │
│  lac_agentd.service - Type=simple/forking            │
│  Restart=on-failure, RestartSec=5                    │
│  StartLimitBurst=5, StartLimitIntervalSec=60         │
│  → 负责进程崩溃后的快速重启                            │
├──────────────────────────────────────────────────────┤
│              第二层:systemd timer健康检查              │
│  lac-healthcheck.timer - 每5分钟                      │
│  → 深度检查:进程状态、日志错误、license时效             │
│  → 发现问题自动重启服务                                │
├──────────────────────────────────────────────────────┤
│               第三层:告警通知                          │
│  健康检查脚本 → webhook → 钉钉/企微/邮件               │
│  → 恢复事件通知、失败升级通知                           │
├──────────────────────────────────────────────────────┤
│               第四层:外部监控                          │
│  Zabbix/Prometheus → 指标采集 → 告警规则               │
│  → 独立于lac_agent自身的监控通道                       │
└──────────────────────────────────────────────────────┘

有了这四层,基本上lac_agent不管遇到什么问题------进程崩溃、僵死、配置错误、网络中断------都能在一定时间内自动恢复或者至少把告警送到运维手上。

一些实践经验

最后分享几个我这一年多搞下来觉得有用的小经验:

1. lac_agent.conf中的enable_auto_refresh参数

这个参数默认是1,意思是授权失效后lac_agent会自动向LAC服务端重新申请。听起来很好,但在某些场景下它可能是个问题------如果LAC服务端的授权池满了,或者你的激活文件有问题,lac_agent就会不停地去申请,每次失败都写日志,搞不好还会触发服务端的限流。

在排查问题的时候,我会临时把这个参数设为0,避免lac_agent"自作主张"地反复申请授权:

ini 复制代码
enable_auto_refresh = 0

2. 关于local_ip在容器环境下的问题

这个留到后面容器化的文章里详细说,但这里提一嘴:安装脚本自动获取的local_ip用的是默认路由的网卡IP,在多网卡环境或者容器环境里可能拿到的不是你想要的IP。建议在lac_agent.conf里明确指定:

ini 复制代码
local_ip = 10.10.12.253

3. 定期检查LAC服务端的授权池状态

不要只盯着客户端,服务端那边的授权池也可能出问题。用LAC管理工具定期检查:

bash 复制代码
# 查看LAC服务端状态
lac_admin status

# 查看已分配的授权列表
lac_admin list

# 查看某个客户端的授权详情
lac_admin show -ip 10.10.12.253

4. 备份配置文件

lac_agent.conf一定要做备份。我有一次升级LAC客户端的时候用了 -f 参数强制覆盖安装,结果配置文件被覆盖了(虽然会备份成lac_agent.conf.timestamp,但当时手忙脚乱没注意到)。后来花了半小时才把配置恢复回来。

bash 复制代码
# 每次修改配置前先备份
cp ${KB_HOME}/share/lac_agent.conf ${KB_HOME}/share/lac_agent.conf.bak.$(date +%Y%m%d%H%M%S)

说到这个方向,前两天看到金仓社区在办"2026智能运维工具开发大赛"( https://bbs.kingbase.com.cn/forumDetail?articleId=2394013b19f3ef84a43edb994692b88ehttps://bbs.kingbase.com.cn/forumDetail?articleId=6152608d769b472397ccfbd29879c0bd ),我上面写的这些脚本其实已经有点运维工具的雏形了------健康检查、自动恢复、告警通知、监控集成,再包装一下没准能交个参赛作品上去。当然这不是重点,重点是这个方向确实值得投入------把踩过的坑沉淀成工具,让其他人少踩一遍。

最后

两篇文章写下来,从crontab的坑到systemd的托管,再到完整的自愈体系,基本把我这一年多在LAC客户端运维上积累的经验都倒出来了。

说真的,lac_agent这个东西说大不大说小不小,平时不显山不露水,但它一挂你就知道厉害了------数据库直接变只读,业务全停。所以把它的守护机制做扎实,绝对是值得花时间的。

别等到凌晨三点被叫醒才想起来搞这些。

相关推荐
KaMeidebaby7 小时前
卡梅德生物技术快报|蛋白 N 端测序在重组贻贝融合蛋白表征中的应用,解决原核表达序列偏移工艺难题
前端·人工智能·物联网·算法·百度
kyriewen8 小时前
我筛了 1400 个 Claude Code Skills,留下 5 个天天在用的
前端·ai编程·claude
JNX_SEMI9 小时前
AT2401C 2.4GHz 全集成射频前端单芯片技术解析
前端·单片机·嵌入式硬件·物联网·硬件工程
anOnion9 小时前
Agentic 前端开发之 实时显示 AI Agent 终端输出
前端·javascript·人工智能
随风一样自由9 小时前
【前端领域】2026最新前端领域全梳理(框架/工具/AI/跨端/底层标准/就业趋势)
前端·人工智能·前端框架
这是个栗子9 小时前
【前端性能优化】优化数据加载:用 Promise.all 从串行到并行
前端·javascript·性能优化·异步编程·前端优化·promise.all
fei_sun10 小时前
黑洞路由(Null Route/空接口路由)
服务器·前端·javascript
大爱一家盟10 小时前
告别卡点BGM同质化 2026原创卡点音乐素材下载网站 TOP5 推荐
大数据·前端·人工智能
彦为君10 小时前
算法思维与经典智力题
java·前端·redis·算法
aa小小11 小时前
localhost 访问异常排查笔记
前端