高级JAVA开发 MQ部分

2023-11-14

MQ

参考和摘自:
中华石杉 《Java工程师面试突击第1季》
ActiveMQ—知识点整理
消息总线真的能保证幂等
ActiveMQ消息传送机制以及ACK机制详解

MQ的作用、为什么要用MQ

解耦、异步、消峰

应用场景:

  1. 解耦:利用 发布/订阅(Publish/Subscribe)模型,多服务订阅同一queue,省去生产者主动调用并维护多个消费者(service),消费者可随时unSubscribe,生产者并不感知。
  2. 异步:利用 点对点( Point-to-Point)模型,将多个任务分别放到不同队列中,之后直接返回。消费者各自从不同队列取得任务并消费。这么做的好处是不用阻塞等待多个任务全部返回再响应用户操作,加速响应。
  3. 消峰:利用 点对点( Point-to-Point)模型,在系统请求高峰期不采用阻塞式调用,将任务全部打入MQ中,让系统调用链中消费者慢慢消化任务。防止系统被访问高峰打死(很大原因是直接访问数据库,数据库成为瓶颈,后面也会在 缓存 章节继续分析)。

常见的MQ的优缺点

摘自中华石杉老师的笔记

特性 ActiveMQ RabbitMQ RocketMQ Kafka
单机吞吐量 万级
吞吐量比RocketMQ和Kafka要低了一个数量级
万级
吞吐量比RocketMQ和Kafka要低了一个数量级
10万级
RocketMQ也是可以支撑高吞吐的一种MQ
10万级
这是kafka最大的优点,就是吞吐量高。
一般配合大数据类的系统来进行实时数据计算、日志采集等场景
topic数量对吞吐量的影响 topic可以达到几百,几千个的级别,吞吐量会有较小幅度的下降。
这是RocketMQ的一大优势,在同等机器下,可以支撑大量的topic
topic从几十个到几百个的时候,吞吐量会大幅度下降。所以在同等机器下,kafka尽量保证topic数量不要过多。如果要支撑大规模topic,需要增加更多的机器资源
时效性 ms级 微秒级
这是rabbitmq的一大特点,延迟是最低的
ms级 延迟在ms级以内
可用性
基于主从架构实现高可用性

基于主从架构实现高可用性
非常高
分布式架构
非常高
kafka是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
消息可靠性 有较低的概率丢失数据 经过参数优化配置,可以做到0丢失 经过参数优化配置,消息可以做到0丢失
功能支持 MQ领域的功能极其完备 基于erlang开发,所以并发能力很强,性能极其好,延时很低 MQ功能较为完善,还是分布式的,扩展性好 功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准
优劣势总结 非常成熟,功能强大,在业内大量的公司以及项目中都有应用。
偶尔会有较低概率丢失消息。而且现在社区以及国内应用都越来越少,官方社区现在对ActiveMQ 5.x维护越来越少,几个月才发布一个版本。
而且确实主要是基于解耦和异步来用的,较少在大规模吞吐的场景中使用。
erlang语言开发,性能极其好,延时很低;
吞吐量到万级,MQ功能比较完备
而且开源提供的管理界面非常棒,用起来很好用
社区相对比较活跃,几乎每个月都发布几个版本分
在国内一些互联网公司近几年用rabbitmq也比较多一些
但是问题也是显而易见的,RabbitMQ确实吞吐量会低一些,这是因为他做的实现机制比较重。
而且erlang开发,国内有几个公司有实力做erlang源码级别的研究和定制?如果说你没这个实力的话,确实偶尔会有一些问题,你很难去看懂源码,你公司对这个东西的掌控很弱,基本职能依赖于开源社区的快速维护和修复bug。
而且rabbitmq集群动态扩展会很麻烦,不过这个我觉得还好。其实主要是erlang语言本身带来的问题。很难读源码,很难定制和掌控。
接口简单易用,而且毕竟在阿里大规模应用过,有阿里品牌保障
日处理消息上百亿之多,可以做到大规模吞吐,性能也非常好,分布式扩展也很方便,社区维护还可以,可靠性和可用性都是ok的,还可以支撑大规模的topic数量,支持复杂MQ业务场景
而且一个很大的优势在于,阿里出品都是java系的,我们可以自己阅读源码,定制自己公司的MQ,可以掌控
社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准JMS规范走的有些系统要迁移需要修改大量代码
还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用RocketMQ挺好的
kafka的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展
同时kafka最好是支撑较少的topic数量即可,保证其超高吞吐量
而且kafka唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略
这个特性天然适合大数据实时计算以及日志收集

