当前位置: 首页 > news >正文

RocketMQ-快速实战

MQ简介

MQ:MessageQueue,消息队列。是在互联网中使用非常广泛的一系列服务中间件。

Message:消息。消息是在不同进程之间传递的数据。这些进程可以部署在同一台机器上,也可以分布在不同机器上。(数据形式:二进制压缩数据、RPC、http,都属于进程间通讯的机制)

Queue:队列。队列原意是指一种具有FIFO(先进先出)特性的数据结构,是用来缓存数据的。对于消息中间件产品来说,能不能保证FIFO特性,尚值得考量。但是,所有消息队列都是需要具备存储消息,让消息排队的能力。

作用:

  • 异步,提高系统的响应速度、吞吐量。

  • 解耦,减少服务之间的影响。提高系统整体的稳定性以及可扩展性。另外,解耦后可以实现数据分发。生产者发送一个消息后,可以由一个或者多个消费者进行消费,并且消费者的增加或者减少对生产者没有影响。

  • 消峰,以稳定的系统资源应对突发的流量冲击。

RocketMQ产品特点

RocketMQ介绍

RocketMQ是阿里巴巴开源的一个消息中间件,在阿里内部历经了双十一等很多高并发场景的考验,能够处理亿万级别的消息。2016年开源后捐赠给Apache,现在是Apache的一个顶级项目。

早期阿里使用ActiveMQ,但是,当消息开始逐渐增多后,ActiveMQ的IO性能很快达到了瓶颈。于是,阿里开始关注Kafka。但是Kafka是针对日志收集场景设计的,他的高级功能并不是很贴合阿里的业务场景。尤其当他的Topic过多时,由于Partition文件也会过多,这就会加大文件索引的耗时,会严重影响IO性能。于是阿里才决定自研中间件,最早叫做MetaQ,后来改名成为RocketMQ。最早他所希望解决的最大问题就是多Topic下的IO性能压力。但是产品在阿里内部的不断改进,RocketMQ开始体现出一些不一样的优势。

RocketMQ特点

当今互联网MQ产品众多,其中,影响力和使用范围最大的当数Apache Kafka、RabbitMQ、Apache RocketMQ以及Apache Plusar。这几大产品虽然都是典型的MQ产品,但是由于设计和实现上的一些差异,造成他们适合于不同的细分场景。

优点缺点适合场景
Apache Kafka吞吐量非常大,性能非常好,集群高可用。会有丢数据的可能,功能比较单一日志分析、大数据采集
RabbitMQ消息可靠性高,功能全面。erlang语言不好定制。吞吐量比较低。企业内部小规模服务调用
Apache Pulsar基于Bookeeper构建,消息可靠性非常高。周边生态还有差距,目前使用的公司比较少。企业内部大规模服务调用
Apache RocketMQ高吞吐、高性能、高可用。功能全面。客户端协议丰富。使用java语言开发,方便定制。服务加载比较慢。几乎全场景,特别适合金融场景

其中RocketMQ,孵化自阿里巴巴。历经阿里多年双十一的严格考验,RocketMQ可以说是从全世界最严苛的高并发场景中摸爬滚打出来的过硬产品,也是少数几个在金融场景比较适用的MQ产品。从横向对比来看,RocketMQ与Kafka和RabbitMQ相比。RocketMQ的消息吞吐量虽然和Kafka相比还是稍有差距,但是却比RabbitMQ高很多。在阿里内部,RocketMQ集群每天处理的请求数超过5万亿次,支持的核心应用超过3000个。而RocketMQ最大的优势就是他天生就为金融互联网而生。他的消息可靠性相比Kafka也有了很大的提升,而消息吞吐量相比RabbitMQ也有很大的提升。另外,RocketMQ的高级功能也越来越全面,广播消费、延迟队列、死信队列等等高级功能一应俱全,甚至某些业务功能比如事务消息,已经呈现出领先潮流的趋势。

RocketMQ快速实战

快速搭建RocketMQ服务

RocketMQ的官网地址: RocketMQ · 官方网站 | RocketMQ

下载页面地址:下载 | RocketMQ

当前最新的版本是5.x,这是一个着眼于云原生的新版本,给 RocketMQ 带来了非常多很亮眼的新特性。但是目前来看,企业中用得还比较少。因此,我们这里采用的还是更为稳定的4.9.5版本。

注:在2020年下半年,RocketMQ新推出了5.0的大版本,这对于RocketMQ来说,是一个里程碑式的大版本。在这个大版本中,RocketMQ对整体功能做了一次大的升级。增加了很多非常有用的新特性,也对已有功能重新做了升级。

