MQ

Message Queue,消息队列,FIFO 结构。

例如电商平台,在用户支付订单后执行对应的操作;

优点:

  • 异步
  • 削峰
  • 解耦

缺点

  • 增加系统复杂性
  • 数据一致性
  • 可用性

JMS

Java Message Service,Java消息服务,类似 JDBC 提供了访问数据库的标准,JMS 也制定了一套系统间消息通信的规范;

区别于 JDBC,JDK 原生包中并未定义 JMS 相关接口。

  1. ConnectionFactory

  2. Connection

  3. Destination

  4. Session

  5. MessageConsumer

  6. MessageProducer

  7. Message

协作方式图示为;

业界产品

ActiveMQ RabbitMQ RocketMQ kafka
单机吞吐量 万级 万级 10 万级 10 万级
可用性 非常高 非常高
可靠性 较低概率丢失消息 基本不丢 可以做到 0 丢失 可以做到 0 丢失
功能支持 较为完善 基于 erlang,并发强,性能好,延时低 分布式,拓展性好,支持分布式事务 较为简单,主要应用与大数据实时计算,日志采集等
社区活跃度

ActiveMQ

作为 Apache 下的开源项目,完全支持 JMS 规范。并且 Spring Boot 内置了 ActiveMQ 的自动化配置,作为入门再适合不过。

快速开始

添加依赖;

<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.7.0</version>
</dependency>

消息发送;

// 1. 创建连接工厂
ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
// 2. 工厂创建连接
Connection connection = factory.createConnection();
// 3. 启动连接
connection.start();
// 4. 创建连接会话session,第一个参数为是否在事务中处理,第二个参数为应答模式
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 5. 根据session创建消息队列目的地
Destination queue = session.createQueue("test-queue");
// 6. 根据session和目的地queue创建生产者
MessageProducer producer = session.createProducer(queue);
// 7. 根据session创建消息实体
Message message = session.createTextMessage("hello world!");
// 8. 通过生产者producer发送消息实体
producer.send(message);
// 9. 关闭连接
connection.close();

Spring Boot 集成

自动注入参考:org.springframework.boot.autoconfigure.jms.activemq.ActiveMQConnectionFactoryConfiguration.SimpleConnectionFactoryConfiguration

添加依赖;

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>

添加 yaml 配置;

spring:
activemq:
broker-url: tcp://localhost:61616
jms:
#消息模式 true:广播(Topic),false:队列(Queue),默认时false
pub-sub-domain: true

收发消息;

@Autowired
private JmsTemplate jmsTemplate; // 接收消息
@JmsListener(destination = "test")
public void receiveMsg(String msg) {
System.out.println(msg);
} // 发送消息
public void sendMsg(String destination, String msg) {
jmsTemplate.convertAndSend(destination, msg);
}

高可用

基于 zookeeper 实现主从架构,修改 activemq.xml 节点 persistenceAdapter 配置;

<persistenceAdapter>
<replicatedLevelDB
directory="${activemq.data}/levelDB"
replicas="3"
bind="tcp://0.0.0.0:0"
zkAddress="172.17.0.4:2181,172.17.0.4:2182,172.17.0.4:2183"
zkPath="/activemq/leveldb-stores"
hostname="localhost"
/>
</persistenceAdapter>