使用MQ带来的问题以及处理办法

MQ带来的问题列举

  1. 系统可用性降低,需要保证MQ健康的运行,否则MQ挂掉会导致整个应用不可用,后果难以设想。
  2. 系统的复杂性变高,比如消息重复消费、消息丢失 等等,需要用一些手段来处理,怎么处理接下来细说,这里将会成为重要考点。
  3. 一致性问题(分布式事务)。A、B、C、D四个任务必须同时成功,放入MQ后A、B、C都成功了,偏偏D任务失败了该如何处理。这也是重要考点。

消息重复消费(幂等)问题

消费者拿到消息但是还没来得及ACK(或者还没来得及提交offset)就挂掉了,重启后会重新拿到已经消费但是还没通知(ACK)给MQ的消息,就产生了重复消费问题。(PS:这里如果MQ采用AUTO_ACK模式,消费者拿到消息后会第一时间给MQ做出ACK反馈,之后再去消费消息。但还没来得及消费完就挂掉了,那么MQ会认为此条消息处理过了,消费者重启后会继续从MQ拿消息,会产生消息丢失的问题,参看:<消息丢失问题>章节)
解决办法:
数据携带唯一id,基于内存Map或Set、Redis、数据库唯一键,保存消费成功的数据,重复数据来第二次时候可以感知到并直接丢弃处理。

面试遇到过这么一个问题:
面试官:有100w用户电话号码数据在数据库中,并不保证其中是否有重复,要求为每一个用户发一条短信并且不可重复发送,现提供一个基于http的短信发送微服务,该如何设计架构,最简单最快的把短信发送出去?

我的思路:
1.数据量过大,不能在数据库上做去重,并且用多线程读取更快。
2.短信服务会成为瓶颈,需要缓冲。
3.怎么在消费的过程中直接过滤掉重复消息。

我:用多线程读取数据(计算好多少页,每个线程取多少次,一次取多少条)将用户数据灌入MQ,多个消费者从MQ取得数据先在Redis中读一下看看有没有消费过,并在Redis中存入消费过的电话号码,调用短信服务(多部署几个)发送。重复电话号码直接舍弃数据不消费。
接着面试官问:如果就有那么几个消费者同时取到电话号码,巧了,他们取到的电话号码相同,查了一下Redis,没人发送过,就有重复发送的问题,怎么解决。
我:呃…


回来想了一下这个问题,因为先读取Redis再写入Redis并不能保证原子性,出现了并发问题。采用和分布式锁相同的思想来解决这个问题。参考下面文章:
Redis分布式锁的正确实现方式
用Redis的set加入NX(SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;)参数保证set原子性并且取得返回值。完美解决~~~


PS:

  1. Redis是主从集群,上述分布式锁会有漏洞。Redisson分布式锁实现框架可以弥补漏洞。(slave节点异步同步master数据,有延时。master节点设置锁还未同步到slave时挂掉了,锁就失效了)
  2. 由于本人技术水平有限,上述的架构方案并不是最优的,读文章小伙伴有更好的解决方案请发邮件给我,不胜感激~~~~

消息丢失问题

