#研发中间件介绍#异步消息可靠推送Notify

时间:2022-09-23 17:30:53
郑昀 基于朱传志的设计文档 最后更新于2014/11/11
关键词:异步消息、订阅者集群、可伸缩、Push模式、Pull模式

本文档适用人员:研发
 
电商系统为什么需要 NotifyServer?
  如子柳所说,电商系统『需要两种中间件系统,一种是实时调用的中间件(淘宝的HSF,高性能服务框架)、一种是异步消息通知的中间件(淘宝的Notify)』。那么用传统的 ActiveMQ/RabbitMQ 来实现 异步消息发布和订阅 不行吗?
 
  2013年之前我们确实用的是 ActiveMQ,当然主要是订阅者 Pull 模式,选 MySQL 做消息持久化存储,SA 还为此反复测试了各种高可用方案,如下图所示,ActiveMQ 5.8,mq主从+mysql互为主从+MMM。
#研发中间件介绍#异步消息可靠推送Notify
图1 mq 高可用
  它有三个问题。
  第一,它对上游发布者要求可能不是那么高,但要求下游实现消息订阅时要健壮,比如订阅者把消息读走了后它挂了也得不丢弃消息继续处理,比如非常重要的消息不能只有一个单点订阅者,必须有订阅者集群,但又不能重复处理消息。我在《#研发中间件介绍#JobCenter》中说过,对每一位开发者维护者提出高要求,这不是我们的解题思路。我在《职场培训第五期:职场的真相》中给出了解题思路:『要摒弃单纯依靠员工之间互相提醒、依靠个人认真细致来规避相同错误的固有思路,铁打营盘流水兵,靠人终归是靠不住的,最好靠遵循规则的机器』。是的,异步消息的可靠推送(Push),应该是消息中间件的职责。
  第二,ActiveMQ 的高可用方案在可伸缩上不那么灵活,不适合电商业务。譬如说,我一开始用一组 [(mq1+mysql1(master角色)),(mq2+mysql2)] 来支撑所有业务的异步消息,但突然七夕节一个销售验证高峰即将到来,需要尽量平滑地把某些消息队列转移出去,用另一组支撑;或者我看某个消息队列的消息量比较大,想追加一个 mysql 节点单独存储它的消息。总之就是线上尽量平滑地扩容 mq server和 database,这事儿还得咱们自己从头搞才顺手。
  最后一个问题是所有开源系统的典型问题,伴随着开源系统以及各种 Driver 的版本升级,我们会一路踏入它埋下的每一个大大小小的坑。当然,不是说我们自己写的中间件就没有 Bug,但  ActiveMQ 确实让人摊手,如下面的 RCA 案例所示。
  • RCA:ActiveMQ 的生产者流量控制导致订单中心大量线程挂起;
  • RCA:PHP连MQ超时导致主库连接被打满,引发众多应用数据不一致——原因在于 PHP::Stomp 包的默认重试次数和默认超时时间;
  • RCA:调小 ActiveMQ之持久化 MySQL 的 wait_timeout 导致发送 MQ 消息频频失败。
 
  最终我们还是选择自己来面对如下场景,采用 Push 模式(NotifyServer 主动向下游 Push 消息):
#研发中间件介绍#异步消息可靠推送Notify
图2 一个异步消息需要很多订阅者集群分头处理
 
淘宝是怎么考虑这些问题的?
  • 可靠性:
    • 消息的投递分为两个阶段
      • 发布者向Broker发送消息
      • Broker向订阅者投递消息
    • 因此,消息有可能在三个地方丢失
      • 发布者到Broker之间
      • Broker本身
      • 从Broker到订阅者
  • 稳定性
    • 监视
      • Broker内存使用
      • 消息收发功能
      • 消息堆积情况
      • 存储的插入速度
      • 各个任务队列长度
      • 其他各项即时统计数据等
    • 控制
      • 自动移除失效存储节点 
      • 优雅降级的控制 
      • 添加新存储节点 
      • 添加新Broker
  • 限制
    • 有可能产生重复消息
    • 对订阅者的要求
      • 幂等性 f(f(x)) = f(x)
      • 重复调用多次产生的业务结果与调用一次产生的业务结果相同
  它内部两个消息中间件产品的区别为:
#研发中间件介绍#异步消息可靠推送Notify
图3 消息中间件对比
  以上资料出自于《消息中间件-Notify的概念和原理.pdf》。
 
