消息队列中间件ActiveMQ高级应用
1 MQ(Message Queue)应用场景分析
消息队列中间件是分布式系统中的重要组件,主要解决异步消息,应用解耦,流量削锋等问题,从而实现高性能,高可用,可伸缩和最终一致性的架构
使用较多的消息队列有ActiveMQ,RabbitMQ,Kafka,MetaMQ等
1.1 异步处理
场景说明:用户注册后,需要发送注册邮件和注册短信。传统的做法如下:
将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端
引入消息队列,异步处理。改造后的架构如下:
1.2 应用解耦
场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。如下图
传统模式的缺点:
· 假如库存系统无法访问,则订单减库存将失败,从而导致下单失败
· 订单系统与库存系统耦合
引入消息队列后的方案,如下图:
· 订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户,下单成功
· 库存系统:订阅下单的消息,获取下单信息,库存系统根据下单信息,进行库存操作
· 假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦
1.3 流量削锋
流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中广泛使用
应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。
· 可以控制活动的人数
· 可以缓解短时间内高流量压垮应用
· 用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面
· 秒杀业务根据消息队列中的请求信息,再做后续处理
2 JMS消息模型
2.1 P2P(Point to Point)点对点模式
P2P模式包含三个角色:消息队列(Queue),发送者(Sender),接收者(Receiver)。
每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。
P2P的特点:
l 每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)
l 发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列
l 接收者在成功接收消息之后需向队列应答成功
如果希望发送的每个消息都会被成功处理的话,那么需要P2P模式
2.2 Publish/Subscribe(Pub/Sub) 发布订阅模式
Pub/Sub模式包含三个角色:主题(Topic),发布者(Publisher),订阅者(Subscriber)。
多个发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。
Pub/Sub的特点
l 每个消息可以有多个消费者
l 发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅之后,才能消费发布者的消息
l 为了消费消息,订阅者必须保持运行的状态
为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。
如果希望发送的消息可以被多个消费者处理的话,那么可以采用Pub/Sub模型。
3 ActiveMQ Topic消息失败重发
3.1 JMS消息确认机制
在Session接口中定义的几个常量:
l AUTO_ACKNOWLEDGE = 1 自动确认
l CLIENT_ACKNOWLEDGE = 2 客户端手动确认
l DUPS_OK_ACKNOWLEDGE = 3 自动批量确认
l SESSION_TRANSACTED = 0 事务提交并确认
3.2 代码实现
消息消费端在创建Session对象时需要指定应答模式为客户端手动应答,当消费者获取到消息并成功处理后需要调用message.acknowledge()方法进行应答,通知Broker消费成功。
如果处理过程中出现异常,需要调用session.recover()通知Broker重复消息,默认最多重复6次
4 ActiveMQ Topic消息持久化订阅
4.1 持久化到文件(默认)
第一步:在
a
c
t
i
v
e
m
q
.
b
a
s
e
/
c
o
n
f
/
a
c
t
i
v
e
m
q
.
x
m
l
文
件
中
配
置
持
久
化
适
配
器
<
p
e
r
s
i
s
t
e
n
c
e
A
d
a
p
t
e
r
>
<
k
a
h
a
D
B
d
i
r
e
c
t
o
r
y
=
"
{activemq.base}/conf/activemq.xml文件中配置持久化适配器 <persistenceAdapter><kahaDB directory="
activemq.base/conf/activemq.xml文件中配置持久化适配器<persistenceAdapter><kahaDBdirectory="{activemq.base}/data/kahadb"/>
第二步:在Java代码中发送消息时
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(“tcp://localhost:61616”);Connection connection = connectionFactory.createConnection();connection.start();Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);Topic topic = session.createTopic(“myTopic”);MessageProducer producer = session.createProducer(topic);TextMessage textMessage = session.createTextMessage(“hello world!”);producer.send(textMessage, DeliveryMode.PERSISTENT, 1, 10006060*24);producer.close();session.close();connection.close();
第三步:消息订阅者方创建消费者对象时
connection.setClientID(“client-1”);TopicSubscriber consumer = session.createDurableSubscriber(topic, “client1-sub”);
4.2 持久化到数据库(mysql)
第一步:将MySQL的数据库驱动复制到activeMQ的lib目录下
第二步:在
a
c
t
i
v
e
m
q
.
b
a
s
e
/
c
o
n
f
/
a
c
t
i
v
e
m
q
.
x
m
l
文
件
中
配
置
持
久
化
适
配
器
<
p
e
r
s
i
s
t
e
n
c
e
A
d
a
p
t
e
r
>
<
j
d
b
c
P
e
r
s
i
s
t
e
n
c
e
A
d
a
p
t
e
r
d
a
t
a
D
i
r
e
c
t
o
r
y
=
"
{activemq.base}/conf/activemq.xml文件中配置持久化适配器 <persistenceAdapter><jdbcPersistenceAdapter dataDirectory="
activemq.base/conf/activemq.xml文件中配置持久化适配器<persistenceAdapter><jdbcPersistenceAdapterdataDirectory="{activemq.base}/data" dataSource="#derby-ds"/>
第三步:在${activemq.base}/conf/activemq.xml文件中配置数据源
4.3 测试持久化效果
第一步:启动MQ服务
第二步:启动消费端,需要消费者进行持久化订阅,进行注册
TopicSubscriber consumer = session.createDurableSubscriber(topic, “client1-sub”);
第三步:停止消费者
第四步:生产者发送消息到Topic
第五步:启动消费端,能够获得到消息说明持久化成功
5 zookeeper+activemq集群实现高可用
使用ZooKeeper实现的Master-Slave实现方式,是对ActiveMQ进行高可用的一种有效的解决方案。高可用的原理:使用ZooKeeper(集群)注册所有的ActiveMQ Broker。只有其中的一个Broker可以对外提供服务(也就是Master节点),其他的Broker处于待机状态,被视为Slave。如果Master因故障而不能提供服务,则利用ZooKeeper的内部选举机制从Slave中选举出一个Broker充当Master节点,继续对外提供服务。通过zookeeper+activeMQ实现的集群,可以有效的排除单点故障引起的服务中断。
5.1 环境准备
1、准备三台虚拟机,IP分别为:
192.168.112.128
192.168.112.129
192.168.112.130
2、提供JDK安装包(安装过程略)
3、提供zookeeper和activeMQ安装包
5.2 安装zookeeper
第一步:将下载的zookeeper安装包分别上传到三台虚拟机,分别进行下面操作
第二步:解压安装包
tar –zxvf zookeeper-3.4.10.tar.gz –C /usr/local
第三步:将/usr/local目录下的zookeeper-3.4.10改名
mv zookeeper-3.4.10 zookeeper
第四步:在zookeeper目录下创建两个目录data和logs,分别存放数据和日志
cd /usr/local/zookeeper/
mkdir data
mkdir logs
第五步:将zookeeper/conf目录下的zoo_sample.cfg文件名改为zoo.cfg
cd /usr/local/zookeeper/conf/
mv zoo_sample.cfg zoo.cfg
5.3 安装activeMQ
第一步:将下载的activemq安装包分别上传到三台虚拟机,分别进行下面操作
第二步:解压安装包
tar –zxvf apache-activemq-5.14.0-bin.tar.gz –C /usr/local
第三步:将/usr/local目录下的apache-activemq-5.14.0改名
mv apache-activemq-5.14.0 activemq
5.4 集群配置
第一步:在/usr/local/zookeeper/data下创建myid文件,文件内容为1。同理,其他虚拟机中也创建myid文件,内容分别为2和3
第二步:修改/usr/local/zookeeper/conf/zoo.cfg文件,加入以下内容
dataDir=/usr/local/zookeeper/data/dataLogDir=/usr/local/zookeeper/logsserver.1=192.168.112.128:2888:3888 server.2=192.168.112.129:2888:3888 server.3=192.168.112.130:2888:3888
第三步:分别启动三台zookeeper(需要关闭防火墙)
service iptables stop
/usr/local/zookeeper/bin/zkServer.sh start
第四步:修改/usr/local/activemq/conf目录下的activemq.xml
vim /usr/local/activemq/conf/activemq.xml
修改brokerName=”activemq-cluster”
将文件中持久化适配器改为
注意:其他虚拟机中修改时hostname需要改为对应的ip
第五步:启动mq服务
./activemq start