1.生产者发送消息丢失:
生产者发送消息到MQ过程中,网络原因丢了。
MQ接收到消息后内部出错,没保存下来。
解决办法:
1.用 事务,发送时用try catch包裹发送消息代码块,如果发送失败可以拦截Exception再做进一步处理(重发或者…)
事务机制是 同步阻塞的,影响发送消息吞吐量。
2.(RabbitMq)利用 confirm机制。把channel设置成confirm模式,发送结果通知给本地实现的接口,如果通知失败再做进一步的处理(重发或者…) 异步不会阻塞,吞吐量高
2.MQ本身问题丢失:
MQ挂掉了导致内存中消息丢失
解决办法: 配置持久化。但是也有一种可能,消息接收到了但是还没来得及持久化就挂掉了,还是会丢失一点点数据。
3.MQ到消费者消费过程中导致的丢失,消费端弄丢了数据
消费着拿到消息但是还没来得及消费就挂掉了,MQ以为消费者已经处理完了
解决办法:关闭AUTO_ACK,采用CLIENT_ACK模式,客户端收到消息处理成功后再手动发送ACK给MQ。如果消费者挂掉了,MQ针对这条消息会ACK超时,重新发给别人继续消费。

消息顺序性问题

这里假设要处理一个订单的三个任务,三个任务为一组:

  1. RabbitMQ等非分布式MQ解决方案:
    思路:将同订单任务按顺序放到一个Queue中,一个消费者只从一个Queue消费。
    在这里插入图片描述
    这里不能建立无穷多个Queue,将订单号的hash值对Queue个数取余分发到对应Queue中即可。
  2. Kafka等分布式MQ解决方案:
    参考:kafka topic消息分配partition规则(Java源码)
    思路:由于Kafka是分布式的,每个Queue中的数据会分布到多个partition中。Kafka可以保证每个partition中的数据是有顺序的,那么指定key(比如订单ID),将需要保证顺序的任务放到同一partition中(kafka会把key值一样的任务放到一个partition中,和上述订单号对Queue个数取余原理相同),一个消费者只能从一个partition消费,这样就保证了按顺序执行。

如果消费者是多线程并发的从partition取得数据,多线程不能保证执行顺序,那么上述模型就不好用了。
解决办法: 在消费者端建立多个线程安全的队列(比如LinkedBlockingQueue,这里我认为采用阻塞队列比较好,省得消耗jvm内存过多导致oom异常),从MQ取得任务,将相同订单号的任务发送到同一个队列(也可以用hash取余的办法),再对每一个队列启动一个线程消费任务,保证顺序执行。
在这里插入图片描述

消息过期丢失、大量积压等问题

  1. 过期问题:
    一般不设置消息的过期时间。如果设置了过期时间,只能在事后从数据源头找出数据,写程序将数据重新发送到MQ中。
  2. 大量积压后如何快速消费:
    ActiveMQ、RabbitMQ等非分布式MQ单个Queue数据量过大增加临时MQ节点也不能解决问题(每个节点存储全量数据),需要增加消费者临时节点来加速消费。
    Kafka是分布式MQ,每个消费者只能指定一个partition消费,那么新建立一个更多节点的Kafka集群,增加临时服务将原Kafka集群中的数据直接分发到新Kafka集群,这样消息会平均分配到更多的机器中,减缓MQ压力,再针对新Kafka集群添加实际业务处理的消费者,增加消费速度即可。
  3. MQ积压导致磁盘空间不足:
    (Kafka)增加临时消费节点将消息写到临时MQ集群中。
    或者增加临时消费者拿到数据直接将数据扔掉,事后做补偿。防止MQ直接压垮掉导致整个系统不可用。

如何保证MQ高可用性

RabbitMQ高可用以及部署模式