窝窝如何实现 NotifyServer 的?
  2013年2月,经过几轮的讨论,技术选型初步确定,研发2部传志开始构建 NotifyServer。
  他设计了如下概念:
#研发中间件介绍#异步消息可靠推送Notify
图4 notifyserver 的几个角色概念
  技术模型可以描述为:
  • 模块关系
    • 各个模块(队列、生产者、交换中心、DB、消息体缓存、队列缓存、日志缓存、分配中心、消费者)存在一定的对应关系,通过这些对应关系能够更好路由和分流消息,动态扩展系统,改善系统瓶颈。
    • 这些对应关系都存储在控制中心关系数据库中,通过控制台界面来进行配置,各模块在启动和定时到控制中心来更新这些关系,用于消息的分配。
    • 这些关系都遵守一定规则,添加更改不会影响系统的稳定性,如:一个队列必须对应两个以上的交换中心来处理消息,如果DB中还有消息没有消费完毕不允许直接删除,等等。
  • 模块监控
    • 控制台定期测试各个模块的健康状况。
    • 各个模块会定期向控制中心发送一些监控数据,报告自己的运行状态。
    • 控制台收集监控数据,以图表、拓扑图等形式向管理人员展示或报警。
  • 消息跟踪
    • 每一条消息在进入系统后都会被分配一个唯一标识。
    • 各模块在处理消息时都会产生特定的日志信息,日志信息实时的传送到日志系统。
    • 唯一标识+日志+各模块信息和关系可以容易的跟踪每一条消息的执行情况。
 
  那么最简单的消息消费泳道图如下所示:
#研发中间件介绍#异步消息可靠推送Notify
图5 消息消费
  分配中心主导的慢速/重试Push,它会尽量从缓存(Redis)中拿消息体,尽量减少对 DB 的访问,尤其是消息体特别大的时候,效果会比较明显,如下图所示。
#研发中间件介绍#异步消息可靠推送Notify
图6 重试的泳道图
 
  对于可伸缩、高可用,他是这么考虑的:
  • 吞吐量:
    • 交换中心、分配中心都采用平行结构。
    • 队列使用持久化方式缓存,使用缓存减少对DB的操作。
    • 交换中心与分配中心分离,性能互不影响。
    • 动态改变网络拓扑结构,分流系统瓶颈。
    • 动态控制吞吐量参数,调整系统性能。
  • 扩展性
    • 交换中心、分配中心、DB、缓存可以动态添加或删除。
    • 队列路由路径可以动态改变。
  • 可用性
    • 交换中心、分配中心采用平行方式提高可用性。
    • DB采用 master-master 方式提高可用性。
    • 缓存采用多点读写方式提过可用性。
  • 一致性
    • 消息状态持久化在DB,未分配或消费失败的会再次被提取。
    • 分配中心采用快慢两种方式接收消息处理消息。
  • 等幂性
    • 缓存保存正在处理的消息,防止重复分配。
 
  与 JobCenter 一样,NotifyServer 也纳入在我们的 idcenter 体系下,这样可以共用一套帐号体系(LDAP),共用一个统一的权限分配:
 
图7 notifyserver 的入口
#研发中间件介绍#异步消息可靠推送Notify
图8 notifyserver 的主界面
 
图9 notifyserver 系统队列(主要是配置信息)界面
 
图10 notifyserver 监控队列(主要是运行时状况)界面
  2013年中旬,经过积分业务的试用后,传志的 NotifyServer 开始在内部推广,各种异步消息发布和订阅一点一点地搬进来,ActiveMQ 方案下线。
 
-over-
 
欢迎订阅我的微信订阅号『老兵笔记』,请扫描二维码关注:
#研发中间件介绍#异步消息可靠推送Notify

