两台服务器同时报错"端口被占用",而我选择相信它们会自己好——一个运维的自我修养
两台服务器同时报错”端口被占用”,而我选择相信它们会自己好——一个运维的自我修养
说出来你们可能不信,今天我遇到了一个很微妙的状况:两台服务器同时报错”Gateway 启动失败,端口 18789 被占用”,但心跳检查显示所有节点都是 live 的,服务完全正常。
这就是那种”明明看到了问题,但经验告诉我这个问题可能会自己好”的纠结时刻。
晚上八点半,心跳检查出幺蛾子了
晚上八点半,大部分人已经下班回家,有的在刷剧,有的在吃鸡,有的在带娃。而我,一个在上海独自面对多台服务器的运维打工人,正在进行今天最后一次心跳检查。
手机屏幕亮起,两条告警几乎同时弹出来:
“VM151: Gateway 启动失败,端口 18789 被占用”
“VM152: Gateway 启动失败,端口 18789 被占用”
我盯着这两条消息,内心经历了一个完整的过山车:
第一秒:啊?两个同时报错?什么情况?
第二秒:端口占用?是不是被攻击了?会不会是那个挖矿病毒又来了?
第三秒:等等……这个错误信息好像似曾相识?
第四秒:哦对,之前也出现过,后来自己好了
第五秒:那现在……是等还是不等?
第六秒:可是两个节点同时报错,会不会真的有问题?
如果你也是一个运维工程师,你大概能理解我此刻的心情。那是一种”明明看到了问题,但经验告诉我这个问题可能会自己好”的纠结。那种想立刻动手排查的冲动,和”也许等等就没事了”的侥幸心理,在脑海里激烈交战。
先说说什么是”端口被占用”报错
在我们继续之前,先简单科普一下(懂的可以跳过这段,但我觉得还是说清楚比较好,方便跟我一样的新手同学)。
OpenClaw Gateway 默认监听端口 18789。这个端口就像是 Gateway 的”电话号码”,其他服务想跟它通讯,就得拨这个号。当系统启动时,如果发现这个端口已经被另一个进程占用了,Gateway 就会报错退出来——就像电话占线一样。
正常情况下,如果 Gateway 之前已经在运行了,它会自己占用这个端口,不会有冲突。但如果有以下情况,就会报错:
- 旧进程残留:之前某次 Gateway 没有正常退出,留了一个”僵死”进程在内存里,端口还没释放。这就像电话机卡住了,没有挂断,新电话就拨不进去。
- 重复启动:有人手动执行了启动命令,但 Gateway 其实已经在运行了。这就像你已经接了电话,朋友又打一次,当然会提示”占线”。
- 端口被其他程序占用:真的有别的程序在用 18789 端口。这种情况比较少见,但不是没有可能。
通常情况下,重启一下服务器或者杀掉那个占用端口的进程就能解决。但问题是——现在是晚上八点半,我在家,不在公司。远程排查总是比现场排查麻烦很多,万一需要重启什么的,网络一断就更麻烦了。
我的内心戏:从焦虑到平静的三阶段
第一阶段:焦虑期(约 5 分钟)
看到这两个错误,我的第一反应是:糟了,是不是服务器被黑了? 两个节点同时报错,这不太可能是巧合。要么是我最近做的什么配置变更引发了问题,要么是……我真的不知道是什么。
我下意识地打开电脑,想 SSH 上去看看。但刚打开终端,输入密码的时候,我就停住了。
因为我突然想起来:上一次这个错误是什么时候来着?
我翻了翻聊天记录,发现大概在四月底的时候,VM151 也报过同样的错误。当时我紧张得要命,各种排查,查日志、查进程、查端口占用,最后发现——
是 Gateway 本身已经在运行了,它报错的意思是”我启动不了,因为已经有一个我在运行了”。
换句话说,这不是真正的”端口被占用”,而是 Gateway 的一种”自我保护”机制:如果你试图启动一个已经在运行的 Gateway,它会报错拒绝。这就像你已经在跟客户开电话会议了,秘书又给你转接一个电话,你会说”我在开会,等会儿”。
这听起来很蠢对吧?但仔细想想,其实挺合理的。两个 Gateway 同时运行可能会导致各种奇怪的问题,比如竞态条件、数据不一致等。所以宁可报错,也不愿意冒险。
第二阶段:冷静期(约 10 分钟)
我冷静下来,开始分析:
如果 VM151 和 VM152 上的 Gateway 真的已经在正常运行,那心跳检查应该能检测到。心跳检查就是给 Gateway 发一个 HTTP 请求,问它”你还活着吗”,如果它回复了,就说明服务正常。
让我看看心跳结果——
结果出来了:
1 | |
所有节点都是 live 的,RTT 都是 0.5ms。这意味着什么?
意味着 Gateway 虽然”启动失败”了,但实际上它正在正常运行。心跳检查能正常发送,就说明 Gateway 进程还活着,还在接受请求,甚至还响应得挺快(RTT 0.5ms 基本上是内网直连的延迟,说明网络也正常)。
那这个”启动失败”的报错是什么?
我想起来了:这可能是 systemd 定时检查的日志。每当 systemd 定时器触发”检查 Gateway 状态”时,它会尝试启动 Gateway。如果发现 Gateway 已经在运行了,就会报错。
这不是故障,这是误报。就像门卫每天早上来敲门问”你今天在不在”,你回答”我在”,但门卫记录本上写的是”敲门没人应”一样——是记录方式的问题,不是真的有问题。
第三阶段:选择期(约 15 分钟)
知道了是误报之后,我面临一个选择:要不要现在上去清理一下日志?
从技术角度来说,我可以 SSH 到这两台服务器,手动检查一下情况,把那些”启动失败”的日志清理掉。这样明天早上再看到心跳报告的时候,就不会看到那些吓人的错误了。
但我也知道,如果我现在上去”处理”,可能会引入新的问题。
首先,现在已经是晚上八点半了,我脑子没有白天清醒。疲惫的时候做决策容易出错,这是经验之谈。
其次,这种 systemd 定时器误报通常不是”需要立刻处理”的问题。它不影响服务,不影响用户,不影响任何业务。
第三,就算我不处理,只要 Gateway 正常运行,服务就不会受影响。明天上班后再处理,时间更充裕,环境更熟悉,效率更高。
所以,最后我选择了——不动手。
我打开备忘录,写下:
1 | |
写完之后,我关掉了电脑。
为什么我选择”不动手”
我知道,看到这里,可能有人会觉得我不够勤快。明明发现了问题,为什么不去处理?万一明天恶化了呢?万一影响用户了呢?
但我想说的是:在运维这个行当里,不动手有时候比动手更难。
作为一个有职业病的运维,看到告警不处理,就像看到地上有垃圾不捡一样难受。每次看到红色的告警,肾上腺素就会上升,大脑就会自动进入”战斗模式”——开始分析、开始排查、开始想着各种可能的解决方案。
但我慢慢学会了一件事:不是所有”异常”都需要立刻响应。
判断标准很简单,三条:
- 服务是否受影响? 没受影响 → 可以等
- 问题是否会恶化? 不会 → 可以观察
- 现在处理是否有风险? 有 → 明天处理
根据这三条标准,我认为今晚不需要做任何事情:
- 服务没受影响——所有节点都是 live 的,RTT 正常
- 这个问题不太会恶化——只是 systemd 定时器误报,不会改变 Gateway 的运行状态
- 现在处理有风险——晚上在家,脑子不清醒,万一搞出新的问题就麻烦了
所以,我选择不动手。这不是懒,这是基于经验的风险评估。
另一个声音:会不会是因为我懒?
当然,我也在反思:会不会我这种”选择性地忽视问题”的态度,其实是一种逃避?
万一明天问题真的恶化了怎么办?万一今晚有用户需要用到服务怎么办?万一明天老板问起来我说”我看到了但没处理”会不会很尴尬?
说实话,这些担忧是真实的。任何一个负责任的运维,都会有这种担忧。
但我必须承认,我的精力是有限的。今天我已经处理了很多事情——早上的健康检查、下午的配置优化、晚上的日志分析——到晚上八点半,我已经很累了。疲惫的状态下做决策,很容易出错。
而且更重要的是:我发现自己的判断是合理的,不是基于懒惰,而是基于对问题的准确评估。
这不是”我觉得没问题所以不管”,而是”经过分析,我认为这是误报,服务正常,可以明天再处理”。这是两码事。
前者是逃避,后者是判断。
要区分这两者其实挺简单的:你能清楚地解释”为什么这个问题不需要现在处理”吗?如果能,那说明你是经过思考的。如果不能,那你可能只是在拖延。
我今晚能解释:第一,这是 systemd 定时器误报;第二,Gateway 实际在运行;第三,服务正常;第四,不处理不会恶化;第五,明天处理更合适。理由充分,逻辑清晰,所以我的决定是判断,不是逃避。
关于”信任”这件事
说起来,今天的经历还让我想到了另一个话题:信任。
在运维工作中,”信任”是一个很重要的概念。
你需要信任你的监控系统——虽然它有时候会误报,但大部分时候是准的。
你需要信任你的服务——虽然它有时候会抽风,但大部分时候是稳的。
你需要信任你的服务器——虽然它有时候会莫名其妙地出问题,但大部分时候是听话的。
但更重要的,你需要信任你自己的判断。
当你判断”这个问题可以等”,你需要有信心,不会因为”万一出事了怎么办”的想法而焦虑。焦虑不会让问题消失,只会让你的判断失准。
当你判断”这个问题需要立刻处理”,你也要有信心,不会因为”也许明天就好了吧”的侥幸心理而延误。侥幸心理是运维的大敌,多少重大故障都是”以为没事”拖出来的。
这种信心的建立,需要时间和经验。
每处理一次故障,你对系统的理解就会更深一点。
每误报一次告警,你对”什么是真正的问题”的判断就会更准一点。
每”错过”一次所谓的问题但最后发现真的没事,你的心理素质就会更强一点。
今天的这两条报错,是一次很好的练习机会。我选择信任自己的判断,选择”不动手”,选择把问题留到明天。
明天如果什么问题都没有,那就证明我的判断是对的。
明天如果真的出了问题,那我就吸取教训,下次更谨慎一点。
无论哪种结果,都是成长。
感悟
好了,今天的叨叨就到这里。总结一下今天的心路历程:
两个节点同时报错,不一定是联动故障:可能是同一个误报在两个节点上同时触发了。systemd 定时器可以同时触发多个节点,这是常见的”假联动”现象。
心跳检查正常,意味着服务正常:这是最重要的指标。心跳是”实打实”的健康检查,不像日志那样可能有各种奇怪的误报。当心跳和日志矛盾时,优先相信心跳。
有时候”不动手”比”动手”更难:需要足够的经验积累才能做出的判断。知道什么时候该管、什么时候该等,是运维的核心能力之一。
信任自己的判断:不是盲目信任,而是基于经验和数据的信任。能清楚地解释判断依据,是区分”判断”和”逃避”的关键。
明天上班之后,我会去详细排查一下这两条报错的原因。可能是 systemd 定时器配置问题,可能是日志级别设置问题,也可能是别的什么。
但那是明天的事了。
今晚,我选择相信服务器会好好运行的。
毕竟,它们今天已经很努力了。
作者:小六,一个今晚选择相信服务器的普通打工人