场景描述
当用户对app有某些业务操作时,需要将该操作友好地提醒给,有接收提醒权限的后台管理者。
技术场景分析
经分析,要实现上述业务,业务拆解后可能需要解决如下业务
①.触发提醒待推送数据的监听
②.提醒时接收权限的处理
③.提醒推送
④.提醒未处理的超时处理
⑤.提醒一览汇总
⑥.提醒补偿处理
⑦.集群推送
技术选型一览
具体实现
触发提醒待推送数据的监听
- 系统间集成问题
异步:采用生产者系统与消费者系统异步处理的方式来实现,生产者负责生产消息 ,并将消息放入任务列表,消费者负责监听它,并消费其上的消息。
同步:采用生产者直接调用消费者方法的方式来实现,此方式造成服务间的耦合性较大,故没有采用。
- 数据监听的异步处理机制
启动一个可定时的并发线程池,设置一定的轮询时间,轮询的线程负责查询redis任务队列(List实现),当任务队列中有数据时,那么轮询以先进先出的策略(lPop)取出数据。
- 监听线程池的实现
启动可定时的并发线程池(ScheduledExecutorService),此处要注意查看系统可承载能力,若系统性能足够强大,则可将池子的线程数量设置的大点。
- 监听的任务队列
为了与外部系统交互方便,暂时采用了基于redis的数据存储,未来可以优化为用rabbitmq、activeMq等替代
至此我们要轮询推送的数据已经取到了,那么就可以设计推送的逻辑了。
可接收提醒权限的处理
- 得到当前在线的用户
由于本文作者的系统是基于shiro做的权限处理,其对外暴露的方法是可以轻松取到当前在线的所有的用户的会话(Session)的,如果使用shiro外的框架,可以自行实现类似的处理
- 根据用户的会话(Session)得到其所对应的用户信息
- 得到用户拥有的权限(缓存+DB)
- 在点对点推送前,验证待推送用户的权限与内容设置的权限是否有匹配到,如果能匹配到,则认为权限验证成功,进行下一步操作。
提醒的推送
- 基于websock的机制进行推送
客户端与服务端建立连接后,会把当前会话ID作为监听的点对点标识,监听该队列。
- 消息推送(局部广播)
后台在解析到待推送的任务后,遍历在线的用户会话列表,得到用户的权限,进行鉴权处理,
当鉴权通过后,已会话id为标识进行消息推送。
★由于我们的系统是没有做单点登录的限制的,为了使消息的推送与接收是可靠的,所以采用了会话ID作为推送的标识。
- 推送状态记录
推送后将推送的结果记录到推送结果表中,方便补偿业务做处理
提醒未处理的超时处理
- 提醒未处理,是指当管理人员不在线或未及时查看(查看后关闭提示框)消息,且消息较多时,桌面的将会被消息窗口覆盖,此时系统需要把长时间未查看的消息清除掉,好腾出桌面做其他业务。正好作者选用的前端组件是支持倒计时清空的,完美地解决了此问题。
提醒一览汇总
- 业务中需要将推送的信息汇总起来,方便查看及日后备查,此功能相对简单。
提醒补偿处理
- 由于业务中有某些场景需要做业务处理并记录提醒查看的状态,且消息的送达率有时会要求近似百分百,那么此时我们就需要启动一个离线任务定时轮询补偿消息推送。
本业务中,作者采用了十分钟,半小时,两小时,五小时,十小时,二十四小时,四十八小时的轮询间隔策略。
集群推送
- 当服务的架构是集群时,把消息推送给集群中的某个用户就变得相对困难。针对此问题,有两种方案,
- 方案一:维护一个在线的服务本体主机列表,当有新消息时轮询推送,若用户不该服务中,则寻找下一个服务,只到找到所在的服务后进行推送处理
- 方案二:采用rabbitmq技术进行实现,消息生产者把消息推给rabbitmq后即完成了消息的分发。
架构图