比如在具体功能方面,在4.x版本中,对于定时消息,只能设定几个固定的延迟级别,而5.0版本中,已经可以指定具体的发送时间了。在客户端语言方面,4.x版本,RocketMQ原生只支持基于Netty框架的Java客户端。而在5.0版本中,增加了对Grpc协议的支持,这基本上就解除了对客户端语言的限制。在服务端架构方面,4.x版本只支持固定角色的普通集群和可以动态切换角色的Dledger集群,而在5.0版本中,增加了Dledger Controller混合集群模式,即可以混合使用Dledger的集群机制以及 Broker 本地的文件管理机制。

但是功能强大,同时也意味着问题会很多。所以目前来看,企业中直接用新版本的还比较少。小部分使用新版本的企业,也大都是使用内部的改造优化版本。

这里下载的是这个版本:

上传到服务器并解压:(unzip rocketmq-all-4.9.5-bin-release.zip

RocketMQ建议的运行环境需要至少12G的内存,这是生产环境比较理想的资源配置。但是我买的云服务器是2核4g,所以需要修改启动配置:(:set number临时显示行号)

注意:生产环境不建议修改上面两个配置。

RocketMQ是基于Java开发的,所以依赖Java开发环境,安装JDK步骤省略,建议采用1.8版本

RocketMQ的后端服务分为nameserver和broker两个服务:

# 第一步:启动nameserver服务,进入安装目录执行命令
nohup bin/mqnamesrv &
# 是否启动成功可以通过jps检查,启动成功或失败可以查看nohup.out文件# 为了方便测试在conf/broker.conf文件添加配置:
autoCreateTopicEnable=true
# 注意:如果是云服务器,还需要额外添加一行配置
brokerIP1 = 你的公网IP# 第二步:启动broker服务,进入安装目录执行命令
nohup bin/mqbroker &

注意:

1、在实际服务部署时,通常会将RocketMQ的部署地址添加到环境变量当中。例如使用vi ~/.bash_profile指令,添加以下内容

export ROCKETMQ_HOME=/home/rocket/rocketmq-all-4.9.5-bin-release // 修改为你的安装目录
PATH=$ROCKETMQ_HOME/bin:$PATH
export PATH

2、停止RocketMQ服务可以通过mqshutdown指令进行,停止服务有短暂延迟,不建议kill杀进程

mqshutdown namesrv # 关闭nameserver服务
mqshutdown broker # 关闭broker服务

快速实现消息收发

1、命令行快速实现消息收发

第一步:需要配置一个环境变量NAMESRV_ADDR,指向之前启动的nameserver服务。

通过vi ~/.bash_profile添加以下配置。然后使用source ~/.bash_profile让配置生效。

export NAMESRV_ADDR='localhost:9876'

修改后文件:

第二步:通过指令启动RocketMQ的消息生产者发送消息。默认往RocketMQ中发送1000条消息

tools.sh org.apache.rocketmq.example.quickstart.Producer ...消息发送日志
SendResult [sendStatus=SEND_OK, msgId=7F0000018FBA1B6D358697CBE7FB03E7, offsetMsgId=C0A800DA00002A9F000000000005DA64, messageQueue=MessageQueue [topic=TopicTest, brokerName=hcss-ecs-3744, queueId=3], queueOffset=499]
11:25:22.820 [NettyClientSelector_1] INFO RocketmqRemoting - closeChannel: close the connection to remote address[127.0.0.1:9876] result: true
11:25:22.825 [NettyClientSelector_1] INFO RocketmqRemoting - closeChannel: close the connection to remote address[127.0.0.1:9876] result: true
11:25:22.825 [NettyClientSelector_1] INFO RocketmqRemoting - closeChannel: close the connection to remote address[192.168.0.218:10911] result: true

第三步:可以启动消息消费者接收之前发送的消息

tools.sh org.apache.rocketmq.example.quickstart.Consumer...消息消费日志
ConsumeMessageThread_please_rename_unique_group_name_4_15 Receive New Messages: [MessageExt [brokerName=hcss-ecs-3744, queueId=2, storeSize=192, queueOffset=199, sysFlag=0, bornTimestamp=1701312827986, bornHost=/192.168.0.218:32850, storeTimestamp=1701312827987, storeHost=/192.168.0.218:10911, msgId=C0A800DA00002A9F00000000000256D2, commitLogOffset=153298, bodyCRC=748130833, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=250, CONSUME_START_TIME=1701314617997, UNIQ_KEY=7F0000018E561B6D358697AEFE52031F, CLUSTER=DefaultCluster, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 32, 55, 57, 57], transactionId='null'}]]

注意:这个Consumer消费者的指令并不会主动结束,他会继续挂起,等待消费新的消息。可以使用CTRL+C停止该进程。

