Rocket笔记 单机安装 集群安装 Springboot整合Rocket 超精细!!!!

一.单机安装

rocketmq-all-4.4.0-bin-release.zip

1.启动NameServer

# 1.启动NameServer
nohup sh ./mqnamesrv &
# 2.查看启动日志
tail -f ~/logs/rocketmqlogs/namesrv.log

2. 启动Broker

# 1.启动Broker
nohup sh ./mqbroker -n localhost:9876 &
# 2.查看启动日志
tail -f ~/logs/rocketmqlogs/broker.log

3.启动没啥异常但是不成功

vi runbroker.sh
vi runserver.sh
参考设置:
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m  -XX:MaxMetaspaceSize=320m

4.测试Rocketmq

4.1发送消息

# 1.设置环境变量
export NAMESRV_ADDR=localhost:9876
# 2.使用安装包的Demo发送消息
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer

4.2接收消息

# 1.设置环境变量
export NAMESRV_ADDR=localhost:9876
# 2.接收消息
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer

4.3关闭RocketMQ

# 1.关闭NameServer
sh  ./mqshutdown namesrv
# 2.关闭Broker
sh  ./mqshutdown broker

二.集群安装

 

Producer:消息的发送者;

Consumer:消息接收者;

Broker:暂存和传输消息;

NameServer:管理Broker;

Topic:区分消息的种类;一个发送者可以发送消息给一个或者多个Topic;一个消息的接收者可以订阅一个或者多个topic消息.

Message Queue:相当于是Topic的分区;用于并行发送和接收消息

2.1集群模式

  2.1.1单Master模式

一旦Broker重启或者宕机时,会导致整个服务不可用

2.1.2 多master模式

一个集群无Slave,全是Master.

优点:配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时,即使机器宕机不可恢复情况下,由于RAID10磁盘非常可靠,消息也不会丢(异步刷盘丢失少量消息,同步刷盘一条不丢),性能最高;

缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息实时性会受到影响。

  2.1.3多Master多Slave模式(异步)

每个Master配置一个Slave,有多对Master-Slave,HA采用异步复制方式,主备有短暂消息延迟(毫秒级),这种模式的优缺点如下:

优点:即使磁盘损坏,消息丢失的非常少,且消息实时性不会受影响,同时Master宕机后,消费者仍然可以从Slave消费,而且此过程对应用透明,不需要人工干预,性能同多Master模式几乎一样;

缺点:Master宕机,磁盘损坏情况下会丢失少量消息。

2.1.4 多Master多Slave模式(同步)

每个Master配置一个Slave,有多对Master-Slave,HA采用同步双写方式,即只有主备都写成功,才向应用返回成功,这种模式的优缺点如下:

优点:数据与服务都无单点故障,Master宕机情况下,消息无延迟,服务可用性与数据可用性都非常高;

缺点:性能比异步复制模式略低(大约低10%左右),发送单个消息的RT会略高,且目前版本在主节点宕机后,备机不能自动切换为主机。

2.2.4 部署集群模式(同步双写)

 

 

工作流程:

1. 启动NameServer,NameServer起来后监听端口,等待Broker、Producer、Consumer连上来,相当于一个路由控制中心。

2. Broker启动,跟所有的NameServer保持长连接,定时发送心跳包。心跳包中包含当前Broker信息(IP+端口等)以及存储所有Topic信息。注册成功后,NameServer集群中就有Topic跟Broker的映射关系。

3. 收发消息前,先创建Topic,创建Topic时需要指定该Topic要存储在哪些Broker上,也可以在发送消息时自动创建Topic。

4. Producer发送消息,启动时先跟NameServer集群中的其中一台建立长连接,并从NameServer中获取当前发送的Topic存在哪些Broker上,轮询从队列列表中选择一个队列,然后与队列所在的Broker建立长连接从而向Broker发消息。

5. Consumer跟Producer类似,跟其中一台NameServer建立长连接,获取当前订阅Topic存在哪些Broker上,然后直接跟Broker建立连接通道,开始消费消息。

