项目背景

作为团队的内部技术需求,需要开发一个长链接服务,主要用作为服务端向客户端主动推送消息的通道,计划用做一些配置信息的下发。对于Netty、webSocket等属于0经验。接到这个需求,开始进行技术调研,搭建demo服务,与客户端进行方案讨论,一步一步完成服务的正式上线。
经过持续的优化,技术具备了实时推送能力,后续逐步接入了更多的业务侧实时触达需求。

技术选型

Java + springBoot + Netty + MQ + Kafka. 采用WebSocket协议。
公司日活百万用户,同时APP在线设备数据15w左右,上线后,整体服务运行稳定。
 

总体的架构设计

notion image
 

协议层

与客户端同学一起讨论方案后,最后采用webSocekt协议。
服务端可以同时支持Socket IO + ProtoBuf方式。

长链接服务

采用核心服务与接入服务解耦分开,这样设计初衷保证核心服务的高稳定性,与业务进行隔离,核心服务将设备的绑定/解绑信息通过kafka 推送给接入服务进行设备实时在线信息的维护,同时接入端负责对接业务层的需求,通过MQ将推送的消息推给接入服务,接入端通过RPC方式推给核心服务,找到在线设备,进行消息推送。同时对于离线消息,通过一定规则,当设备再次上线后,可进行投递。

业务流程

notion image
 

补充介绍

socket方式

socket方式采用ProtoBuf 协议,webSocket 目前仅采用字符串方式(TextWebSocketFrame)
Socket 方式网络协议头
/**  *  +---------------------------------------------------------------+     *  | 魔数 2byte | 协议版本号 1byte | 序列化算法 1byte | 报文类型 1byte  |     *  +---------------------------------------------------------------+     * | 状态 1byte |        消息 ID 8byte     |      数据长度 4byte     |     * +---------------------------------------------------------------+     * |                   数据内容 (长度不定)                          |     * +---------------------------------------------------------------+     */
内容
属性名
类型
描述
默认值
魔数
magic
short
魔数,是协定的一个共识字段,判断请求协议的魔数是否合法。
2
协议版本号
version
byte
为了应对业务需求的变化,可能需要对自定义协议的结构或字段进行改动。不同版本的协议对应的解析方法也是不同的
1
序列化算法
serialization
byte
序列化算法字段表示发送方将对象转换成二进制流,以及接收方将接收的二进制流转换成对象的方法,具体类型值稍后补充
1
报文类型
messageType
byte
报文类型用于描述业务场景中存在的不同报文类型。如 RPC 框架中有请求、响应、心跳类型。IM 通讯场景中有登陆、创建群聊、发送消息、接收消息、退出群聊等类型
根据业务场景讨论确认 1:绑定 2:重连 3:关闭 4:响应(response) 5:心跳(heartBeat)ping 6:心跳(heartBeat)pong 7:业务1 8:业务2 9:业务3
状态
status
byte
状态字段用于标识请求是否正常,一般由被调用方设置,这里暂时可以设置默认值
1
请求ID
requestId
long
作为串联整个请求的ID,请求方自定义就好
请求方生成
数据长度
messageLength
int
消息体内容长度(二进制字节流)
消息内容
byte
消息内容二进制字节

核心流程设计

1、服务部署

长链接服务的核心服务,4节点,单节点4C12G。突发应急情况下K8S可支持动态扩缩容。
长链接服务的接入服务,4节点,单节点4C4G。同样支持动态扩展。

2、通道维护

每个设备的连接,通过Map<deviceId,Channel>维护在服务内存里,链接的创建及断开进行增删。

3、消息路由

通过MQ的广播消息实现。(也可以通过Redis的发布订阅模式、Zookeeper的watch机制)
当长链接接入端收到消息触达请求,组装好请求后,通过rpc推送给长链接的核心服务,由于是多节点部署,核心服务由一个节点收到请求后,判断此设备是否在当前节点,如果在,则找到对应的Channel,判断channel存活状态后,将消息推送出去,获得response success后,将推送成功的消息由kafka推送给接入服务。如果此设备通道不在当前节点,则发送MQ广播消息,去其它几个节点寻找,找到后,则进行推送。

4、离线消息

当推送消息时,设备正好离线没有成功推送,则通过一定规则比如:24小时内,推送不超过3次,设备再次上线则进行消息触达。

5、埋点监控

对于设备的在线情况,可以通过metrics埋点,看到设备的实时在线情况。

监控数据看板

notion image
 

项目代码示例

 
 
实时业务场景技术解决方案实时业务场景技术解决方案