希望长大对我而言,是可以做更多想做的事,而不是被迫做更多不想做的事...... 首页 RocketMQ 丁D 学无止境 2019-03-12 21:25 3132已阅读 RocketMQ MQ 消息中间件 摘要消息队列作为高并发系统的核心组件之一,能够帮助业务系统解构提升开发效率和系统稳定性。 ## mq一般作用 **提高系统响应速度**(不等待结果立即返回) **异步解耦**(如后台系统挂掉。消息可以先留在mq队列中后续消费) **并发削峰**(如正常时间 只有1000qps使用普通服务器就行。但是在一段时间有5000这时候使用好的服务器有点浪费,,所以使用mq来削峰如5分钟后告诉下单结果) **分布式事务** 消息中间件的主要功能是异步解耦,还有个重要功能是挡住前端的数据洪峰,保证后端系统的稳定性,这就要求消息中间件具有一定的消息堆积能力 ## rocket相比其他mq的优点 能够保证严格的消息顺序 提供丰富的消息拉取模式 实时的消息订阅机制 亿级消息堆积能力 ## rocketmq问题 **重复消费** **顺序消费** **消息丢失** 使用多主多从异步复制(当主节点gg时,会有少部分还没复制到从节点的消息丢失)。。使用同步复制 可以保证消息100%不丢失(但是性能下降10%) ## rocketmq节点 ![alt](/upload/b736fb798743217f851d38dcebd2236.png ) **Name Server** **Broker **部署相对复杂,Broker 分为 Master 与 Slave 一个 Master 可以对应多个 Slave,但是一个 Slave 只能对应一个 Master,Master 与 Slave 的对应关系通过指定相同的 BrokerName,不同的 BrokerId 来定义,BrokerId为 **0 表示 Master,非 0 表示 Slave**。Master 也可以部署多个。每个 Broker 与 Name Server 集群中的所有节点建立长连接,定时注册 Topic 信息到所有Name Server。 **Producer **与 Name Server 集群中的其中一个节点(随机选择)建立长连接,定期从 Name Server 取 Topic 路由信息,并向提供 Topic 服务的 Master 建立长连接,且定时向 Master 发送心跳。Producer 完全无状态,可集群部署。 **Consumer **与 Name Server 集群中的其中一个节点(随机选择)建立长连接,定期从 Name Server 取 Topic 路由信息,并向提供 Topic 服务的 Master、Slave 建立长连接,且定时向 Master、Slave 发送心跳。Consumer既可以从 Master 订阅消息,也可以从 Slave 订阅消息,订阅规则由 Broker 配置决定。 **Broker **要跟所有的nameServer 建立连接 Consumer每隔30s从Name server获取topic的最新队列情况,这意味着Broker不可用时,Consumer最多最需要30s才能感知。 当Consumer得到master宕机通知后,转向slave消费,slave不能保证master的消息100%都同步过来了,因此会有少量的消息丢失。但是一旦master恢复,未同步过去的消息会被最终消费掉。 ## 拉取方式 **push **consumer 应用注册一个listener 一旦收到消息会broker通知消费者,消费者回调listener接口 **pull **consumer 应用主动从broker拉消息 读取消息的位置 使用pull方式来读取消息 要自己保存offset偏移量可以保存到数据库 push不用关心,push 挂掉重启会从上次 消费的位置重新消费的 ## 消费方式 **广播消费** 一条消息被多个消费者消费。。即使consumer同属于一个消费者组 **集群消费** 一个消费者组平摊消费消息 一个topic 9条消息 3个消费者 平均一个消费者消费3条消息 **顺序消息** 生产者单线程顺序发送,并且发送到同一个队列中能保证消息顺序消费,但是主要 通讯异常broker重启,队列总数变化 哈希取模后定位变化 短暂消息顺序不一致,,,业务要是能容忍消息短暂乱序 **推荐使用严格顺序消息** 只要集群中有一台不可用整个集群不可用 使用同步双写模式,此缺陷通过 备机自动避免 有几分钟服务不可用 自动切换还未实现(**绝大部分都可以容忍短暂乱序**) Producer 向一些队列轮流发送消息,队列集合称为 Topic,Consumer 如果做广播消费,则一个 consumer实例消费这个 Topic 对应的所有队列,如果做集群消费,则多个 Consumer 实例平均消费这个 topic 对应的队列集合。 ## 优先级 规范中描述的优先级是指在一个消息队列中,每条消息都有不同的优先级,一般用整数来描述,优先级高的消息先投递,如果消息完全在一个内存队列中,那么在投递前可以按照优先级排序,令优先级高的先投递。 由于 RocketMQ 所有消息都是持久化的,所以如果按照优先级来排序,开销会非常大,因此 RocketMQ 没有特意支持消息优先级,但是可以通过变通的方式实现类似功能,即单独配置一个优先级高的队列,和一个普通优先级的队列, 将不同优先级发送到不同队列即可。对于优先级问题 只要达到优先级目的即可,不是严格意义上的优先级,通常将优先级划分为高、中、低,或者再多几个级别。每个优先级可以用不同的 topic 表示,发消息时,指定不同的 topic 来表示优先级,这种方式可以解决绝大部分的优先级问题,但是对业务的优先级精确性做了妥协 ## 刷盘方式 **rocketmq 建议使用多主多从同步复制 异步刷盘** **同步刷盘** 消息保存到磁盘中才算成功 ![alt](/upload/fa0ed2cc650ce5f9488f238a165956e.png ) **异步刷盘** 消息保存到pagecache中就算成功 ![alt](/upload/6e028b1497d5942072e49c899a24d9e.png ) ## 持久化 **commit log** 实则是一个文件 完全顺序写,随机读。 队列存储的只是消息在commit log的位置信息 ![alt](/upload/fabdf3600dc5aab46919ca3ac6e4a60.png ) **好处** 队列轻量化 **缺点** 读一条消息,会先读 Consume Queue,再读 Commit Log,增加了开销 Commit Log 中存储了所有的元信息,包含消息体,类似于 Mysql、Oracle 的 redolog,所以只要有 Commit Log 在,Consume Queue 即使数据丢失,仍然可以恢复出来。 ![alt](/upload/8f2cbae100bfd25d6413eb88350f78f.png ) ## broker搭建 **多 Master 模式** 一个集群无 Slave,全是 Master,例如 2 个 Master 或者 3 个 Master 优点:配置简单,单个 Master 宕机或重启维护对应用无影响,在磁盘配置为 RAID10 时,即使机器宕机不可恢复情况下,由于 RAID10 磁盘非常可靠,消息也不会丢(异步刷盘丢失少量消息,同步刷盘一条不丢)。性能最高。 缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息实时性会受到受到影响 **多 Master 多 Slave 模式,异步复制** 每个 Master 配置一个 Slave,有多对 Master-Slave,HA 采用异步复制方式,主备有短暂消息延迟,毫秒级。 优点:即使磁盘损坏,消息丢失的非常少,且消息实时性不会受影响,因为 Master 宕机后,消费者仍然可以从 Slave 消费,此过程对应用透明。不需要人工干预。性能同多 Master 模式几乎一样。 缺点:Master 宕机,磁盘损坏情况,会丢失少量消息。 **多 Master 多 Slave 模式,同步双写** 每个 Master 配置一个 Slave,有多对 Master-Slave,HA 采用同步双写方式,主备都写成功,向应用返回成功。 优点:数据与服务都无单点,Master 宕机情况下,消息无延迟,服务可用性与数据可用性都非常高 缺点:性能比异步复制模式略低,大约低 10%左右,发送单个消息的 RT 会略高。目前主宕机后,备机不能自动切换为主机,后续会支持自动切换功能。 ## 最佳实践 一个生产者最好只发一个topic的消息 一个应用尽可能用一个 Topic,消息子类型用 tags 来标识,tags 可以由应用自由设置 一个topic有多个队列 默认是4个。 一个消费者只能消费一个队列 一个topic有多个队列 一个消费者可以消费多个队列 一个队列只能由一个消费者消费 ![alt](/upload/094f8fbeeecfacab08db18e510548a5.png ) 防止消息丢失的方案 https://blog.csdn.net/LO_YUN/article/details/103949317 消息堆积怎么办 比如修复consumer代码故障,确保consumer逻辑正确可以消费; 停止consumer,开启10倍20倍的queue个数; * 创建一个临时的consumer程序,消费积压的queue,并把消息写入到扩建的10倍queue中;(这个消费者只转存没有具体的业务逻辑) * 再开启10倍20倍的consumer对新的扩充后队列进行消费; * 这种做法相当于通过物理资源扩充了10倍来快速消费; 不能直接加机器 因为一个队列只能由一个消费者消费,所以应该加队列然后加一个队列对应一个消费者 加大消费速度 很赞哦! (34) 上一篇:类加载机制 下一篇:缓存穿透,缓存雪崩,缓存击穿 目录 点击排行 Elasticsearch6.3.2之x-pack redis哨兵 2019-07-09 22:05 Redis+Twemproxy+HAProxy+Keepalived 2019-07-12 17:20 GC优化策略和相关实践案例 2019-10-10 10:54 JVM垃圾回收器 2019-10-10 10:23 标签云 Java Spring MVC Mybatis Ansible Elasticsearch Redis Hive Docker Kubernetes RocketMQ Jenkins Nginx 友情链接 郑晓博客 佛布朗斯基 凉风有信 MarkHoo's Blog 冰洛博客 南实博客 Rui | 丁D Java研发工程师 生活可以用「没办法」三个字概括。但别人的没办法是「腿长,没办法」、「长得好看,没办法」、「有才华,没办法」。而你的没办法,是真的没办法。 请作者喝咖啡