2.2.5 服务器环境

序号

IP

角色

架构模式

1

192.168.174.204

nameserver brokerserver

Master1、Slave2

2

192.168.174.205

nameserver  brokerserver

Master2、Slave1

2.2.6 修改hosts 信息

192.168.174.204 rocketmq-nameserver1
192.168.174.205 rocketmq-nameserver2

192.168.174.204 rocketmq-master1
192.168.174.204 rocketmq-slave2
192.168.174.205 rocketmq-master2
192.168.174.205 rocketmq-slave1

重启网卡: systemctl restart network

2.2.7防火墙配置

# 开放name server默认端口
firewall-cmd --remove-port=9876/tcp --permanent
# 开放master默认端口
firewall-cmd --remove-port=10911/tcp --permanent
# 开放slave默认端口 (当前集群模式可不开启)
firewall-cmd --remove-port=11011/tcp --permanent 
# 重启防火墙
firewall-cmd --reload

2.2.8环境变量配置

#set rocketmq
ROCKETMQ_HOME=/usr/local/rocketmq/rocketmq-all-4.4.0-bin-release
PATH=$PATH:$ROCKETMQ_HOME/bin
export ROCKETMQ_HOME PATH

2.2.9 创建消息存储路径

mkdir /usr/local/rocketmq/store
mkdir /usr/local/rocketmq/store/commitlog
mkdir /usr/local/rocketmq/store/consumequeue
mkdir /usr/local/rocketmq/store/index
mkdir /usr/local/rocketmq/store_slave

2.2.10 配置文件

第一台(192.168.174.204):

/opt/soft/rocketmq/conf/2m-2s-sync/broker-a.properties

#所属集群名字
brokerClusterName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-a
#0 表示 Master,>0 表示 Slave
brokerId=0
brokerIp1:192.168.174.204
#nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=10911
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/opt/soft/rocketmq/store
#commitLog 存储路径
storePathCommitLog=/opt/soft/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/opt/soft/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/opt/soft/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/opt/soft/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/opt/soft/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=SYNC_MASTER
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageThreadPoolNums=128
#拉消息线程池数量
#pullMessageThreadPoolNums=128
enablePropertyFilter = true
filterSupportRetry = true

/opt/soft/rocketmq/conf/2m-2s-sync/broker-b-s.properties

#所属集群名字
brokerClusterName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-b
#0 表示 Master,>0 表示 Slave
brokerId=1
brokerIp1:192.168.174.204
#nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=11011
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/opt/soft/rocketmq/store_slave
#commitLog 存储路径
storePathCommitLog=/opt/soft/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/opt/soft/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/opt/soft/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/opt/soft/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/opt/soft/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=SLAVE
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageThreadPoolNums=128
#拉消息线程池数量
#pullMessageThreadPoolNums=128
enablePropertyFilter = true
filterSupportRetry = true

第二台(192.168.174.205):

/opt/soft/rocketmq/conf/2m-2s-sync/broker-b.properties

#所属集群名字
brokerClusterName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-b
#0 表示 Master,>0 表示 Slave
brokerId=0
brokerIp2:192.168.174.205
#nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=10911
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/opt/soft/rocketmq/store
#commitLog 存储路径
storePathCommitLog=/opt/soft/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/opt/soft/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/opt/soft/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/opt/soft/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/opt/soft/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=SYNC_MASTER
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageThreadPoolNums=128
#拉消息线程池数量
#pullMessageThreadPoolNums=128

enablePropertyFilter = true
filterSupportRetry = true

/opt/soft/rocketmq/conf/2m-2s-sync/broker-a-s.properties

#所属集群名字
brokerClusterName=rocketmq-cluster
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-a
#0 表示 Master,>0 表示 Slave
brokerId=1
brokerIp2:192.168.174.205
#nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=11011
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=120
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/opt/soft/rocketmq/store_slave
#commitLog 存储路径
storePathCommitLog=/opt/soft/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/opt/soft/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/opt/soft/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/opt/soft/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/opt/soft/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=SLAVE
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
#sendMessageThreadPoolNums=128
#拉消息线程池数量
#pullMessageThreadPoolNums=128