单机模式,普通集群模式,镜像集群模式

  1. 单机模式
  2. 普通集群模式
    集群中Master保存Queue元数据(Queue的属性之类的数据)和Queue数据,slave只保存Queue的元数据,在访问slave节点时,slave去和主节点通信取得Queue数据。
    总结:
    优点:提高消费吞吐量
    缺点:1. 性能开销大,在集群内部产生大量数据传输 2.可用性几乎没有保障,主节点挂掉了,整个MQ不可用。
  3. 镜像集群模式
    所有节点都保存Queue的所有数据。在写入数据时,各个节点自动同步。消费数据时同样。
    总结:
    优点:高可用,单个节点挂掉不影响整个集群
    缺点:1.性能开销大,需要所有机器同步所有数据。 2.不是分布式的,单Queue数据量超级大,超出单机最大容量时无法处理。 3.扩展性很差,和第2点一样,加机器也不能缓解数据量超级大的问题。
如何开启镜像集群模式

在管理控制台新增一个策略,这个策略是镜像集群模式的策略,指定的时候可以要求数据同步到所有节点,也可以要求同步到指定数量的节点,然后再次创建Queue的时候应用这个策略,就会自动将数据同步到其他的节点上去了。

kafka的高可用性

多个broker组成,每个broker是一个节点;创建一个topic,这个topic可以划分为多个partition,每个partition可以存在于不同的broker上,每个partition放一部分数据。(可以理解为每个Queue的数据被划分到不同机器上,换言说每个机器都持有同一个Queue的一部分数据)。在0.8版本以前没有HA机制,其中一台机器宕机则数据直接丢失。0.8版本后可以针对每个partition设置多个broker,其中一台是leader节点,其余是follower节点,只有leader节点提供对外读写服务,数据读写自动同步到follower节点,如果leader挂掉,follower们通过选举算法选举一个follower作为新的leader继续提供服务。

摘自中华石杉《Java工程师面试突击第1季(可能是史上最好的Java面试突击课程)\06_引入消息队列之后该如何保证其高可用性?\视频\04》图片摘自中华石杉《Java工程师面试突击第1季(可能是史上最好的Java面试突击课程)\06_引入消息队列之后该如何保证其高可用性?\视频\04

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

高级JAVA开发 MQ部分 的相关文章