2、搭建Maven客户端项目

第一步:创建一个标准的maven项目,在pom.xml中引入以下核心依赖

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

第二步:就可以直接创建一个简单的消息生产者

public class Producer
{public static void main(String[] args)throws MQClientException, InterruptedException{// 初始化一个消息生产者DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");// 指定nameserver地址producer.setNamesrvAddr("192.168.232.128:9876");// 启动消息生产者服务producer.start();for (int i = 0; i < 2; i++){try{// 创建消息。消息由Topic,Tag和body三个属性组成,其中Body就是消息内容Message msg =new Message("TopicTest", "TagA", ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));// 发送消息,获取发送结果SendResult sendResult = producer.send(msg);System.out.printf("%s%n", sendResult);}catch (Exception e){e.printStackTrace();Thread.sleep(1000);}}// 消息发送完后,停止消息生产者服务。producer.shutdown();}
}

注意:对于生产者,需要指定对应的nameserver服务的地址,这个地址需要指向你自己的服务器。

第三步:创建一个消息消费者接收RocketMQ中的消息。

public class Consumer
{public static void main(String[] args)throws InterruptedException, MQClientException{// 构建一个消息消费者DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4");// 指定nameserver地址consumer.setNamesrvAddr("192.168.232.128:9876");consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);// 订阅一个感兴趣的话题,这个话题需要与消息的topic一致consumer.subscribe("TopicTest", "*");// 注册一个消息回调函数,消费到消息后就会触发回调。consumer.registerMessageListener(new MessageListenerConcurrently(){@Overridepublic ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context){msgs.forEach(messageExt -> {try{System.out.println("收到消息:" + new String(messageExt.getBody(), RemotingHelper.DEFAULT_CHARSET));}catch (UnsupportedEncodingException e){}});return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;}});// 启动消费者服务consumer.start();System.out.print("Consumer Started");}
}

注意:对于消费者,同样需要指定nameserver的地址,另外消费者需要在RocketMQ中订阅具体的Topic,只有发送到这个Topic上的消息才会被这个消费者接收到

生产消费报错:RemotingTooMuchRequestException: sendDefaultImpl call timeout

解决方法:

1、在conf/broker.conf 中加入配置:

namesrvAddr = 你的公网IP:9876
brokerIP1 = 你的公网IP

2、重启broker,启动命令指定配置文件:

nohup mqbroker -n localhost:9876 -c conf/broker.conf &

重启完成,上面的生产者消费者测试代码通过

相关文章:

  • docker-compose;私有镜像仓库harbor搭建;镜像推送到私有仓库harbor
  • 【开源】基于JAVA的大病保险管理系统
  • matlab 混沌动力学行为-分岔图-李雅普指数等
  • 推荐几款python在线学习和电子书网站
  • 带你手搓阻塞队列——自定义实现
  • 【UGUI】Unity教程:实现物品的拖拽功能
  • SpringBoot+mysql+vue实现大学生健康档案管理系统前后端分离
  • MySQL数据库的备份与恢复
  • 腾讯云手动下发指令到设备-用于设备调试
  • 全栈冲刺 之 一天速成MySQL
  • 知乎禁止转载的回答怎么复制做笔记?
  • 恒驰服务 | 华为云云上运维服务offering
  • 近期知识点随笔
  • 【Java】使用IntelliJ IDEA搭建SSM(MyBatis-Plus)框架并连接MySQL数据库
  • 【Git】修改提交信息(单次、批量)
  • 收藏网友的 源程序下载网
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • Android Studio:GIT提交项目到远程仓库
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • Java,console输出实时的转向GUI textbox
  • PHP面试之三:MySQL数据库
  • 前端临床手札——文件上传
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 微服务入门【系列视频课程】
  • 微信公众号开发小记——5.python微信红包
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • (06)金属布线——为半导体注入生命的连接
  • (1)Android开发优化---------UI优化
  • (11)MSP430F5529 定时器B
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (排序详解之 堆排序)
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • *** 2003
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .NET gRPC 和RESTful简单对比
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET/MSBuild 中的发布路径在哪里呢?如何在扩展编译的时候修改发布路径中的文件呢?
  • .NET中的十进制浮点类型,徐汇区网站设计
  • .NET中使用Protobuffer 实现序列化和反序列化
  • @DateTimeFormat 和 @JsonFormat 注解详解
  • @Not - Empty-Null-Blank
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • @requestBody写与不写的情况
  • [ Linux ] git工具的基本使用(仓库的构建,提交)
  • [ vulhub漏洞复现篇 ] Grafana任意文件读取漏洞CVE-2021-43798
  • [1]-基于图搜索的路径规划基础