enablePropertyFilter = true
filterSupportRetry = true

第1,2 台 启动namesrv

nohup sh /opt/soft/rocketmq/bin/mqnamesrv &

启动 第1台 broker

nohup sh mqbroker -c /opt/soft/rocketmq/conf/2m-2s-sync/broker-a.properties &
nohup sh mqbroker -c /opt/soft/rocketmq/conf/2m-2s-sync/broker-b-s.properties &

启动 第2台 broker

nohup sh mqbroker -c /opt/soft/rocketmq/conf/2m-2s-sync/broker-b.properties & 
nohup sh mqbroker -c /opt/soft/rocketmq/conf/2m-2s-sync/broker-a-s.properties &
# 1.关闭NameServer
sh /opt/soft/rocketmq/bin/mqshutdown namesrv

# 2.关闭Broker
sh /opt/soft/rocketmq/bin/mqshutdown broker
tail -f ~/logs/rocketmqlogs/broker.log

三 Springboot整合rocketmq.

3.1pom.xml

		<dependency>
			<groupId>org.apache.rocketmq</groupId>
			<artifactId>rocketmq-spring-boot-starter</artifactId>
			<version>2.2.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.rocketmq</groupId>
			<artifactId>rocketmq-client</artifactId>
			<version>4.9.0</version>
		</dependency>

3.2application.yml

rocketmq:
  name-server: 192.168.174.204:9876;192.168.174.205:9876
  producer:
    group: codeTest
  consumer:
    group: codeTest

3.3 生产者

3.3.1普通推送

1.消息的顺序问题:  将不同的消息发送到同一个服务器上.

2.消息的重复问题:  (1)保持幂等性 (不管多少条相同的数据,结果都是一条数据)(2):利用一张日志表,来到的数据都有自身的id 记录下,再来的数据与之id相比较.记录的不在记录.

@Autowired
private RocketMQTemplate template;

    /**
     * 普通推送
     */
    public void sendDataSync() {
        DefaultMQProducer producer = template.getProducer();
        int num = 10;
        while (num > 0) {
            String message = "sendMessage" + num;
            Message message1 = new Message("test-topic-Sync", "test-tag-Sync", message.getBytes(StandardCharsets.UTF_8));

            try {
                SendResult sendResult = producer.send(message1);
                if (sendResult.getSendStatus() == SendStatus.SEND_OK) {
                    Console.log("普通消息发送成功");
                } else {
                    Console.log("普通消息发送失败:[{}]", num, sendResult.getSendStatus());

                }
            } catch (Exception e) {
                Console.error("普通消息发送报错" + e);
            }
            num--;
        }

    }
 @Autowired
private ProducerService service;

 /**
     * 推送顺序消费
     */
    @RequestMapping(value = "/sendSync", method = RequestMethod.GET)
    public void sendSync() {
        service.sendDataSync();
    }

3.3.2 顺序推送

 public void sendOrderly() {
        try {
            DefaultMQProducer producer = template.getProducer();
            int num = 10;
            while (num > 0) {

                String message = "sendMeeage1_" + num;
                Message message1 = new Message("test-topic-orderly", "test-tag-orderly", "1_" + num, message.getBytes(StandardCharsets.UTF_8));
                SendResult send1 = producer.send(message1, (list, message2, o) -> {
                    Integer integer = (Integer) o;
                    int index = integer % list.size();
                    return list.get(index);
                }, 0);

                message = "sendMeeage2_" + num;
                Message message3 = new Message("test-topic-orderly", "test-tag-orderly", "2_" + num, message.getBytes(StandardCharsets.UTF_8));
                SendResult send2 = producer.send(message1, (list, message2, o) -> {
                    Integer integer = (Integer) o;
                    int index = integer % list.size();
                    return list.get(index);
                }, 1);

                message = "sendMeeage3_" + num;
                Message message4 = new Message("test-topic-orderly", "test-tag-orderly", "3_" + num, message.getBytes(StandardCharsets.UTF_8));
                SendResult send3 = producer.send(message1, (list, message2, o) -> {
                    Integer integer = (Integer) o;
                    int index = integer % list.size();
                    return list.get(index);
                }, 2);
                num--;
            }
        } catch (Exception e) {

            Console.error("推送信息失败,异常异常信息:[{}]", e.getStackTrace());
        }
        
    }