随机推荐

  • 05_寄存器和RAM

    计算机的组成原理中 存储是必不可少的部分 可以用来存储计算的结果 图片 文字等等 本文将介绍存储是如何实现的 锁存器 首先我们来看一个门电路 当两个输入引脚都为0时 输出引脚也为0 如果A引脚输入1 输出为1 B引脚也会变为1 此时将A引脚
  • 指针:引领程序灵魂的精准指引

    指针 引领程序灵魂的精准指引 在计算机编程中 指针是一种强大而又常用的概念 它具备着引领和指引程序执行流程的作用 为我们开辟了更加广阔的编程世界 在本文中 我们将深入探讨指针的基本概念 使用方法和示例代码 帮助您更好地理解和运用指针 一 指
  • [leetcode] 2039. 网络空闲的时刻

    题目链接 题意 给定一张n个点不含重边的无向图 点的编号从0开始到n 1 两点之间如果有连边 可以认为耗时为1秒 1 gt n 1的点都需要向0号点发送消息 从第0秒开始 在0号收到消息之后 会回复消息 从第一秒开始 如果1 gt n 1号
  • django2.2 通过redis 存储session

    1 安装pip install django redis 2 配置setting文件 vi setting py 配置session使用redis CACHES default BACKEND django redis cache Redi
  • Python 2.7(3.x)以及numpy、matplotlib和scipy库三种方法实战安装

    Python是目前十分流行的跨平台编程语言 由于其具有优美简洁的特性以及简单的语法 同时支持工程应用 因而得到了越来越多的关注 Ubuntu下python和其比较常用的库 比如numpy matplotlib和scipy都是比较容易安装的
  • Visual Studio开发Qt5.12.3,使用QChartView widget时报错问题

    Visual Studio开发Qt5 12 3 使用QChartView widget时报错问题 使用场景 在Visual studio2017上开发Qt5 12 3项目 在ui界面上将一个QWidget提升为QChartView作为图标展
  • HTML之表格篇-表格嵌套表格

    嵌套表格一 效果如图所示 代码如下
  • jar包加密程序,防止反编译

    本窗体程序基于开源项目xjar https gitee com core lib xjar tree 2 1 1 src main java io xjar 1 pom文件
  • waf 绕过之[RoarCTF 2019]Easy Calc1(还运用了chr代替)

    打开题目 查看源码 发现有PHP文件 打开发现 这是一道审计代码传参题 需要构造num 然而num不允许传字母进去 会报错 这就为什么会有WAF的知识呢 不懂 然后WAF的绕过 在num前加空格就可以了 这样waf就找不到num这个变量了
  • __dict__属性

    dict 是 Python 中的一个特殊属性 通常存在于大多数 Python 对象中 用于存储该对象的可变属性 以下是关于 dict 的一些关键点和详细信息 存储属性 对于大多数自定义的 Python 对象 dict 属性包含了这个对象的属
  • 信息学奥赛一本通C++语言——1163:阿克曼(Ackmann)函数

    题目描述 阿克曼 Ackmann 函数A m n 中 m n定义域是非负整数 m 3 n 10 函数值定义为 a k m m n n 1 m 0 时 a k m m 1 1 m gt 0 n 0 时 a k m m 1 a k m m
  • GNN论文周报|来自北航、港大、UIUC等机构前沿论文研究

    图神经网络 GNN 是一类专门针对图结构数据的神经网络模型 在社交网络分析 知识图谱等领域中取得了不错的效果 近来 相关研究人员在GNN的可解释性 架构搜索 对比学习等方面做了很多探究 本周精选了10篇GNN领域的优秀论文 来自北航 港大
  • 算法基础:素数环

    题目描述 一个环由n个圈组成 将自然数1 n放入圈内 使得任意相邻圈的两个数之和均为素数 第一个圈的元素均为1 下图为n 6时的一个例子 程序样例 输入为一个整数n 6 8 输出分别为 1 4 3 2 5 6 1 6 5 2 3 4 1 2
  • window10 几款好用的屏幕录制制作动图工具

    有时候静态图片不能够展示交互效果 需要录制一下视频 所以就去网上找了几个好用的屏幕录制软件 一 GifCam GifCam录制视频很方便 打开软件 将窗口拖动到需要录制的地方 点击 Rec 就可以开始录制 在录制的过程中 可以随意的改变窗口
  • SpringBoot之RESTful 接口的实现以及Postman的使用

    SpringBoot实现Restful以及Postman的使用 1 HTTP相关知识 1 1 HTTP 工作原理 1 2 HTTP请求过程 1 3 HTTP请求的方法 2 Restful接口的使用 2 1 Restful风格API 2 2
  • c++随笔-删除文件

    c 删除文件非常简单 只需remove 文件名 即可 需要包含 include
  • java servlet json_Java HttpServlet Json 数据交互

    Android 对其访问进行封装 服务端 packagecom server importjava io PrintWriter importjavax servlet annotation WebServlet importjavax s
  • Rabbit的工作(2)【牛客练习赛36_C + dp背包】

    题目链接 那么的巧合 竟是这题的原题 就是 我们既然一定要选取K个任务 就先去取K个任务 然后逐一加上需要的额外天数即可 include
  • 上采样和下采样层 nn.pixelshuffle and nn.pixelunshuffle

    前言 理论部分后面有空的时候补一下 这里先放代码和简要说明 Downsample 这里先对channel维度降低为原来 1 2 1 2 1 2 然后再对channel维度提升 r
  • 高级JAVA开发 MQ部分

    高级JAVA开发 MQ部分 MQ MQ的作用 为什么要用MQ 常见的MQ的优缺点 使用MQ带来的问题以及处理办法 MQ带来的问题列举 消息重复消费 幂等 问题 消息丢失问题 消息顺序性问题 消息过期丢失 大量积压等问题 如何保证MQ高可用性