消息推送
消息推送是针对 Web 应用开发领域的技术,指服务端以主动方式将信息送达客户端。主要用于提升用户体验,避免用户刷新页面从服务端拉取数据。例如 Web 邮件中自动出现刚收到的邮件项,Web 即时通讯自动提示新到消息等应用场景。
要实现消息推送机制,涉及两方面的内容:
Web 层消息推送
服务层消息服务
Web 层消息推送
套接字
可以使用套接字接口进行全双工通讯。可以通过 Flash XMLSocket、Java Applet 技术实现。
但由于实现方案与厂商技术绑定过紧,不属于 Web 标准化范畴,并且存在一些限制(通讯端口开启安全、客户端插件),这里不进行描述。
HTTP 请求轮询
目前的 Web 应用是基于 HTTP 协议的,其规定了请求-响应的处理模型,位于应用层的单工通讯模式使得纯粹意义上的服务端推送方式变得难以实现。
为了基于 HTTP 协议进行“推送”实现,可由客户端发起 HTTP 请求轮询,服务端在请求后返回响应。
根据轮询时间、请求处理方式,分为以下三种推。
简单轮询
客户端一般以定时方式发起请求,服务端处理后返回响应。
原理、客户端/服务端实现简单
可根据应用场景调整轮询时间间隔
服务端需要处理大量请求
长轮询
客户端发起请求后服务端将该请求挂起(不返回响应),直到超时、异常或需要处理响应(推内容)才返回。客户端收到响应后再次请求(即轮询)服务端,并处理响应。
实时性高
服务端需要管理挂起请求
HTTP 流
客户端发起请求后服务器端处理请求,并通过 HTTP 流一直向客户端写入数据,直到超时或异常才返回响应。连接断开后客户端再次请求服务端,属于长轮询的一种。
HTML 5 WebSocket
这是标准化的客户端全双工通讯规范,但由于目前服务端规范尚未成型,且考虑到现有客户端对 HTML 5 的支持有限,这里不进行描述。
多客户端支持
上述介绍是针对浏览器客户端的,在实际应用场景中,还需要考虑其他客户端支持,例如 iOS、Android 等。
在移动客户端方面,需要考虑如下几点。
APIs 多样
不同客户端本地 APIs 接口存在差异,但都支持基本的 HTTP 协议。直接基于 HTTP 协议进行开发可将差异最小化。
网络连接不稳定
通讯信道打开后不一定能长时间维护,客户端与服务端的状态管理复杂。
最小化流量
需要尽量最小化网络流量,提升移动客户端可用性。
服务层消息服务
消息是系统或组件间通讯的一种低耦合方式,是系统级异步架构的基础。
在 Web 消息推送中,服务端管理应用状态,当状态发生变迁时需要通知客户端,完成消息推送。
Java Message Service
需要重点关注如下技术点:
消息域
点对点只有一个客户端可以接收到消息。
发布/订阅广播给订阅的客户端。可配置持久化订阅。
消息确认
会话本地事务提交时会对收到的消息进行确认,回滚时将重传所有消息
非本地事务确认:Session.AUTO_ACKNOWLEDGE、Session.CLIENT_ACKNOWLEDGE、Session.DUPS_OK_ACKNOWLEDGE
技术设计
目标
支持浏览器客户端的推送
高性能、高可靠
模块化,不与应用耦合
未来可支持多种移动客户端
Web 层设计
Web 层考虑采用开源组件Pushlets进行实现。
Pushlets 组件
Pushlets 基于 HTTP 协议的发布/订阅模型,提供了 Poll(轮询)、Pull(拉)两种推方式实现。其中 Pull 即长轮询方式,当有消息时就返回。
发布:GET/POST 或方法调用(Dispatcher 接口)
订阅:GET 流,拉/轮询模式
树形主题:可层次化订阅
协议格式:JS,XML(JSON 尚未支持)
对使用 HTTP 协议的客户端都可用
易扩展:例如事件源实现
方便整合:可独立为 Web 应用,也可为 Web 应用组件
多种实现:J2EE/servlets,JavaScript (AJAX)
JS 客户端
js-pushlet-client.js
使用 “隐藏 iframe 技巧”
格式:JavaScript 函数事件
ajax-pushlet-client.js
使用 XMLHttpRequest
格式:XML
不支持 HTTP 流
使用 AJAX 客户端,较为灵活,便于封装。
服务层设计
服务层消息服务采用应用服务器 JMS 中间件。通过发布/订阅模型实现状态同步。
处理步骤
配置主题订阅
应用状态变迁时发布 JMS 消息
JMS 消息监听器将监听到的消息发布到 Pushlets
将该消息写入 Web 层消息表
消息表
保存推送多的消息记录,用于客户端刷新时/多客户端查找消息。
userId
createdTime
lastGetTime
clients
msg
type
timeout
targetSys
srcSys
….
xxx
xxx
xxx
[“pc”, “iOS”]
{}
公告
3天
OA
OA
消息体使用 JSON 字符串存放于 msg 字段中。其余字段可根据通用性进行抽取,比如用户名等。
消息监听器接收到消息时推 Pushlets,并进行记录写入(记录 lastGetTime 为写入时间,表示这条消息已经推送过)。
设置定时任务对超时记录进行删除。
逻辑架构
JMS 消息系统为单独的通讯总线服务独立于应用系统,Pushlets 为应用系统中的一个组件。
消息表管理组件提供消息新增,以及对推送过的消息记录的查询、删除。
推时序
关键点
服务层消息处理JMS 对于应用开发是透明的,应用只需调用封装好的发送接口,继承监听接口。发送时根据应用场景设置主题属性,监听处理时根据消息属性实现处理逻辑。
消息表管理需要使用定时任务或手动触发清除历史消息。
Pushlets 配置,License 问题:Pushlets 是以 LGPL 开源的,对于商业项目使用时必须进行封装:《基于 Pushlets 的消息推送设计》。
参考
摘抄自:https://docs.google.com/document/d/1qHVKlGz1raVemA2eHMSrPQppVKAiIrnFmfkpoyYE-U4/edit?pli=1#