@RequestMapping(value = "/sendOrderly", method = RequestMethod.GET)
public void sendOrderly(){
service.sendOrderly();
    }
@Component
@RocketMQMessageListener(consumerGroup = "test-consumer-orderly", topic = "test-topic-orderly",
        selectorExpression = "test-tag-orderly", consumeThreadMax = 5,
        consumeMode = ConsumeMode.ORDERLY)
public class MyPushOrderlyListener implements RocketMQListener<String> {

    private static Map<String, Object> map = new HashMap<>();
    private static Long startTime = 0L;
    private static Long endTime = 0L;
    
    @Override
    public void onMessage(String s) {
       if (map.size()==0){
           startTime = System.currentTimeMillis();
       }
        Console.log("有序消费监听接收到消息:[{}]", s);
        map.put(s, null);

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (map.size() == 10) {
            endTime = System.currentTimeMillis();
            Console.log("有序消费完成, 耗时[{}]!", endTime - startTime);
            map = new HashMap<>();
        }
    }
}

3.3.3 立即消费

 public void  sendDataAsync(){
           int num=10;
        try{

            while (num>1){

            DefaultMQProducer producer = template.getProducer();
            String message="message"+num;
            Message message1 = new Message("test-topic-currently", "test-tag-currently", message.getBytes(StandardCharsets.UTF_8));
            SendResult send = producer.send(message1);
            if (send.getSendStatus() == SendStatus.SEND_OK) {
                Console.log("普通消息发送成功");
            } else {
                Console.log("普通消息发送失败:[{}]", num, send.getSendStatus());

            }
            }
        }catch (Exception e) {
            Console.log("推送数据错误:[{}]",e.getMessage());
        }
           num--;
       }
  /**
     * 推送立刻消费
     * */
    @RequestMapping(value = "/sendCurrently", method = RequestMethod.GET)
    public void sendCurrently(){
        service.sendDataAsync();
    }
@Component
@RocketMQMessageListener(consumerGroup = "test-consumer-currently", topic = "test-topic-currently",
        selectorExpression = "test-tag-currently", consumeThreadMax = 2,
        consumeMode = ConsumeMode.CONCURRENTLY)
public class MyPushCurrentlyConsumer implements RocketMQListener<String> {

    private static Map<String, Object> map = new HashMap<>();
    private static Long startTime = 0L;
    private static Long endTime = 0L;

    @Override
    public void onMessage(String s) {

        if (map.size() ==0){
            startTime = System.currentTimeMillis();
        }
        Console.log("并发消费监听接收到消息:[{}]", s );
        map.put(s,null);

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if (map.size()==10){
            endTime= System.currentTimeMillis();
            Console.log("并发消费完成, 耗时[{}]!", endTime - startTime);
        }

    }
}

3.3.4 集群推送

 public void sendDataCluter(){
          try{
              DefaultMQProducer producer = template.getProducer();
              int num =10;
              while (num>1){
              String sendMessage="sendMessage_"+num;
                  Message message = new Message("test-topic-currently-sc", "test-tag-currently-sc", sendMessage.getBytes(StandardCharsets.UTF_8));
                  SendResult send = producer.send(message);
                  if (send.getSendStatus()==SendStatus.SEND_OK){
                      Console.log("集群模式推送数据成功:[{}]",num);
                  }else {
                      Console.log("集群模式推送数据失败");
                  }
                  num--;
              }
              Console.log("集群数据推送完成!");
          }catch (Exception e){
              Console.log("集群数据推送异常:[{}]",e.getMessage());
          }
      }
  /**
     * 推送, 集群消费
     */
    @RequestMapping(value = "/sendCluster", method = RequestMethod.GET)
   public void sendCluster(){
        service.sendDataCluter();
    }
