前两天朋友老李打电话过来吐槽,说公司服务器更新完系统之后,内部监控平台一直报网络状态异常,明明服务都正常运行,页面却显示一堆离线设备。查了一圈网络设备和防火墙,都没发现问题,最后发现锅竟然在数据库上。
更新后连接状态写不进去了
他们用的是一个基于 PostgreSQL 的状态记录系统,每分钟从各节点上报一次网络连通性,存到 status_log 表里。系统更新后,日志开始频繁出现 ERROR: insert or update on table \"status_log\" violates foreign key constraint 这类错误。
一查才明白,系统升级过程中自动重装了数据库驱动,而新驱动对 schema 的校验更严格了。原来代码里有个小毛病:插入时没指定 tenant_id 字段,默认传了 null,以前的老版本凑合能过,新驱动直接拦下。
INSERT INTO status_log (node_id, status, checked_at)
VALUES (1024, 'online', NOW());
补上默认租户就恢复正常:
INSERT INTO status_log (node_id, status, checked_at, tenant_id)
VALUES (1024, 'online', NOW(), 1);
时间戳类型兼容性也得留意
还有次我自己踩过坑,CentOS 升级到 8 之后,MySQL 的时区处理变了。原本写入的 timestamp 字段自动转成 UTC,结果前端展示全乱了八小时。后来发现是系统时区设置和 JDBC 连接串里的 useTimezone 没对上。
连接字符串得显式加上:
jdbc:mysql://localhost:3306/netmon?serverTimezone=Asia/Shanghai&useSSL=false
别忽略权限和序列问题
有些系统更新后会重置数据库用户权限。比如 Ubuntu 升级后,PostgreSQL 的 pg_hba.conf 被覆盖,原本允许 local 连接的配置没了,导致本地脚本无法写入状态数据。
另外,如果用自增主键,注意序列(sequence)是否被重置。曾见过更新后 sequence 回到 1,结果插入冲突,状态记录直接卡死。
查一下当前值:
SELECT currval('status_log_id_seq');
手动调整回来:
SELECT setval('status_log_id_seq', (SELECT MAX(id) FROM status_log));
系统更新不是一键搞定就完事的,尤其涉及数据库写入的网络监控类功能,稍微一点变动就可能让状态数据断档。改完系统别急着打卡下班,先跑一遍状态上报脚本,看看日志有没有异常,省得第二天被报警吵醒。