socket.io-python-emitter 发送消息 socket.io-redis 无法收到的问题。

之前将服务迁移到 docker ,结果发现 socket.io-python-emitter 发送的消息全部发送不出去。经检查发现是 socket.io-redis 0.2.0 做了性能优化,与老版本不兼容了,无奈查源码自己打了个补丁(现已合并至主干)。

最开始是发现网站发起的推送延迟很厉害,而且推送 ping 日志显示丢包达到了80%以上。由于所有推送操作同时使用了极光推送及自建的 socket.io 推送。一开始没想到两套推送方案全部挂了,以为是测试设备出了问题,并且测试时设备日志记录了一次极光推送被强制关闭的log。同时发现极光推送控制台日志显示设备不在线(后来发现近期极光推送非常不稳定,这种延迟是常规状态了,由于原来自建推送可用, 所以没有注意)。

但是经检查发现设备没有问题,而且设备状态上报部分同样使用的 socket.io,也很正常。所以又测试了一下python向网页端推送,发现还是收不到推送,确认python发出的推送出现故障了。

无奈进 redis 数据库查看推送是否进入了数据库,结果发现python发出的推送消息的确进入了redis数据库,但是和socket.io本身发出消息的频道名称不一致。找了一下,没有当时的记录了,大体是执行的redis-cli命令,通过 PSUBSCRIBE * 订阅所有频道。

于是觉得可能是频道名字的问题,所以仿着 socket.io 消息的格式通过 PUBLISH 频道名称 消息 发了个消息,无效,并且命令返回了1,只有手工PSUBSCRIBE * 的订阅,也就是 socket.io 过呢本没有接收消息。觉得是 socket.io 有问题,岁查看代码,发现socket.io-redis 会根据房间名订阅消息,并不会订阅 #emitter 频道的消息,就很纳闷之前的系统为什么能工作。检查了下修订历史,发现是 0.1.4 -> 0.2.0 为了性能只订阅相关房间的消息,看了一下发现 python 的代码是2年前了,和当前的实现不兼容…

无奈只能自己修改了,中间又发现新版本同时还修改了包格式,不过都问题不大。

这次修bug理清了大部分 socket.io-redis 的流程。

socket.io-redis 接收消息是通过订阅 redis 上面相关的频道来实现的,会检查 uid 看看是不是本机发出的,如果不是就转到 socket.io 处理。不过这里有个问题,uid 是随机生成的6位字符串,也就是有可能碰到相同的uid,socket.io-redis 会抛弃相同uid的消息造成相同uid的 socket.io 之间无法通行。

发送消息是通过向 redis 发送消息,然后其他 socket.io-redis 订阅并接收实现的。广播消息会直接发送到 prefix + ‘#’ + packet.nsp + ‘#’ ;发送到指定房间的消息会对涉及到的房间都发送一条 prefix + ‘#’ + packet.nsp + ‘#’ + room + ‘#’ 频道的消息。

发表评论

电子邮件地址不会被公开。