消息中间件

  • 消息中间件为咱们带来了异步特性,为系统解耦,对于大型分布式系统具备很是重大的意义

  • 这样系统变得很是复杂
  • 引入可扩展配置算是比较优雅的解决方案
    • 下降了开发部署成本
    • 并没实质性下降复杂性

引入消息中间件解耦服务调用java

  • 只须要向消息中间件发送消息
  • 其余服务订阅该消息
  • 成功解耦,不用关心多少系统须要知道登录成功这个事件
  • 各个系统互不影响

  • 上面用数据库 记录中间状态,写入时数据库不可用,仍是会有问题
  • 对于须要感知的应用,须要定时轮询查看状态,完成操做也要修改
  • 能解决问题,实现简单,可是也存在问题:
    • 增长了业务库的负担
    • 依赖的复杂和不安全(发短信的服务对数据库有操做权限,这样不安全)
    • 扩展性很差

互联网时代的消息中间件数据库

  • JMS(java message service)是JavaEE(企业版)关于消息的规范
  • ActiveMQ 等产品是对该规范的实现
    • 企业内部或小型系统直接使用JMS产品是很经济的
    • 大型系统有一些场景不适合
  • 在大型互联网中,使用消息中间件,最基础俩特色
    • 应用之间解耦
    • 操做的异步
  • 重点考虑:
    • 消息的顺序保证
    • 扩展性
    • 可靠性
    • 业务操做与消息发送的一致性
    • 及多集群订阅者
  • 消息发送一致性
    • 产生消息的业务动做和消息发送的一致性
    • 上述两种作法,第一种丢失消息的几率是很低的,
    • 可是对于必须保证一致性的场景,上面的两种方案都不可取
  • JMS 能保证消息发送的一致性吗?
    • JMS 重要要素
    • JMS 模型分为:Queue模型(PTP Domain模型)和Topic模型(pub/sub Domain模型)
      • XA 开头的接口表示支持XA协议(分布式事务协议)
        • 引入分布式事务带来的问题:
          • 带来开销增长复杂性
          • 对业务操做有限制,业务操做资源必须支持XA协议
  • 最总一致性方案:

  • 定时重复反向流程,重复查询就能够了
    • 大多数状况下,反向流程是不须要工做的

  • 新方案开销:仅仅增长了一次网络通讯、一次更新消息状态,开销并不大

  • 如何解决消息中间件和使用者之间的强依赖问题?
    • 思路有三:
      • 增强消息中间件可靠性,使之100%可靠
      • 消息中间件影响业务进行的部分加强可靠性
        • 业务表和消息表放在一个库,业务应用底层调用数据库同一个事务操做这俩表,保证一致性
        • 影响有三:
          • 业务库承载消息数据
          • 消息中间件去访问业务库
          • 业务操做的对象是一个数据库,支持事务的存储,知足消息的存储
        • 变通方案
          • 较多的逻辑从消息中间件的服务端挪到了消息中间件的客户端,而且在业务应用上执行
      • 提供弱依赖支持,可以较好的保证一致性
      • 利用本地磁盘方案
        • 若是消息中间件不可用,并且写入本地磁盘也坏了,消息就丢了
        • 两种用法:
          1. 容灾方案,平时不用,出现问题才使用
          2. 直接使用,能够控制调用发送消息接口的时间,好比作批处理
    • 业务应用和发送消息一致性带来的俩限制:
      • 须要肯定要发送消息的内容
      • 须要实现对业务的检查(实现反向流程)

消息模型对消息接收的影响缓存

  • JMS Queue 模型(点对点模型):
    • peer to peer 点对点
    • 消息发送出来不能肯定会被谁消费,但只有一个应用回去消费这条消息
  • JMS Topic模型
    • 发送消息和topic内部逻辑与Queue 模型同样
    • 接收消息很不相同,每一个应用都能接收到全部的消息
    • 每一个链接connection 都有惟一clientId
    • 下图是多连接的状况:
      • 应用3有两个链接
    • 换作topic 模型
  • 模型须要知足的条件:
    • 一个进程能够有多个connection链接到消息Server
    • topic模型,实际应用中每一个集群节点可能会很大,这个发送那么多重复数据负担太大
    • 整合这俩模型:
      • 面向集群用topic模型,具体应用使用queue模型来分发
        • 级联方案:

消息订阅者订阅消息的方式:安全

  • 持久订阅和非持久订阅
  • 要作到可靠,选择持久订阅
    • 接收者应用中止,消息保留,一旦上线再次发送

保证消息可靠性网络

  • 三个阶段均可靠,才能保证消息可靠:
    • 发送阶段要有明确的返回成功,才表明成功;
      • 失败、超时、异常都表明没成功
    • 消息存储(持久化存储)
        • 基于现有能够选择分布式文件系统、关系型数据库、NOSQL
      • 使用关系型数据库,不会那么严格按照范式,更多地使用冗余和宽表
        • 好比 学生id和学生名称,不少时候要一块儿展现
        • 单表查询比多表联查快的多,名称字段常常做为冗余字段存在
    • 消息中间件存储,一条消息存储一条数据
      • 表设计:
      • 单条消息订阅集群比较多时,更新投递次数频繁,把该字段放到消息表
        • 没法给投递列表里面的单独的接收者创建索引,损失了这个维度的灵活性
        • 堆积消息多的时候,不能针对特定集群调度,处理效率低
      • 基于双机内存保持数据的可靠
        • 内存速度远超磁盘,可是断电消失,可考虑双机内存
        • 一旦一台出问题,中止另外一台的写操做,并把数据落盘
        • 这种适用于大部分消息到了消息中间件后能大部分很快消费掉
  • 消息中间件扩容
    • 消息中间件自己没有持久状态扩容简单
    • 让发送者接收者感知到,有新的消息中间件加入集群,可以使用软负载配置
      • 不一样消息中间件使用相同存储,同一个消息中间件使用多个存储、
      • 消息存储中加入ServerId 来记录消息来自哪台机器
      • 须要注意:
        • 若是某个中间件长时间不可用,考虑加入新机器对应他的ServerId
        • 没处理完的消息,分给别的机器处理
  • 消息存储扩容
    • 不存在复杂查询,服务端主动调度,绕开了根据消息id 取消息
  • 消息投递可靠性保证
    • 业务处理完再确认
    • 不要吃掉异常,再确认,这样出现异常消息就丢了
    • 投递处理优化
      • batch操做
      • 一个应用上多个订阅者订阅同一个消息

订阅者视角,消息重复的产生和应对异步

  • 消息发送端重复发送
    • 解决:相同消息使用同一个id
  • 消息中间件向外投递重复
    • 中间件不能及时更新已投递状态,可用分布式事务来解决,可是代价高
    • 也可要消息接受者来处理,进行幂等操做:
      • 幂等是一个数学概念
      • 屡次重复操做和一次操做效果同样

JMS消息确认方式:分布式

  • AUTO_ACKNOWLEDGE
    • 接收到自动确认
  • CLIENT_ACKNOWLEDGE
    • 调用acknowledge() 函数确认
  • DUPS_ACKNOWLEDGE
    • 客户端处理函数执行完再确认
  • connection 建立queue 或topic 时设置

消息投递其余属性:函数

  • 优先级
  • 订阅者消息处理顺序和分级订阅
  • 自定义属性
  • 局部顺序
    • 须要一个属性区分和哪些消息一块儿排队

保证顺序的消息队列的设计性能

  • 单机多队列
  • 变推(push)为拉(pull)
  • 多个物理队列

单机多队列问题与优化优化

  • 队列多,查询性能差
  • 根据队列作索引

  • 好处:
  • 坏处:
  • 克服坏处:
    • 做缓存
    • 因为是顺序读取,可采用预读策略
  • 本地消息存储可靠性:
    • 把单个消息中间件机器变成Master-slave形式
    • 发送消息向中间件,等slave复制完毕再返回”成功“
  • 队列扩容:

推(Push)和拉(Pull)对比:

相关文章
相关标签/搜索