#研发中间件介绍#异步消息可靠推送Notify的更多相关文章

  1. #研发中间件介绍#定时任务调度与管理JobCenter

    郑昀 最后更新于2014/11/11 关键词:定时任务.调度.监控报警.Job.crontab.Java 本文档适用人员:研发员工   没有JobCenter时我们要面对的:   电商业务链条很长,业 ...

  2. RabbitMQ 延迟队列,消息延迟推送

    目录 应用场景 消息延迟推送的实现 测试结果 应用场景 目前常见的应用软件都有消息的延迟推送的影子,应用也极为广泛,例如: 淘宝七天自动确认收货.在我们签收商品后,物流系统会在七天后延时发送一个消息给 ...

  3. NET SignaiR 实现消息的推送,并使用Push.js实现通知

    一.使用背景 1. SignalR是什么? ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指 ...

  4. PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息限制

    2013年10月06日最新整理. PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息限制 微信公共平台消息主动推送接口一直是腾讯的私用接口,相信很多朋友都非常想要用到这个功能. 通过学习 ...

  5. Swift - 本地消息的推送通知(附样例)

    使用UILocalNotification可以很方便的实现消息的推送功能.我们可以设置这个消息的推送时间,推送内容等. 当推送时间一到,不管用户在桌面还是其他应用中,屏幕上方会都显示出推送消息. 1, ...

  6. .NET之微信消息模板推送

    最近在项目中使用到了微信消息模板推送的功能,也就是将对应的消息推送到对应的用户微信上去,前提是你必须要有一个微信公众号并且是付费了的才会有这个功能,还有就是要推送的用户必须是的关注了你的微信公众号的. ...

  7. dwr3实现消息精确推送详细步骤

    最近项目中需要用到推送消息,找了很久终于找到一篇不错的文章,方便以后查看就转载了,也分享给大家,希望能帮到有需要的人. 第一.在项目中引入dwr.jar,然后在web.xml中进行配置,配置如下: & ...

  8. 基于HTTP协议之WEB消息实时推送技术原理及实现

    很早就想写一些关于网页消息实时推送技术方面的文章,但是由于最近实在忙,没有时间去写文章.本文主要讲解基于 HTTP1.1 协议的 WEB 推送的技术原理及实现.本人曾经在工作的时候也有做过一些用到网页 ...

  9. spring boot 集成 websocket 实现消息主动推送

    spring boot 集成 websocket 实现消息主动 前言 http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单 ...

随机推荐

  1. python sys模块

    sy模块主要用于:解析器及环境 命令行参数 python xx.py xx1 xx2注:xx.py: sys.argv[0] 脚本名称 xx1 sys.argv[1] 第1个参数退出程序 sys.ex ...

  2. Codeforces 271 Div 2 B. Worms

    题目链接:http://codeforces.com/contest/474/problem/B 解题报告:给你n个堆,第i个堆有ai个物品,物品的编号从1开始,第一堆的编号从1到a1,第二堆编号从a ...

  3. Java学习笔记(八)——封装

    一.封装 1.定义 将类的信息隐藏在类的内部,不允许外部程序直接进行访问,而是通过该类提供的方法来实现对隐藏信息的操作和方法. 2.优点 (1)只能通过规定的方法访问数据 (2)隐藏类的细节,方便修改 ...

  4. CacheManagerUtils.java

    package com.vcredit.framework.utils; import net.sf.ehcache.Cache;import net.sf.ehcache.CacheManager; ...

  5. 泛型、Linq 查询使用

    查询类对象数组中符合条件的一个实例对象 泛型自带查询方法: EntityErpFldMx ms = aryFldMx.Where(i => i.Jhd == "4900120121&q ...

  6. Python学习(5)——内置函数

    常用字符串内置函数 1)str.count() //返回该字符串中某个子串出现的次数 2)str.find() //返回某个子串出现在该字符串的起始位置 3)str.lower() //将该字符串全部 ...

  7. UIView 添加子视图的常用方法

    1.  - (void)addSubview:(UIView *)view 这是最常用的方法有两个注意点 参数view可以是nil,运行不会报错,当然,父视图的subViews也不会增加. 此方法增加 ...

  8. 浅谈我对几个Web前端开发框架的比较

    强调一下,这篇日志主要还是针对想学前端开发的新朋友写的,不是说我有什么独特见解,而是比较客观的状态,就各种框架的异同和应用场合,需要注意的地方做简单描述,不做具体深入分析,有的地方比较抽象,对于抽象之 ...

  9. Vue使用的一些实例

    1.实现歌曲的点击切换. <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  10. web模拟终端博客系统

    本文由QQ音乐前端团队发表 前段时间做了一个非常有意思的模拟终端的展示页:http://ursb.me/terminal/(没有做移动端适配,请在PC端访问),这个页面非常有意思,它可以作为个人博客系 ...