@Component
public class MyPushConsumer {
    private static final String groupName="test-consumer-currently";
    private static final  String topic="test-topic-currently-sc";
    private  static  final  String tag="test-tag-currently-sc";

    @Scheduled(initialDelay = 3000, fixedDelay = 5000)
    public void consumer1(){
        Console.log("集群模式push监听1启动");

        try {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(groupName);
        consumer.setNamesrvAddr("192.168.174.204:9876;192.168.174.205:9876");
        consumer.subscribe(topic,tag);
        consumer.setMessageModel(MessageModel.CLUSTERING);
        consumer.registerMessageListener(new BasePushListener1());
        consumer.setConsumeTimeout(1L);
        consumer.start();
        } catch (MQClientException e) {
          Console.error("集群模式监听异常,异常信息:[{}]", e.getMessage());
        }
    }

    @Scheduled(initialDelay = 3000, fixedDelay = 5000)
    public void consumer2(){
        Console.log("集群模式push监听2启动");
        try {
            DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(groupName);
            consumer.setNamesrvAddr("192.168.174.204:9876;192.168.174.205:9876");
            consumer.subscribe(topic,tag);
            consumer.setMessageModel(MessageModel.CLUSTERING);
            consumer.registerMessageListener(new BasePushListener2());
            consumer.setConsumeTimeout(1L);
            consumer.start();
        } catch (MQClientException e) {
            Console.error("集群模式监听异常,异常信息:[{}]", e.getMessage());
        }
    }



    private class BasePushListener1 implements  MessageListenerConcurrently {
        @Override
        public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
           if (CollUtil.isNotEmpty(list)){
               for (MessageExt messageExt : list) {
                   String topic = messageExt.getTopic();
                   try {
                       String body = new String(messageExt.getBody(), "UTF-8");
                       String tags = messageExt.getTags();
                       Console.log("push消费者1收到消息:" + " topic :" + topic + " ,tags : " + tags + " ,msg : " + body);
                   } catch (UnsupportedEncodingException e) {
                       return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                   }
               }
           }
            return ConsumeConcurrentlyStatus.RECONSUME_LATER;
        }
    }


    private class BasePushListener2 implements MessageListenerConcurrently {
        @Override
        public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
            if (CollUtil.isNotEmpty(list)){
                for (MessageExt messageExt : list) {
                    String topic = messageExt.getTopic();
                    try {
                        String body = new String(messageExt.getBody(), "UTF-8");
                        String tags = messageExt.getTags();
                        Console.log("push消费者2收到消息:" + " topic :" + topic + " ,tags : " + tags + " ,msg : " + body);
                    } catch (UnsupportedEncodingException e) {
                        return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                    }
                }
            }
            return ConsumeConcurrentlyStatus.RECONSUME_LATER;
        }
    }

}

3.3.5 推送,主动消费

public void pull(){
          try{
              DefaultMQProducer producer = template.getProducer();
              int num =10;
              while (num>1){
                  String sendMessage="sendMessage_"+num;
                  Message message = new Message("test-topic-pull", "test-tag-pull", sendMessage.getBytes(StandardCharsets.UTF_8));
                  SendResult send = producer.send(message);
                  if (send.getSendStatus()==SendStatus.SEND_OK){
                      Console.log("pull数据成功:[{}]",num,send.getQueueOffset());
                  }else {
                      Console.log("pull数据失败");
                  }
                  num--;
              }
              Console.log("pull完成!");
          }catch (Exception e){
              Console.log("pull异常:[{}]",e.getMessage());
          }
      }
  /**
     * 推送, 主动消费
     */
    @RequestMapping(value = "/pull", method = RequestMethod.GET)
    public void pull(){
        service.pull();
    }
