Ejabberd集群跨节点文件上传失败(Invalid slot错误)技术求助
首先,先明确你遇到的核心错误日志:
2020-08-19 10:57:54.010 [warning] <0.1997.0>@mod_http_upload:process:563 Rejecting file ca427369-3812-4459-8162-ba4694f831fd.jpg from ::ffff:127.0.0.1 for 7049.xxxx.yyyyy.com: Invalid slot
在HAProxy负载的Ejabberd集群中出现这个问题,本质是mod_http_upload的slot验证机制和集群节点间的状态不同步导致的——单节点下没有跨节点路由的问题,所以运行正常。下面是具体的技术思路和解决方案:
核心原因分析
mod_http_upload的工作流程是:
- 客户端先请求生成一个上传slot(由某个Ejabberd节点生成并存储在本地)
- 客户端使用这个slot上传文件
如果HAProxy把第二步的上传请求路由到了不是生成slot的那个节点,目标节点没有这个slot的记录,就会返回"Invalid slot"错误——因为默认情况下slot信息只保存在生成它的节点本地,集群节点间不会自动同步这些临时数据。
具体解决方案
1. 配置HAProxy会话粘性(最快速的临时解决/验证方案)
让同一个客户端的slot生成请求和上传请求强制路由到同一个Ejabberd节点:
- 基于客户端IP的粘性:在HAProxy的backend配置中添加
stick-table type ip size 100k和stick on src,这样同一IP的请求会落到同一节点 - 基于JID的粘性:如果客户端请求中携带JID信息(比如在HTTP头或参数里),可以配置HAProxy基于JID的哈希值做粘性路由,确保同一用户的所有请求都到同一节点
示例HAProxy backend配置片段:
backend ejabberd_cluster balance roundrobin stick-table type ip size 100k expire 30m stick on src server node1 192.168.1.10:5443 check server node2 192.168.1.11:5443 check
2. 启用Ejabberd集群的slot分布式存储(长期集群化方案)
修改Ejabberd的mod_http_upload配置,让slot信息存储在集群共享的Mnesia数据库中,这样所有节点都能访问到slot数据:
- 确保所有Ejabberd节点已经组成Mnesia集群(Ejabberd默认会用Mnesia做集群存储,但需要确认节点间已连通)
- 在
ejabberd.yml中配置mod_http_upload的存储类型为mnesia,并开启分布式支持:
mod_http_upload: store_type: mnesia slot_duration: 3600 # 确保所有节点这个值一致 max_file_size: 10485760
修改后重启所有Ejabberd节点,确保Mnesia表在集群中同步。
3. 统一集群节点的mod_http_upload配置
确保所有Ejabberd节点的mod_http_upload配置完全一致,包括slot_duration、max_file_size等参数——如果节点间配置不同,可能导致slot的有效期或验证规则不一致,即使路由到同一节点也可能出错。
4. 调试与验证
- 在HAProxy中开启详细日志,记录每个请求的源IP、目标节点、请求路径(区分slot生成和上传请求),确认是否存在跨节点路由的情况
- 在Ejabberd节点上开启
mod_http_upload的debug日志,添加配置:
loglevel: debug log_rotate_size: 10485760 log_rotate_date: "" log_rotate_count: 10 log_rate_limit: 100
然后查看日志,跟踪slot的生成节点和验证节点,确认问题是否由跨节点路由导致。
内容的提问来源于stack exchange,提问作者Kamalakkannan Rajaram

