Swoole开发消息推送服务
什么是消息推送服务器
消息服务器可以理解成是一个通道,它是把客户端和服务器、用户与用户、设备与设备之间连接的一个通道。
消息推送服务
应用场景:虎牙游戏直播
虎牙游戏直播
角色分析
- 主播
- 观众
- 频道
哪些地方需要做推送服务呢?
- 主播开播时,系统发送消息给粉丝。
- 游戏竞猜结果推送
- 新闻推送
- 即时聊天
- 主动更新APP设置
- 服务器主动控制
技术选项
- 硬件设备:RAM 16GB + 8核E5-230
- 操作系统:Ubuntu
- 编程语言和框架:PHP+Swoole
- 存储:Redis+MySQL
- 通信协议:TCP+固定包头
- 数据交换格式:腾讯的WP+JSON,建议使用WebSocket+JSON
消息服务器特点
- 并发连接数:单机同时平均在线20W用户,峰值可达50W,使用3台消息服务器MsgServer,可支持150W用户同时在线。
- 分布式系统:架构层面没有任何单点,任意程序模块均可水平扩容。
系统架构
系统架构
获取消息服列表 GetMsgServerIP
- 一个PHP提供的HTTP接口,客户端会携带设备ID、用户ID等信息请求此接口。
- PHP程序查询Redis得到当前在线的消息服MsgServerIP列表。
- 负载分配按照一定算法,计算出该客户端连接到哪台MsgServer消息服务器。
- 消息服一旦宕机,会自动从Redis中剔除,客户端可连接到其他消息服务器。
消息服务器 MsgServer
消息服与客户端保持连接,设置Linux的ulimit -n
为100w,表示Linux可以创建100W个连接。
消息服会主动的与代理服ProxyServer
保持连接,程序一启动就立即与代理服建立连接,一旦断掉又会重新连接代理服。消息服一旦与代理服建立连接后,就会从代理服中接收来自其它消息服的消息转发。
消息服如何与客户端保持长连接呢?
- 消息服检测客户端存活状态,心跳时间为300秒/500秒。
使用心跳,客户端若没有任务请求则每隔300秒向消息服发送一个空包。若用户所处的网络环境较差则每隔300秒发送一次心跳包,若用户网络环境较好则设置请求间隔时间为500秒 。
为什么要这么做呢?
- 心跳过快耗电过多,心跳过慢则有可能被电信运营商切断连接。
由于手机的网络模块比较耗电,每次发送心跳包都需要检查用户的网络环境,若心跳过快则用户手机耗电过快。若心跳过慢则有可能被电信运营商切断连接,电信运营商若发现建立一个TCP连接后5分钟都没有任何数据活动的话,它的路由器就会将连接切断。
-
设备或用户登录退出操作,更新Redis中的状态。
-
消息进行双向确定/重传/去重。
消息服发送消息后客户端必须回复ACK
确认包,才认为已经成功。否则进行重传,客户端对服务器推送的消息进行去重,避免受到重复的消息,确保100%的可靠。
- 消息服一旦发现用户离线,会将消息保存起来,根据类型设置不同的过期时间。
若某些用户的连接断开也就是用户离线了,其他用户也会先他发送离线消息。消息服会将离线消息保存到Redis中,按照用户ID或设备ID作为Key,消息作为Value保存到Set集合中,同时设置过期时间,根据消息的类型,有的保存1天,有的保存7天等。
- 设备上线后会尝试推送离线消息
消息服进程
代理服务器 ProxyServer
代理服务器
- 代理服用于检测消息服的存活状态
若消息服没有连接到代理服,则认为此消息服已下线,则从Redis中删除消息服的IP地址信息。消息服上线后重新连接到代理服,并自动加入到Redis。
-
代理服接收来自PHP代码、C++代码、Java程序的消息推送请求,转发给用户所在的消息服,消息服再将消息下发给用户 。
-
代理服提供统一的API,支持使用不同语言,定时向某些用户推送消息。
代理服进程
作业服务器 JobServer
- 接受运营下发的广播或组播任务
- 查询用户和组,打包成单条消息,发送给代理服。
- 定时任务处理
- 其他业务逻辑处理
作业服务器进程
配套工具
- 运营管理平台:下发推送任务
push job
,查看用户在线状态,查看用户消息列表。 - 日志查询平台:对某些用户进行染色,查询
Access
日志或消息日志。 - 统计监控平台:统计当天消息发送数据、统计在线人数、监控报警。
注意事项
开发过程中的遇到的问题
- Android客户端的Java程序使用
socket.sendUrgentData
检测Socket
是否可用,某些路由节点不支持这种数据包,导致服务器收到的数据莫名其妙多了1字节。 - 不要使用PHP做大规模的计算逻辑
- PHP数组内存占用较大,需要对其规模有预估,避免内存爆掉。
- 尽量使用PHP局部变量和对象,避免使用全局变量和类静态变量。
- 不要迷信Redis,由于Redis是单线程的,因此CPU可能会成为瓶颈。可是使用Swoole的
task
进程或swoole_table
来取代一部分Redis的使用。 - Redis/MySQL/消息队列使用多实例
- Swoole设置CPU亲和性,避开CPU0,使CPU0仅处理网络中断。
- 上线后及时监控和报警,第一时间发现问题。
为什么要使用PHP开发呢
- 从立项、评审、开发、测试、上线,仅用了一个月,效率惊人。
- PHP开发调试简单,有利于产品迭代、完善和进化。
- PHP程序在Web方面有绝对优势,强大的后端Server配置Web管理界面。
为什么要使用Swoole呢
- 完整的Server/Client解决方案,无需关心网络通信的底层细节。
- C语言开发,性能强悍。底层几乎没有任何性能损失,CPU全部被利用到PHP程序上。
- 拥有各种API,如task/table/sendMessage/timer/event,非常灵活强大。
- Swoole有百度地图、腾讯企业QQ等大型企业使用,更加靠谱。
- 社区支持力度大,有问题可以联系到Swoole作者本人。