broker 地址为:failover:(tcp://192.168.4.19:61616,tcp://192.168.4.19:61617,tcp://192.168.4.19:61618)?randomize=false

负载均衡

在高可用集群节点 activemq.xml 添加节点 networkConnectors;

<networkConnectors>
<networkConnector uri="static:(tcp://192.168.0.103:61616,tcp://192.168.0.103:61617,tcp://192.168.0.103:61618)" duplex="false"/>
</networkConnectors>

更多详细信息可参考:https://blog.csdn.net/haoyuyang/article/details/53931710

集群消费

由于发布订阅模式,所有订阅者都会接收到消息,在生产环境,消费者集群会产生消息重复消费问题。

ActiveMQ 提供 VirtualTopic 功能,解决多消费端接收同一条消息的问题。于生产者而言,VirtualTopic 就是一个 topic,对消费而言则是 queue。

在 activemq.xml 添加节点 destinationInterceptors;

<destinationInterceptors>
<virtualDestinationInterceptor>
<virtualDestinations>
<virtualTopic name="testTopic" prefix="consumer.*." selectorAware="false"/>
</virtualDestinations>
</virtualDestinationInterceptor>
</destinationInterceptors>

生产者正常往 testTopic 中发送消息,订阅者可修改订阅主题为类似 consumer.A.testTopic 这样来消费。

更多详细信息可参考:https://blog.csdn.net/java_collect/article/details/82154829

RocketMQ

是一个队列模型的消息中间件,具有高性能、高可靠、高实时、分布式特点。

架构图示

  1. Name Server

    名称服务器,类似于 Zookeeper 注册中心,提供 Broker 发现;

  2. Broker

    RocketMQ 的核心组件,绝大部分工作都在 Broker 中完成,接收请求,处理消费,消息持久化等;

  3. Producer

    消息生产方;

  4. Consumer

    消息消费方;

快速开始

安装后,依次启动 nameserver 和 broker,可以用 mqadmin 管理主题、集群和 broker 等信息;

https://segmentfault.com/a/1190000017841402

添加依赖;

<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.5.2</version>
</dependency>

消息发送;

DefaultMQProducer producer = new DefaultMQProducer("producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.setInstanceName("producer");
producer.start();
Message msg = new Message(
"producer-topic",
"msg",
"hello world".getBytes()
);
//msg.setDelayTimeLevel(1);
SendResult sendResult = producer.send(msg);
System.out.println(sendResult.toString());
producer.shutdown();

delayLevel 从 1 开始默认依次是:1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h。

参考 org.apache.rocketmq.store.schedule.ScheduleMessageService#parseDelayLevel。

消息接收;

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer-group");
consumer.setNamesrvAddr("127.0.0.1:9876");
consumer.setInstanceName("consumer");
consumer.subscribe("producer-topic", "msg");
consumer.registerMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> {
for (MessageExt msg : list) {
System.out.println(new String(msg.getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
consumer.start();

.\mqadmin.cmd sendMessage -t producer-topic -c msg -p "hello rocketmq" -n localhost:9876

Spring Boot 集成

添加依赖;

<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>

添加 yaml 配置;

rocketmq:
name-server: 127.0.0.1:9876
producer:
group: producer

发送消息;

@Autowired
private RocketMQTemplate mqTemplate; public void sendMessage(String topic, String tag, String message) {
SendResult result = mqTemplate.syncSend(topic + ":" + tag, message);
System.out.println(JSON.toJSONString(result));
}

接收消息;

@Component
@RocketMQMessageListener(consumerGroup = "consumer", topic = "topic-test", selectorExpression = "tag-test")
public class MsgListener implements RocketMQListener<String> { @Override
public void onMessage(String message) {
System.out.println(message);
}
}

Console 控制台

RocketMQ 拓展包提供了管理控制台;

https://github.com/apache/rocketmq-externals/tree/master/rocketmq-console

重复消费

产生原因:

  1. 生产者重复投递;
  2. 消息队列异常;
  3. 消费者异常消费;

怎么解决重复消费的问题,换句话怎么保证消息消费的幂等性

通常基于本地消息表的方案实现,消息处理过便不再处理。

顺序消息

消息错乱的原因:

  1. 一个消息队列 queue,多个 consumer 消费;
  2. 一个 queue 对应一个 consumer,但是 consumer 多线程消费;

要保证消息的顺序消费,有三个关键点:

  1. 消息顺序发送
  2. 消息顺序存储
  3. 消息顺序消费

参考 RocketMq 中的 MessageQueueSelector 和 MessageListenerOrderly。

分布式事务

在分布式系统中,一个事务由多个本地事务组成。这里介绍一个基于 MQ 的分布式事务解决方案。

通过 broker 的 HA 高可用,和定时回查 prepare 消息的状态,来保证最终一致性。

MQ 入门实践的更多相关文章

  1. 分布式学习系列【dubbo入门实践】

    分布式学习系列[dubbo入门实践] dubbo架构 组成部分:provider,consumer,registry,monitor: provider,consumer注册,订阅类似于消息队列的注册 ...

  2. sass、less和stylus的安装使用和入门实践

    刚 开始的时候,说实话,我很反感使用css预处理器这种新玩意的,因为其中涉及到了编程的东西,私以为很复杂,而且考虑到项目不是一天能够完成的,也很少是 一个人完成的,对于这种团队的项目开发,前端实践用c ...

  3. WebSphere MQ 入门指南

    WebSphere MQ 入门指南这是一篇入门指南.我们从最基本的概念说起: 基础概念 对于MQ,我们需要知道4个名词:队列管理器.队列.消息.通道:对于编程设计人员,通常更关心消息和队列,对于维护管 ...

  4. Django入门实践(三)

    Django入门实践(三) Django简单应用 前面简单示例说明了views和Template的工作过程,但是Django最核心的是App,涉及到App则会和Model(数据库)打交道.下面举的例子 ...

  5. Django入门实践(二)

    Django入门实践(二) Django模板简单实例 上篇中将html写在了views中,这种混合方式(指Template和views混在一起)不适合大型开发,而且代码不易管理和维护,下面就用Djan ...

  6. Django入门实践(一)

    Django入门实践(一) Django编程思路+入门 认识Django有一个多月了,我觉得学习Django应该先理清它的编程思路.它是典型的MVC框架(在Django里也称MTV),我觉得Djang ...

  7. WebSphere MQ 入门指南【转】

    WebSphere MQ 入门指南 转自 WebSphere MQ 入门指南 - 大CC - 博客园http://www.cnblogs.com/me115/p/3456407.html 这是一篇入门 ...

  8. 全文搜索引擎Elasticsearch入门实践

    全文搜索引擎Elasticsearch入门实践 感谢阮一峰的网络日志全文搜索引擎 Elasticsearch 入门教程 安装 首先需要依赖Java环境.Elasticsearch官网https://w ...

  9. 【实战】Docker入门实践二:Docker服务基本操作 和 测试Hello World

    操作环境 操作系统:CentOS7.2 内存:1GB CPU:2核 Docker服务常用命令 docker服务操作命令如下 service docker start #启动服务 service doc ...

随机推荐

  1. [转]#include< > 和 #include” ” 的区别

    原文网址:https://www.cnblogs.com/LeoFeng/p/5346530.html 一.#include< > #include< > 引用的是编译器的类库 ...

  2. Ubuntu 下安装Anaconda + 显卡驱动 + CUDA + CUDNN + 离线安装环境

    写来给自己备忘,并不是什么教程- .- 下载安装包 Anaconda:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 显卡驱动:https ...

  3. 解决bs4在python中出现“ImportError: cannot import name ‘HTMLParseError‘”错误

    在使用BeautifulSoup4时候出现了ImportError: cannot import name 'HTMLParseError'的错误. 根本原因是BeautifulSoup在4.4.0以 ...

  4. 将springboot项目部署到服务器的tomcat中无法访问

    第一步:让启动类继承SpringBootServletInitializer,并重写configure方法,关键代码如下 @SpringBootApplication public class MyS ...

  5. 【HTB系列】靶机Vault的渗透测试详解

    出品|MS08067实验室(www.ms08067.com) 本文作者:大方子(Ms08067实验室核心成员) Kali: 10.10.14.213 靶机地址:10.10.10.109 先用nmap探 ...

  6. OSPF“孤儿”区域

    在多区域OSPF中,area0为主干区域,其他非主干区域都需要包含一个接口连接主干区域,那么当出现有的区域不和主干区域相连,成了"孤儿": 解决办法: 虚链路 在连接孤儿区域的路由 ...

  7. 用Vue3构建企业级前端应用,TS能让你更轻松点

    摘要:Vue 3已经发布有一段时间了,到底有哪些新特性值得关注,如何用它构建企业级前端项目,怎样快速上手Vue 3?本篇文章将对此进行详细讲解. 前言 工欲善其事,必先利其器 --<论语> ...

  8. javascript中的内存管理

    目录 简介 内存生命周期 JS中的垃圾回收器 引用计数垃圾回收算法 Mark-and-sweep回收算法 调试内存问题 闭包Closures中的内存泄露 javascript中的内存管理 简介 在c语 ...

  9. LeetCode113. 路径总和 II

    原题链接 1 class Solution: 2 def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]: 3 ans,tm ...

  10. 用于功率集成电路应用的600伏、10安、4H-SIC横向单沟道金属氧化物半导体场效应晶体管的演示和分析

    用于功率集成电路应用的600伏.10安.4H-碳化硅横向单沟道金属氧化物半导体场效应晶体管的演示和分析 摘要: 本文报道了一个具有大电流处理能力(10 A)的600伏4H-碳化硅横向场效应晶体管的演示 ...