分布式消息通信ActiveMQ
消息中间件
消息中间件是指利用高效可靠的消息传递机制进行平台无关的数据交流,并且基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,可以在分布式架构下扩展进程之间的通信。
消息中间件能做什么
消息中间件主要解决分布式系统之间消息的传递问题 ,能够屏蔽各种平台以及协议之间的特性,实现应用之间的协同。
示例:
电商平台中的注册功能,用户注册不单是向数据库insert,可能还需要赠送积分,发送邮件,发送短信等系列操作。
假如:每个操作都耗时1s,那么注册过程就需要耗时4s才能响应给用户。从注册这个服务可以看出,每个子操作都是独立的,同时,基于领域划分以后,它们都属于不同的子域。所以我们可以对这些子操作实现异步化操作。类似多线程并行处理。
如何实现异步化?用多线程能实现吗?多线程当然可以实现,只是,消息的持久化、消息的重发这些条件,多线程 并不能满足.所以需要借助一些开源的消息中间件来解决。 而分布式消息队列就是一个很好的解决办法。通过引入分布式队列,大大提升程序的处理效率,并且还解决了各个模块之间的耦合问题。
分布式消息队列解决的场景:
引入消息中间件后(异步处理),电商平台中的注册架构图变为
电商中的秒杀:
用户提交过来的请求,先写入消息队列。消息队列是有长度的,如果消息队列超过指定长度,直接抛弃。
秒杀的 具体核心处理业务,接收消息队列中消息进行处理。这里的消息处理能力取决于消费端本身的吞吐量。
解耦、异步化、流量整形、数据的最终一致性(最大化的重试完成数据一致性)
ActiveMQ 简介
ActiveMQ
ActiveMQ 是完全基于JMS 规范实现的一个消息中间件产品,是Apache 开源基金会研发的消息中间件。ActiveMQ 主要应用在分布式系统架构中,帮助构建高可用、高性能、可伸缩的企业级面向服务的系统。
ActiveMQ 特性
多语言和协议编写客户端
语言:Java、C、C++、C#、Ruby、Perl、Python、PHP
协议:openwire、stomp、REST、ws、notification、xmpp、AMQP
完全支持JMS1.1和J2EE1.4规范
对Spring的支持,ActiveMQ可以很容易的嵌入到spring模块中
ActiveMQ 下载安装启动
下载地址
http://activemq.apache.org/activemq-5158-release.html
解压
tar -zxvf apache-activemq-5.15.8-bin.tar.gz
启动服务
cd apache-activemq-5.15.8/bin
sh activemq start
启动并带指定日志文件 sh activemq start > /tmp/activemqlog
关闭服务
sh activemq stop
监控地址
http://192.168.15.134:8161/admin/ admin admin
ActiveMQ 的端口61616
默认为61616
检查是否成功启动ActiveMQ
netstat -an|grep 61616
JMS 基本概念和模型
JMS的定义
JMS(Java Message Service) :面向消息中间件的API
MOM(Message Oriented Middleware):面向消息中间件
Java 消息服务是Java平台中关于面向消息中间件的API,用于两个程序 之间,或者分布式系统中发送消息,进行异步通信。
JMS 是一个与具体平台无关的API,绝大多数MOM 提供商都对JMS提供了支持。ActiveMQ就是其中的一个实现。
MOM
MOM 是面向消息的中间件,使用消息传送提供者来协调消息传送操作。 MOM 需要提供API和管理工具。客户端使用API调用,把消息发送到由提供者管理的目的地。在发送消息后,客户端会继续执行其他工作,并且在接收方收到这个消息确认之前,提供者一直保留该消息。
MOM 的特点
消息异步接收,发送者不需要等待消息接受者响应
消息可靠接收,确保消息中间件可靠保存。只有接收方收到消息后才删除消息
开源JMS提供商
JbossMQ(jboss4)、Jboss messaging(jboss5)、joram、ubermq、mantamq、openjms ...
JMS 规范
JMS 规范的目的是为了使得Java 应用程序能够访问现有MOM(消息中间件)系统,形成一套统一的标准规范,解决不同消息中间件之间的协作问题。
不同消息的传递域,点对点消息传送和发布/订阅消息传送
提供接收同步和异步消息的工具
对可靠消息传送的支持
常见消息格式,例如流、文本和字节
JMS 的体系结构
JMS 的基本功能
JMS 的基本功能是用于和面向消息中间件相互通信的应用程序的接口
消息传递域
p2p(point-2-point) 点对点消息传递域
每个消息只能有一个消费者(离线存储)
类似QQ聊天的私聊
生产者和消费者之间没有时间上的相关性,无论消费者在生产者发送消息的时候是否处于运行状态,都可以提取消息
如果session关闭时,有一些消息已经被收到,但是没有被签收,消费者下一次连接到相同对列时,这些消息仍然会被接收
如果用户在receive 方法中设定了消息的选择条件(消息过滤)
如果是持久化消息,消息会被持久化保存,直到消息被签收
发布订阅(publish/subscribe)消息传递域
每个消息有多个消费者
类似QQ群聊
生产者和消费者有时间上的相关性
订阅一个主题的消费者只能消费自它订阅之后发布的消息。
JMS 规范允许客户创建持久订阅,一定程度上降低了时间的相关性要求
持久订阅允许消费者消费它在未处于激活状态时发送的消息
持久化订阅和非持久化订阅
在非持久化订阅的前提下,不能恢复或者重新指派一个未签收的消息;
如果所有消息必须要签收,则使用持久订阅
消息的组成
消息头(Header)
消息头包含消息的识别信息和路由信息
消息头包含一些标准的属性:
JMSDestination
消息发送的目的地,queue或者topic
JMSDeliveryMode
传送模式,持久化模式和非持久模式
JMSPrority
消息优先级(优先级分为10个级别,从0最低-9最高)
如果不设定优先级,默认级别4,需要注意的是,JMS Provider 并不一定保证按照优先级的顺序提交
JMSMessageID
唯一识别每个消息的标识
消息体
就是我们需要传递的消息的内容
JMS API定义了5种消息体格式:
TextMessage
java.lang.String 对象,如xml文件内容
MapMessage
名/值对的集合,名是String 对象,值可以是Java 任何基本类型
BytesMessage
字节流
StreamMessage
Java 中的输入输出流
ObjectMessage
Java 中的可序列化对象
Message
没有消息体,只有消息头和属性
消息的属性
按类型分为:
应用设置的属性
Message.setStringProperty(key,value);
标准属性
使用“JMSX” 作为属性名的前缀
消息中间件定义的属性
JMS Provider 特定的属性
JMS 的可靠机制
消息的确认方式
消息的处理阶段:
客户端接收消息
客户端处理消息
消息被确认
会话存在两种机制:
事务性会话
createSession(boolean transacted, int acknowledgeMode)
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
session.commit() //消息被确认 事务提交意味着生产的所有消息被发送,消费的所有消息被确认
session.rollback(); //重新处理 消息没有被提交,没有被处理,消费端的所有消息被恢复,并且重新被提交, 表示一个事务结束, 另一个事务会开始。事务回滚意味着生产的所有消息被销毁,消费的所有消息 被恢复并重新提交,除非它们已经过期
通过session.commit() //完成事务的签收
非事务性会话
transacted 设置为FALSE
Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
客户端签收模型
Session session = connection.createSession(Boolean.FALSE, Session.CLIENT_ACKNOWLEDGE);
那么需要手动签收
textMessage.acknowledge();
客户端延迟确认,消息可能重复消费
Session session = connection.createSession(Boolean.FALSE, DUPS_OK_ACKNOWLEDGE);
事务性的自动确认
非事务性的自动确认和手动确认
消息的持久化存储
持久化(存储在数据库或磁盘)
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
对于持久消息,消息提供者会使用存储-转发机制,先将消息存储到稳定的介质中,等消息发送成功后再删除。如果JMS Provider 宕机,那么这些未送达的消息则不会丢失,JMS Provider 恢复正常后,会重新读取这些消息,并传送给对应的消费者。
非持久化(存储在内存中)
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
对于非持久化消息,JMS Provider 不会将它存到文件、数据库等稳定介质中。也就是说非持久消息,存储在内存中,如果JMS Provider 宕机,那么非持久化消息会丢失。
持久订阅
持久订阅者和非持久订阅者针对的Domain 是Pub/Sub,而不是P2P
当Broker 发送消息给订阅者时,如果订阅者处于未激活状态,持久订阅者可以收到消息,而非持久订阅者则收不到消息。
当持久订阅者处于未激活状态时,Broker 需要为持久订阅者保存消息,如果持久订阅者订阅的消息太多则会溢出。
持久订阅时,客户端向JMS 服务器注册一个自己身份的ID, 当这个客户端处于离线时,JMS Provider 会为这个ID 保存所有发送到主题的消息,当客户再次连接到 JMS Provider时,会根据自己的ID得到所有当自己处于离线时发送到主题的消息。
持久订阅的方式(消费端)
connection.setClientID("test");
Topic destination=session.createTopic("myTopic");
MessageConsumer consumer=session.createDurableSubscriber(destination,"test");
JMS 规范结合ActiveMQ 实现消息发送
案例架构图
示例代码
引入Jar 包
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.8</version>
</dependency>
生产端
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class JMSQueueProducer {
public static void main(String args[]) {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.15.134:61616");
Connection connection = null;
try {
connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//创建目的地
Destination destination = session.createQueue("myQueue");
//创建发送者
MessageProducer producer = session.createProducer(destination);
//持久化
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
TextMessage textMessage = session.createTextMessage("Hello,World");
producer.send(textMessage);
session.commit();
session.close();
} catch (JMSException e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
}
消费端
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
import javax.xml.soap.Text;
public class JMSQueueConsumer { public static void main(String args[]) {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.15.134:61616");
Connection connection = null;
try {
connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);
//创建目的地
Destination destination = session.createQueue("myQueue");
//创建接收者
MessageConsumer consumer = session.createConsumer(destination);
//接收消息 阻塞方式监听消息
TextMessage textMessage =(TextMessage) consumer.receive();
System.out.println(textMessage.getText());
session.commit(); //表示消息被自动确认
session.close();
} catch (JMSException e) {
e.printStackTrace();
}finally {
if(connection!=null)
{
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
}
分布式消息通信ActiveMQ的更多相关文章
- 分布式消息通信(ActiveMQ)
分布式消息通信(ActiveMQ) 应用场景 异步通信 应用解耦 流量削峰 # ActiveMQ安装 下载 http://activemq.apache.org/ 压缩包上传到Linux系统 apac ...
- 分布式消息通信之RabbitMQ_01
目录 官网 1. RabbitMQ安装 1.1 Window版安装 1.2 Linux版安装 2. 典型应用场景 3. 基本介绍 3.1 AMQP协议 3.2 RabbitMQ的特性 3.3 工作模型 ...
- 分布式消息通信Kafka-原理分析
本文目标 TopicPartition 消息分发策略 消息消费原理 消息的存储策略 Partition 副本机制 1 关于 Topic 和 Partition 1.1 Topic 在 kafka 中, ...
- 分布式消息通信之RabbitMQ Tutorials
目录 官网 1 Hello World! 1.1 生产者demo producer 1.2 消费者demo consumer 1.3 查看queue队列中的信息 页面查看,可看到有4条消息 命令查看 ...
- 分布式消息通信之RabbitMQ_Note
目录 1. RabbitMQ 安装 2. RabbitMQ 应用场景,特性 3. 官网入门指引 4. RabbitMQ 工作模型 5. RabbitMQ 主要的几种交换机类型 6. Java API的 ...
- 分布式消息通信之RabbitMQ_02
目录 1. 可靠性投递分析 1.1 消息投递 1.2 消息路由 1.3 消息存储 1.4 消息消费 1.5 其他 2. 高可用架构部署方案 2.1 集群 2.2 镜像 3. 经验总结 3.1 配置文件 ...
- 使用ActiveMQ实现JMS消息通信服务
PTP(点对点的消息模型) 在点对点模型中,相当于两个人打电话,两个人独享一条通信线路.一方发送消息,一方接收消息. 在p2p的模型中,双方通过队列交流,一个队列只有一个生产者和一个消费者. 1.建立 ...
- Netty构建分布式消息队列实现原理浅析
在本人的上一篇博客文章:Netty构建分布式消息队列(AvatarMQ)设计指南之架构篇 中,重点向大家介绍了AvatarMQ主要构成模块以及目前存在的优缺点.最后以一个生产者.消费者传递消息的例子, ...
- 消息通信库ZeroMQ 4.0.4安装指南
一.ZeroMQ介绍 ZeroMQ是一个开源的消息队列系统,按照官方的定义,它是一个消息通信库,帮助开发者设计分布式和并行的应用程序. 首先,我们需要明白,ZeroMQ不是传统的消息队列系统(比如Ac ...
随机推荐
- Nodejs + express post get 参数获取小结
req.params.xxxxx 从path中的变量 req.query.xxxxx 从get中的?xxxx=中 req.body.xxxxx 从post中的变量 Post下别忘了: app.use( ...
- Google APAC----Africa 2010, Qualification Round(Problem A. Store Credit)----Perl 解法
原题地址链接:https://code.google.com/codejam/contest/351101/dashboard#s=p0 问题描述: Problem You receive a cre ...
- 命令行下运行 java someClass.class出现 “错误:找不到或无法加载主类someClass ” 的解决方案
假设在C:\Java\code\目录下建立了如下 Test.java文件: package code; public class Test { public static void main(Stri ...
- javascript的 热点图怎么写
在gis中,你如果用js来写热点图 不借助后台怎么搞,as的话比较容易有相应的类库甚至官方都有.而且用js不借助arcgis发布rest服务,(注:热点图可以借助服务的形式发布,arcgis for ...
- Vue小案例(一)
案例需求: 创建一个品牌展示表格,表头有编号(id),品牌名称(name),创建时间(time)和操作,需要实现的功能是对数据的增删操作,和时间的格式化. 思路分析:在开发之前需要想清楚要用到Vue中 ...
- github连接提示
解决办法: 1,将连接方式从http更换为ssh.注意,github.com后面一定有(冒号): git remote rm origin git remote add origingit@githu ...
- linux Mint 安装网易云音乐
第一天从官网下来了最新版netease-cloud-music_1.1.0_amd64_ubuntu.deb安装,用的挺好的,第二天就打不开了郁闷,查了下很多人都遇到了这样的问题,需要root权限运行 ...
- 面向对象进阶------>模块 json pickle hashlib
何为模块呢? 其实模块就是.py文件 python之所以好用就是模块多 模块分三种 : 内置模块 . 拓展模块.自定义模块. 现在我们来认识:内置模块中的 序列化模块和 hashlib 模块 1 ...
- 【转】snmpwalk常用用法
在日常监控中,经常会用到snmp服务,而snmpwalk命令则是测试系统各种信息最有效的方法,现总结一些常用的方法如下: 1.snmpwalk -v 2c -c public 10.103.33.1 ...
- 创建 In-app Billing 商品
创建可供购买的 In-app Billing 商品 在你发布 In-app Billing 应用前,你需要在 Google Play 开发者控制台 定义可供购买的数字商品列表. 在 Google Pl ...