Swoole 长连接推送服务

Swoole开发消息推送服务

什么是消息推送服务器

消息服务器可以理解成是一个通道,它是把客户端和服务器、用户与用户、设备与设备之间连接的一个通道。

Swoole 长连接推送服务_第1张图片
消息推送服务

应用场景:虎牙游戏直播

虎牙游戏直播

角色分析

  • 主播
  • 观众
  • 频道

哪些地方需要做推送服务呢?

  • 主播开播时,系统发送消息给粉丝。
  • 游戏竞猜结果推送
  • 新闻推送
  • 即时聊天
  • 主动更新APP设置
  • 服务器主动控制

技术选项

  • 硬件设备:RAM 16GB + 8核E5-230
  • 操作系统:Ubuntu
  • 编程语言和框架:PHP+Swoole
  • 存储:Redis+MySQL
  • 通信协议:TCP+固定包头
  • 数据交换格式:腾讯的WP+JSON,建议使用WebSocket+JSON

消息服务器特点

  • 并发连接数:单机同时平均在线20W用户,峰值可达50W,使用3台消息服务器MsgServer,可支持150W用户同时在线。
  • 分布式系统:架构层面没有任何单点,任意程序模块均可水平扩容。

系统架构

Swoole 长连接推送服务_第2张图片
系统架构

获取消息服列表 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

Swoole 长连接推送服务_第3张图片
代理服务器
  • 代理服用于检测消息服的存活状态

若消息服没有连接到代理服,则认为此消息服已下线,则从Redis中删除消息服的IP地址信息。消息服上线后重新连接到代理服,并自动加入到Redis。

  • 代理服接收来自PHP代码、C++代码、Java程序的消息推送请求,转发给用户所在的消息服,消息服再将消息下发给用户 。

  • 代理服提供统一的API,支持使用不同语言,定时向某些用户推送消息。

Swoole 长连接推送服务_第4张图片
代理服进程

作业服务器 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作者本人。

你可能感兴趣的:(Swoole 长连接推送服务)