emqttd服务器频繁崩溃求助:附error.log报错片段
看起来你碰到了emqttd早期版本里一个典型的QoS 2消息处理bug,我来帮你拆解问题和对应的解决办法:
问题根源分析
从你提供的错误日志来看,崩溃是因为emqttd_session:acked/3函数在第736行处理PubRel消息时,找不到对应的状态匹配项。这属于MQTT QoS 2消息流程中的异常场景:Broker收到了客户端发送的{pubrel,76,{1524,127985,200713}}消息,但当前会话中没有记录对应的PubRec状态,导致Erlang的模式匹配失败,直接触发了gen_server进程崩溃。
具体解决步骤
优先升级emqttd版本
这个问题在emqttd v2.x及更早的版本里是已知的官方bug,后续的v3.0+稳定版本已经修复了Session模块的这个缺陷——新版本会对非法的PubRel消息做容错处理,直接丢弃异常消息而不是让进程崩溃。这是最彻底的解决方案,建议尽快升级到最新的稳定版。排查客户端的QoS 2实现
如果暂时无法升级服务器,先检查你的MQTT客户端代码:确保严格遵循QoS 2的四次握手流程(Publish → PubRec → PubRel → PubComp),每个步骤的消息ID(PacketId)必须一一对应,且不要在会话未正常建立时发送PubRel消息。很多时候这类问题是客户端侧的协议实现不规范导致的。临时修复代码(应急方案)
若必须使用当前版本,可以修改emqttd_session.erl中的acked/3函数,添加一个默认分支来捕获未匹配的消息:acked({pubrel, PacketId, _Reason}, State, SessPid) -> % 保留原有的匹配逻辑 ...; acked(UnknownMsg, State, _SessPid) -> % 新增默认分支,记录警告日志并维持会话状态 lager:warning("Received unmatched ack message: ~p", [UnknownMsg]), {ok, State}.修改后重新编译emqttd,这样遇到未匹配的消息时只会记录警告,不会导致进程崩溃。
开启调试日志定位问题客户端
在emqttd的配置文件中开启会话调试日志,添加以下配置:log.level = debug log.handlers.console.level = debug这样可以捕获崩溃前后的完整会话交互细节,帮你定位是哪个客户端发送了异常的PubRel消息,进而针对性修复客户端的问题。
内容的提问来源于stack exchange,提问作者David ten Hove