@Component
public class MyPullConsumer {
    private static final Map<MessageQueue,Long> offsetMap=new HashMap<>();
    private static final DefaultMQPullConsumer consumer;
    private  static  final  String groupName="codeTest";

    static {
         consumer = new DefaultMQPullConsumer(groupName);
         consumer.setNamesrvAddr("192.168.174.204:9876;192.168.174.205:9876");

        try {
            consumer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
    }
    @Scheduled(initialDelay = 3000, fixedDelay = 1000)
  public void pullMessage(){

      try {
          Set<MessageQueue> messageQueues = consumer.fetchSubscribeMessageQueues("test-topic-pull");
          if (messageQueues.size()>0){
              for (MessageQueue queue : messageQueues) {
                  Long offset=0L;
                  if (offsetMap.containsKey(queue)){
                      offset = offsetMap.get(queue);
                  }
                  PullResultExt pullResultExt = (PullResultExt) consumer.pullBlockIfNotFound(queue, null, offset, 32);
                  offsetMap.put(queue,pullResultExt.getNextBeginOffset());
                  PullStatus status = pullResultExt.getPullStatus();
                  UpdateConsumerOffsetRequestHeader requestHeader = new UpdateConsumerOffsetRequestHeader();

                  if (status==PullStatus.FOUND){
                      List<MessageExt> list = pullResultExt.getMsgFoundList();
                      if (CollUtil.isNotEmpty(list)){
                          for (MessageExt messageExt : list) {
                              if (System.currentTimeMillis()-messageExt.getBornTimestamp() <=1000){
                                  System.out.println("当前消息队列:[" + queue.getQueueId() + "],接收到消息:[" + new String(messageExt.getBody()) + "]");
                              }
                          }
                      }

                  }

              }
          }
      } catch (Exception e) {
          e.printStackTrace();
      }
  }

3.3.6 单向推送

/**
* 单向推送
* */
   public void  oneWaySend(){
        try{
            DefaultMQProducer producer = template.getProducer();
            int num =100;
            while (num>0){
                String numbers = RandomUtil.randomNumbers(10);
                String sendMessage="oneWaySendMessage"+numbers;
                Message message = new Message("test-topic-oneway", "test-tag-oneway", sendMessage.getBytes(StandardCharsets.UTF_8));
                producer.sendOneway(message);
                num--;
                Console.log("单向推送消息完成!");
            }

        }catch (Exception e){
            Console.log("单向推送消息异常,异常信息:[{}]", e.getMessage());
        }
    }
 /**
     * 单向推送
     */
    @RequestMapping(value = "/oneWaySend", method = RequestMethod.GET)
    public void oneWaySend(){
        service.oneWaySend();
    }
@Component
@RocketMQMessageListener(consumerGroup = "test-consumer-oneway",topic = "test-topic-oneway",selectorExpression = "test-tag-oneway")
public class MyOneWayListener implements RocketMQListener<String> {
    @Override
    public void onMessage(String s) {
        Console.log("单向监听接收到消息:[{}]", s);


        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3.3.7 异步推送

 public void asyncSend(){
     try{
         int num =10;
         String topic="test-topic-async";
         String tag="test-topic-async";
         String destination=topic+":"+tag;

         while (num>0){
           String sendMessage="asyncSendMessage_"+num;
             Message message = new Message(topic, tag, sendMessage.getBytes(StandardCharsets.UTF_8));
             template.asyncSend(destination, message, new SendCallback() {
                 @Override
                 public void onSuccess(SendResult sendResult) {
                     if (sendResult.getSendStatus()==SendStatus.SEND_OK){
                         Console.log("异步推送[{}]成功, 返回:[{}]!", sendMessage, sendResult.getSendStatus());
                     }else {
                         Console.log("异步推送[{}]失败, 返回:[{}]!", sendMessage, sendResult.getSendStatus());
                     }
                 }

                 @Override
                 public void onException(Throwable throwable) {
                   Console.log("异步推送[{}]异常, 异常信息:[{}]!", sendMessage, throwable.getMessage());
                 }
             });
         }
     }catch (Exception e){Console.log(e);}

    }
/**
     * 异步推送
     */
    @RequestMapping(value = "/asyncSend", method = RequestMethod.GET)
    public void asyncSend(){
        service.asyncSend();
    }
@Component
@RocketMQMessageListener(consumerGroup = "test-consumer-async",
        topic = "test-topic-async",consumeThreadMax = 2,selectorExpression ="test-topic-async" )
public class MyAsyncListener  implements RocketMQListener<Message> {

    private static Map<String,Object> map =new HashMap<>();
    private static  Long start_time=0L;
    private static  Long end_time=0L;

    @Override
    public void onMessage(Message message) {

        if (map.size()==0){
            start_time=System.currentTimeMillis();
        }
        Console.log("异步推送消费监听接收到消息:[{}]",new String(message.getBody()));
        map.put(new String(message.getBody()),null);
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {

          Console.error(e);
        }
        if (map.size()==10){
            end_time=System.currentTimeMillis();
            Console.log("异步推送消费完成, 耗时[{}]!",end_time-start_time);
        }

    }
}

3.3.8 延迟推送

public void delaySend(){
    try{
        DefaultMQProducer producer = template.getProducer();
        int num =10;
        while (num>0){
            String sendMessage="delaySendMessage_"+num;
            Message message = new Message("test-topic-delay", "test-tag-delay", sendMessage.getBytes(StandardCharsets.UTF_8));
            int level = getDelayLevel(num);
            message.setDelayTimeLevel(level);
            SendResult send = producer.send(message);
            if (send.getSendStatus()==SendStatus.SEND_OK){
                Console.log("延迟推送消息[{}]成功, 延迟级别:[{}]!", num, level);
            }else {
                Console.log("延迟推送消息[{}]失败, 推送返回状态:[{}]", num, send.getSendStatus());
            }
            num--;
            Console.log("单向推送消息完成!");
        }

    }catch (Exception e){
        Console.log("单向推送消息异常,异常信息:[{}]", e.getMessage());
    }
}
 public int getDelayLevel(int second){
        int delayLevel = 0;
        // 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
        if (second > 0 && second < 5) {
            delayLevel = 1;
        } else if (second >= 5 && second < 10) {
            delayLevel = 2;
        } else if (second >= 10 && second < 30) {
            delayLevel = 3;
        } else if (second >= 30 && second < 60) {
            delayLevel = 4;	
        } else if (second >= 60) {
            delayLevel = 5;
        }
  /**
     * 普通延迟推送
     */
    @RequestMapping(value = "/delaySend", method = RequestMethod.GET)
    public void delaySend(){
        service.delaySend();
    }
@Component
@RocketMQMessageListener(consumerGroup = "test-consumer-delay",topic = "test-topic-delay",selectorExpression ="test-tag-delay" )
public class MyDelayListener implements RocketMQListener<String> {
    @Override
    public void onMessage(String s) {
        Console.log("延迟监听接收到消息:[{}]", s);
    }
}

3.3.9 过滤延时

/**
     * 过滤推送
     */


    public void filterSend(){

        try{
            DefaultMQProducer producer = template.getProducer();
            producer.setSendLatencyFaultEnable(true);
            int num =10;
            while (num>0){
                String sendMessage="delaySendMessage_"+num;
                Message message = new Message("test-topic-filter", "test-tag-filter", sendMessage.getBytes(StandardCharsets.UTF_8));
                message.putUserProperty("id",String.valueOf(num));

                SendResult send = producer.send(message);
                if (send.getSendStatus()==SendStatus.SEND_OK){
                    Console.log("过滤推送消息成功!");
                }else {
                    Console.log("过滤推送消息失败, 推送返回状态:[{}]", send.getSendStatus());
                }
                num--;
                Console.log("过滤推送消息完成!");
            }
        }catch (Exception e){
            Console.log("过滤推送消息异常,异常信息:[{}]", e.getMessage());
        }

    }
    @RequestMapping(value = "/filterSend", method = RequestMethod.GET)
    public void filterSend(){
        service.filterSend();
    }
@Component
public class MyFilterConsumer {

    private static final String groupName = "test-consumer-filter";
    private static final String topic = "test-topic-filter";
    private static final String tag = "test-tag-filter";
    private static final DefaultMQPushConsumer consumer;

    static {
       consumer = new DefaultMQPushConsumer(groupName);
       consumer.setNamesrvAddr("192.168.174.204:9876;192.168.174.205:9876");

    }
    public void filterConsumer(){
        try {
            consumer.subscribe(topic, MessageSelector.bySql("id between 3 and 7"));
            consumer.registerMessageListener(new BasePushListener());
            consumer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
    }
    private class BasePushListener implements MessageListenerConcurrently{
        @Override
        public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
            if (CollUtil.isNotEmpty(list)){
               try{
                for (MessageExt messageExt : list) {
                    String topic = messageExt.getTopic();
                    String s = new String(messageExt.getBody(), "UTF-8");
                    String tags = messageExt.getTags();
                    System.out.println(messageExt.getProperty("id"));
                    System.out.println("过滤消费收到消息:" + " topic :" + topic + " ,tags : " + tags + " ,msg : " + s);
                }
                }catch (Exception e){
                   Console.log(e);
                   return  ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
               }
            }
            return  ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
    }
}
@Component
@RocketMQMessageListener(consumerGroup = "test-consumer-filter",
       topic = "test-topic-filter",selectorType = SelectorType.SQL92,selectorExpression = "id = 5")
public class MyFilterListner implements RocketMQListener<String> {
    @Override
    public void onMessage(String s) {
        Console.log("过滤监听接收到消息:[{}]", s);
    }
}

3.3.10 推送,无消费,web查询信息

public void sendWeb() {
        try {
            DefaultMQProducer producer = template.getProducer();
            int num = 10;
            while (num > 0) {
                String sendMessage = "sendMessage_" + num;
                Message message = new Message("test-topic-web", "test-tag-web", sendMessage.getBytes(StandardCharsets.UTF_8));
                SendResult sendResult = producer.send(message);
                if (sendResult.getSendStatus() == SendStatus.SEND_OK) {
                    Console.log("普通web推送消息:[{}]成功!", num);
                } else {
                    Console.log("普通web推送消息:[{}]失败, 推送返回状态:[{}]", num, sendResult.getSendStatus());
                }
                num --;
            }
            Console.log("普通web推送消息完成!");
        } catch (Exception e) {
            Console.log("普通web推送消息异常,异常信息:[{}]", e.getMessage());
        }
    }
  /**
     * 推送, 无消费, web查询信息
     */
    @RequestMapping(value = "/sendWeb", method = RequestMethod.GET)
    public void sendWeb(){
        service.sendWeb();
    }

四 rocketmq补充

4.1 按照发送特点

4.1.1 同步消息: 同步发送是指消息发送方发出数据后,会阻塞直到MQ服务方发回响应消息。

4.1.2 异步消息: 异步发送是指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。MQ 的异步发送,需要用户实现异步发送回调接口(SendCallback),在执行消息的异步发送时,应用不需要等待服务器响应即可直接返回,通过回调接口接收服务器响应,并对服务器的响应结果进行处理。应用场景:异步发送一般用于链路耗时较长,对 RT 响应时间较为敏感的业务场景,例如用户视频上传后通知启动转码服务,转码完成后通知推送转码结果等。

4.1.3 单向消息: 单向(one-way)消息:单向(Oneway)发送特点为只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。此方式发送消息的过程耗时非常短,一般在微秒级别。应用场景:适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。

4.2按照使用功能特点

  4.2.1 普通消息

  4.2.2 顺序消息

  4.2.3 广播消息

  4.2.4 延时消息

  4.2.5 批量消息

  4.2.6 事务消息

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值