文章目录为什么crontab不够用lac_agentd.sh官方提供的systemd注册脚本systemd unit文件详解Typesimple vs Typeforking从crontab迁移到systemd的完整步骤systemd方式下的日志管理进阶搭建完整的自愈体系与外部监控系统的集成完整架构总结一些实践经验最后兼容是对前人努力的尊重是确保业务平稳过渡的基石然而这仅仅是故事的起点上篇说了crontab守护lac_agent的那些坑说实话写完上篇的时候我自己都有点后怕——在那之前我一直觉得crontab每5分钟拉起一次已经够用了直到凌晨三点被叫醒才知道这套机制有多脆弱。这篇文章接着聊怎么从crontab迁移到systemd托管以及怎么搭建一套真正靠谱的健康检查和自动恢复体系。为什么crontab不够用先简单回顾一下上篇提到的crontab的几个硬伤进程僵死Z状态/D状态时crontab以为还活着不会重新拉起PID文件残留导致start命令误判进程仍在运行crond自身异常时整个守护机制失效没有失败重试的退避策略每次都是固定5分钟没有告警通知机制拉不起来也不会告诉你这些问题归结到一点crontab是个定时触发器不是服务管理器。它没有状态感知、没有重启策略、没有依赖管理、没有日志聚合。这些能力systemd都有。所以结论很明确生产环境的lac_agent应该用systemd来托管。lac_agentd.sh官方提供的systemd注册脚本官方其实已经想到了这一点。在安装完LAC客户端之后bin目录下会有一个lac_agentd.sh脚本专门用来把lac_agent注册成systemd服务。先看看这个脚本怎么用# 查看帮助$ /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到底做了什么。打开这个脚本看看cat/home/kingbase/Server/bin/lac_agentd.sh不同版本内容可能不一样但核心逻辑就是生成一个systemd unit文件写到/etc/systemd/system/lac_agentd.service然后执行systemctl daemon-reload。systemd unit文件详解如果官方脚本生成的unit文件不能满足你的需求比如你想自定义重启策略、资源限制等你可以手动编辑这个unit文件。这里面有几个关键的点我要展开说一下。Typesimple vs Typeforkinglac_agent start命令会把进程fork到后台然后退出这种模式对应Typeforking。但是这种模式有个问题——systemd只能跟踪主进程的PID如果lac_agent自己又fork了子进程systemd就不太容易管住了。我推荐的做法是用TypesimpleExecStart直接执行lac_agent不带start参数让lac_agent作为前台进程运行。这样systemd能完全掌控它的生命周期进程退出了systemd立刻知道进程僵死了systemd也能通过watchdog检测到。但这里有个前提lac_agent不加start参数时的行为根据文档是手动执行一次授权检查执行完就退出了。这就尴尬了——我们需要的是常驻进程。所以下面这个方式更稳妥# 用start参数 Typeforking PIDFile Typeforking 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关键是顺序别搞错了不然可能出现两套守护同时拉起的混乱局面。#!/bin/bash# 从crontab迁移lac_agent到systemd的完整流程# 以kingbase用户操作部分步骤需要rootKB_HOME/home/kingbase/ServerLAC_BIN${KB_HOME}/binecho Step 1: 停止当前的lac_agent进程和crontab守护 # 使用stop命令会同时停止进程并清除crontab${LAC_BIN}/lac_agent stop# 确认crontab已经清除echo当前crontab内容crontab-l2/dev/null||echo(空)# 确认lac_agent进程已经停止ifpgrep-f${LAC_BIN}/lac_agent/dev/null;thenecho[WARN] lac_agent进程仍在运行手动停止pkill-9-f${LAC_BIN}/lac_agentsleep2fiechoecho Step 2: 切换到root注册systemd服务 echo请执行: su - 然后运行 lac_agentd.shecho或者手动创建unit文件参考上面的配置# 下面是root执行的部分# su - ROOT_SCRIPT# /home/kingbase/Server/bin/lac_agentd.sh# systemctl daemon-reload# systemctl enable lac_agentd# systemctl start lac_agentd# ROOT_SCRIPTechoecho Step 3: 验证systemd服务状态 # systemctl status lac_agentd# journalctl -u lac_agentd -f # 实时查看日志echoecho Step 4: 清理旧的crontab残留如果有# crontab -l | grep -v lac_agent | crontab -echoecho 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 -ncrontab还会保留后续需要手动清理。systemd方式下的日志管理用systemd托管之后lac_agent的日志就自动接入journalctl了。这比看crontab的输出日志方便太多。# 查看lac_agentd服务的实时日志journalctl-ulac_agentd-f# 查看最近1小时的日志journalctl-ulac_agentd--since1 hour ago# 查看今天的日志journalctl-ulac_agentd--sincetoday# 查看指定时间段的日志journalctl-ulac_agentd--since2026-06-20 03:00--until2026-06-20 04:00# 查看所有lac_agent相关的日志包括手动执行的journalctlSYSLOG_IDENTIFIERlac_agent--sincetoday但有个问题需要注意journalctl的日志是二进制格式而且默认有大小限制通常几百MB太老的日志会被自动清理。如果你需要长期保留lac_agent的日志比如为了审计最好还是配置log_file让lac_agent自己写日志文件# 在lac_agent.conf中配置log_file/home/kingbase/lac/lac_agent.log log_levelINFO然后配合logrotate做日志轮转# /etc/logrotate.d/lac_agent/home/kingbase/lac/lac_agent.log{daily rotate30compress delaycompress missingok notifempty copytruncate}这样systemd journal lac_agent自己的日志文件双保险。进阶搭建完整的自愈体系systemd解决了进程挂了自动重启这个问题但一个完整的自愈体系还需要健康检查——进程在不代表工作正常告警通知——恢复了也要知道发生了什么审计日志——事后复盘需要数据支撑升级机制——自动恢复失败时要升级到人工先说健康检查。systemd有个ExecStartPost和 watchdog 机制但lac_agent本身如果不支持sd_notify协议systemd就很难知道它是不是真的在正常工作。我的做法是写一个独立的健康检查脚本用systemd timer或者单独的crontab来定期执行#!/bin/bash# /home/kingbase/lac/lac_healthcheck.sh# lac_agent深度健康检查脚本KB_HOME/home/kingbase/ServerLAC_BIN${KB_HOME}/binHEALTH_LOG/home/kingbase/lac/healthcheck.logALERT_WEBHOOK# 填你的告警webhook地址log(){echo$(date%Y-%m-%d %H:%M:%S)$1$HEALTH_LOG}send_alert(){locallevel$1localmsg$2log[ALERT-${level}]${msg}if[-n$ALERT_WEBHOOK];thencurl-s-XPOST$ALERT_WEBHOOK\-HContent-Type: application/json\-d{\level\:\${level}\,\msg\:\${msg}\,\host\:\$(hostname)\}\/dev/null21fi}check_health(){# 1. 检查systemd服务状态localSVC_STATUS$(systemctl is-active lac_agentd2/dev/null)if[$SVC_STATUS!active];thensend_alertCRITICALlac_agentd服务状态异常:${SVC_STATUS}# 尝试重启systemctl restart lac_agentdsleep5SVC_STATUS$(systemctl is-active lac_agentd2/dev/null)if[$SVC_STATUS!active];thensend_alertCRITICALlac_agentd重启失败需人工介入return1elsesend_alertINFOlac_agentd重启成功fifi# 2. 检查lac_agent status命令的响应localAGENT_STATUS$(${LAC_BIN}/lac_agent status21)ifecho$AGENT_STATUS|grep-qinot responding\|error\|failed;thensend_alertWARNINGlac_agent状态异常:${AGENT_STATUS}systemctl restart lac_agentdreturn1fi# 3. 检查license.dat文件的时效性localLIC_FILE$(find${KB_HOME}-namelicense.dat-typef2/dev/null|head-1)if[-n$LIC_FILE][-f$LIC_FILE];thenlocalLIC_AGE$((($(date%s)-$(stat-c%Y $LIC_FILE))/3600))if[$LIC_AGE-gt168];then# 超过7天没更新send_alertWARNINGlicense.dat已${LIC_AGE}小时未更新可能授权同步异常fifi# 4. 检查lac_agent日志中的错误localLAC_LOG${KB_HOME}/share/lac_agent.conf# 从配置中获取实际日志路径简化处理直接检查常见位置localLOG_PATH/home/kingbase/lac/lac_agent.logif[-f$LOG_PATH];thenlocalERROR_COUNT$(grep-cERROR\|CRIT\|EMERG\|ALERT$LOG_PATH2/dev/null||echo0)localRECENT_ERRORS$(tail-100$LOG_PATH|grep-cERROR\|CRIT2/dev/null||echo0)if[$RECENT_ERRORS-gt5];thensend_alertWARNINGlac_agent日志中最近发现${RECENT_ERRORS}条错误fifilog[OK] 健康检查通过return0}check_health然后用systemd timer来定期执行# /etc/systemd/system/lac-healthcheck.timer [Unit] DescriptionLAC Agent Health Check Timer [Timer] OnBootSec2min OnUnitActiveSec5min AccuracySec30s [Install] WantedBytimers.target# /etc/systemd/system/lac-healthcheck.service [Unit] DescriptionLAC Agent Health Check [Service] Typeoneshot Userkingbase ExecStart/home/kingbase/lac/lac_healthcheck.shsystemctlenablelac-healthcheck.timer systemctl start lac-healthcheck.timer这样每5分钟做一次深度健康检查比单纯靠systemd的Restart机制要可靠得多。与外部监控系统的集成如果你用Zabbix/Prometheus做监控可以把lac_agent的状态做成监控指标。Zabbix方式写一个自定义监控项# /etc/zabbix/scripts/check_lac_agent.sh#!/bin/bashKB_HOME/home/kingbase/ServerSTATUS$(${KB_HOME}/bin/lac_agent status21)ifecho$STATUS|grep-qirunning\|active\|ok;thenecho1elseecho0fi然后在Zabbix Agent配置里加UserParameterlac.agent.status,bash /etc/zabbix/scripts/check_lac_agent.shPrometheus方式可以写一个简单的exporter脚本或者用textfile collector#!/bin/bash# /opt/prometheus/lac_agent_metrics.shKB_HOME/home/kingbase/ServerMETRICS_FILE/var/lib/node_exporter/textfile/lac_agent.promSTATUS$(${KB_HOME}/bin/lac_agent status21)ifecho$STATUS|grep-qirunning\|active\|ok;thenVALUE1elseVALUE0ficat$METRICS_FILEEOF # HELP lac_agent_running Whether lac_agent is running (1running, 0not running) # TYPE lac_agent_running gauge lac_agent_running${VALUE}EOF这样你就能在监控大盘上看到lac_agent的运行状态了配合告警规则能做到比crontab方式更及时的故障发现。完整架构总结把上面说的东西串起来一套完整的lac_agent自愈体系是这样的┌──────────────────────────────────────────────────────┐ │ 第一层systemd托管 │ │ lac_agentd.service - Typesimple/forking │ │ Restarton-failure, RestartSec5 │ │ StartLimitBurst5, StartLimitIntervalSec60 │ │ → 负责进程崩溃后的快速重启 │ ├──────────────────────────────────────────────────────┤ │ 第二层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自作主张地反复申请授权enable_auto_refresh 02. 关于local_ip在容器环境下的问题这个留到后面容器化的文章里详细说但这里提一嘴安装脚本自动获取的local_ip用的是默认路由的网卡IP在多网卡环境或者容器环境里可能拿到的不是你想要的IP。建议在lac_agent.conf里明确指定local_ip 10.10.12.2533. 定期检查LAC服务端的授权池状态不要只盯着客户端服务端那边的授权池也可能出问题。用LAC管理工具定期检查# 查看LAC服务端状态lac_admin status# 查看已分配的授权列表lac_admin list# 查看某个客户端的授权详情lac_admin show-ip10.10.12.2534. 备份配置文件lac_agent.conf一定要做备份。我有一次升级LAC客户端的时候用了-f参数强制覆盖安装结果配置文件被覆盖了虽然会备份成lac_agent.conf.timestamp但当时手忙脚乱没注意到。后来花了半小时才把配置恢复回来。# 每次修改配置前先备份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?articleId2394013b19f3ef84a43edb994692b88e 和 https://bbs.kingbase.com.cn/forumDetail?articleId6152608d769b472397ccfbd29879c0bd 我上面写的这些脚本其实已经有点运维工具的雏形了——健康检查、自动恢复、告警通知、监控集成再包装一下没准能交个参赛作品上去。当然这不是重点重点是这个方向确实值得投入——把踩过的坑沉淀成工具让其他人少踩一遍。最后两篇文章写下来从crontab的坑到systemd的托管再到完整的自愈体系基本把我这一年多在LAC客户端运维上积累的经验都倒出来了。说真的lac_agent这个东西说大不大说小不小平时不显山不露水但它一挂你就知道厉害了——数据库直接变只读业务全停。所以把它的守护机制做扎实绝对是值得花时间的。别等到凌晨三点被叫醒才想起来搞这些。