ActiveMQ系列:一个MQ产品的基础知识
1、概要介绍
1.1、MQ是什么?ActiveMQ是什么?AMQP是什么?
消息队列( messagequeuing )使用消息将应用程序连接起来。这些消息通过像RabbitMQ 这样的消息代理服务器在应用程序之间路由。这就像是在应用程序之间放置一个邮局。
ActiveMQ是一个消息代理和队列服务器。Apache ActiveMQ是Apache软件基金会所研发的开放源代码消息中间件;由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行(摘自百度百科)。
AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品、不同开发语言等条件的限制。
1.2、落地的实现(产品)
1.Kafka
2.RabbitMQ
3.RocketMQ
4.ActiveMQ
5.其他
1.3、MQ的主要功能有哪些?
- API 的发送和接收
- MQ 的高可用性
- MQ 的集群以及容错机制配置
- MQ 的持久化
- 延时发送以及定时投递
- 签收机制(防止防重复消费)
- Spring整合、Springboot整合(Java语言方面)
- 其他小模块
1.4、如何学习?
不可否认,市面上MQ消息中间件 “琳琅满目”,不可能把所有的MQ都学习一遍,那么该如何做呢?其实MQ所提供的功能大体类似,只是实现方式有所差异,一个发送方法在ActiveMQ中叫 send(),在RabbitMQ中可能叫 push()...诸如此类,所以要学会融会贯通,所谓 “知己知彼,百战不殆”。
从 1.3 我们可以看出一个 MQ 所有的主要功能几近类似,就可以从一个宏观的角度来学习,称之 “技术维度”。就好比Java 中有连接数据库的功能,Python 肯定也有,只是实现方法不一样,那么就可以以此为切入点,学习完ActiveMQ后,哪天搞大数据需要用到 Kafka 了,从发送、接收开始套入,是不是就比逐个 MQ 产品学习的成本要低很多呢?
2、MQ学习前言
2.1、先抛问题
1.(why)为什么要在系统里引入消息中间件
2.(how)在何种情景下引入消息中间件
3.其他等等等
2.2、小案例(以学生提问问题为例)
(阻塞式提问):首先,A 学生遇到问题,请教老师,占用5分钟;B 学生也遇到问题,也需要占用5分钟;C 学生也遇到问题,也需要占用5分钟。。。但此时,A 学生还未用完5分钟,导致后面的学生一直在无限等待,老师也没办法上课。
(引入MQ):首先,老师给出规定的提问问题格式(消息的格式约定),学生遇到问题按照给定格式,提交到班长,由班长一 一 投递给老师,学生提交后即可回去,等待老师解决。
2.3、引入MQ后的好处
1.解决了耦合调用的问题(同一个问题可能有N个学生提问)
2.异步模型(学生提交完后即可回去学习,无需无限等待)
3.抵御洪峰流量,达到保护主业务的目的,也即削峰
4.其他等等等
2.4、系统之间直接调用实际工程落地和存在的问题
微服务架构后,链式调用是我们在写程序时候的一般流程,为了完成一个整体功能会将其拆分成多个函数(或子模块),
比如模块A调用模块B,模块B调用模块C,模块c调用模块D。但在大型分布式应用中,系统间的RPC交互繁杂,一个功能
背后要调用上百个接口并非不可能,从单机架构过渡到分布式微服务架构的通例,这种架构会有哪些问题???
总的来讲就是:
1.系统之间接口耦合比较严重
2.面对大流量并发时,容易被冲垮
3.等待同步存在性能问题
那么,你是如何解决的?
2.5、系统之间接口耦合比较严重
1、每新增一个下游功能,都要对上有的相关接口进行改造;举个例子:假如系统A要发送数据给系统B和C,发送给每个系统的数据可能有差异,因此系统A对要发送给每个系统的数据进行了组装,然后逐一发送;
2、当代码上线后又新增了一个需求:
把数据也发送给D,新上了一个D系统也要接受A系统的数据。此时就需要修改A系统,让他感知到D的存在,同时把数据处理好再A给D。在这个过程中你会看到,每接入一个下游系统,都要对A系统进行代码改造,开发联调的效率很低。其整体
架构如下图:
2.6、面对大流量并发时,容易被冲垮
每个接口模块的吞吐能力是有限的,这个上限能力如果堤坝,当大流量(洪水)来临时,容易被冲垮。
举个栗子:
上游系统发起下单购买操作,我就是下单一个操作,下游系统完成秒杀业务逻辑(读取订单,库存检查,库存冻结,余额
检查,余额冻结,订单生成,余额扣减,库存扣减,生成流水,余额解冻,库存解冻)
2.7、等待同步存在性能问题
RPC接口基本上是同步调用,整体的服务性能遵循“木桶理论”,即整体系统的耗时取决于链路中最慢的那个接口。比如A调用B/C/D都是50ms,但此时B又调用了B1,花费2000ms,那么直接就拖累了整个服务性能。
2.8、此时,需要有能够摆平上述情况的解决方案
1、要做到系统解耦,当新的模块接进来时,可以做到代码改动最小;能够解耦
2、设置流量缓冲池,可以让后端系统按照自身吞吐能力进行消费,不被冲垮;能够削峰
3、强弱依赖梳理能将非关键调用链路的操作异步化并提升整体系统的吞吐能力;能够异步
3、面向消息的中间件(message-oriented middleware)能够很好解决以上问题
3.1、MOM是什么
利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。
通过提供消息传递和消息排队模型在分布式环境下提供应用解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步等功能。
大致的过程是这样的:
发送者把消息发送给消息服务器,消息服务器将消息存放在若干队列/主题中,在合适的时候,消息服务器会将消息转发给接受者。在这个过程中,发送和接受是异步的,也就是发送无需等待,而且发送者和接受者的生命周期也没有必然关系;
尤其在发布pub/订阅sub模式下,也可以完成一对多的通信,即让一个消息有多个接受者。
消息发送者可以发送一个消息而无须等待响应。消息发送者将消息发送到一条虚拟的通道(主题或队列)上;
消息接收者则订阅或监听该通道。一条信息可能最终转发给一个或多个消息接收者,这些接收者都无需对消息发送者做出同步回应。整个过程都是异步的。
案例:
也就是说,一个系统跟另外一个系统之间进行通信的时候,假如系统A希望发送一个消息给系统B,让他去处理。
但是系统A不关注系统B到底怎么处理或者有没有处理好,所以系统A把消息发送给MQ,然后就不管这条消息的“死活”了,接着系统B从MQ里消费出来处理即可。至于怎么处理,是否处理完毕,什么时候处理,都是系统B的事儿,与系统A无关。
这样的一种通信方式,就是所谓的“异步”通信方式对于系统A来说,只要把消息发给MQ,然后系统B就会异步的去进行处理了,系统A不需要“同步”的等待系统B处理完。这样的好处是什么呢?两个字:解耦
4、ActiveMQ 能干嘛?
4.1、为什么是ActiveMQ?
1.实现高可用、高性能、可伸缩、易用和安全的企业级面向消息服务的系统
2.异步消息的消费和处理
3.控制消息的消费顺序
4.可以和spring/springboot整合简化编码
5.配置集群容错的MQ集群
6.其他等等等
4.2、其他MQ也可以做到诸如此类的功能,但 ......
1.Kafka:适用于大数据处理
2.RabbitMQ:底层为erlang语言,你能看得懂源码麽。。。
3.RocketMQ:阿里用Java基于Kafka以及ActiveMQ重写的消息中间件,虽经过双十一考研,但某一天突然跟Dubbo一样不再维护了呢?Who know?
5、安装步骤
1.官网下载
2./opt 目录下面(个人喜好)
3.解压缩 apache-activemq-5.15.9-bin.tar.gz
4.在根目录下 mkdir /myactiveMQ
5.cp -r apache-activemq-5.15.9/myactiveMQ/
6.普通启动mq: ./activemq start/stop
7.activemq的默认进程端口是61616(netstat -anplgrep 61616)/(lsof-i:61616)
8.查看后台进程(ps -ef | grep activemq|grep-v grep)
9.带运行日志启动(./activemq start > /myactiveMQ/run_activemq.log)
10.浏览器打开 http://IP:8161/admin (默认账号密码是:admin/admin)
6、在 IDEA 中使用ActiveMQ
6.1、总体流程
1.IDEA 创建 MAVEN 工程
2.pom.xml 引入依赖
3.JMS编码规范
4.创建队列生产者
5.创建队列消费者
6.创建主题生产者
7.创建主题消费者
6.2、JMS编码规范
JMS(Java Messaging Service)规范,本质是API,Java平台消息中间件的规范,java应用程序之间进行消息交换。并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。对应的实现ActiveMQ
6.3、先回忆下JDBC链接数据库的步骤
第1步:注册驱动(仅仅做一次)Class.forName(“com.mysaql.jdbc.Driver”);
第2步:建立连接(Connection)Connection conn=DriverManager.getConnection(url,user,password);
第3步:创建运行SQL的语句(Statement)Statement st=connection.createStatement();
第4步:运行语句 ResultSet rs =st.executeQuery(sql);
第5步:处理运行结果(ResultSet)省略……
第6步:释放资源 省略…
6.4、消息也需要有目的地
一如Java中 new 一个对象,new 了之后该对象就会存在堆内存中,消息产生之后也需要到对应的目的地(无论是队列还是主题),否则就会成为死信
6.5、队列和主题两大模式
队列模式
主题模式
未完待续................(下篇开始撸码)