Java整合RocketMQ多种消息实现,简单易懂

文章目录

    • 什么是RocketMQ
      • RocketMQ组成和工作流程
        • NameServer
        • Broker
        • Producer
        • Consumer
    • 下载
    • bin项目启动
    • 代码项目启动
    • 收发消息
      • 同步消息
      • 异步消息
      • 单发消息
      • 顺序消息
      • 延时消息
      • 事务消息
      • 广播消费和集群消费
      • 消费者组

什么是RocketMQ

  • RocketMQ属于消息中间件的一种(Message Queue),支持十万级以上的容量,主要作用是用来进行异步处理,削峰,解耦等
    • 异步:异步操作数据。比如在一个消耗物品的场景下,消费物品100ms,记录日志50ms,那么加起来就是150ms,如果再加新功能可能会更慢。如果使用异步那么我们只需要消费物品然后把后边任务放入队列直接返回就只使用100ms就可以。
    • 削峰:削弱峰值流量。如果某一个时间点流量特别大的话有可能系统会宕机,那么在这种情况下可以把请求丢进消息队列中,类似于一个缓冲区,然后按照系统消费速度来进行消费的话就不会宕机。
    • 解耦:解耦系统。如果代码耦合的比较严重的情况下,比如A调用B的情况下,修改A的代码B可能要随着一起被改变。但是如果解耦的话A调用消息队列,消息队列调用B,那么A不是直接调用B所以修改A时有可能不用修改B。

RocketMQ组成和工作流程

NameServer

  • 是一个无状态的节点,可以集群,但相互之间没有信息互通,主要功能有两一个,一个是Broker管理,NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活;路由信息管理,每个NameServer将保存关于Broker集群的整个路由信息和用于客户端查询的队列信息。
  • 工作流程:启动后相当于一个路由控制中心,等待其余角色连接

Broker

  • 主要负责消息的存储、投递和查询以及服务高可用保证.
  • 工作流程:启动后会向NameServer建立长链接并定时30s发送心跳包,心跳包包含自己的BrokerId和存储的Topic信息,如果NameServer是集群那么会向所有的NameServer建立长连接,

Producer

  • 消息发布的角色,支持分布式集群方式部署。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。
  • 工作流程:发送消息时会负载均衡的跟一个NameServer建立长连接,然后通过NameServer找到需要发送的Topic对应的Broker,然后向对应的Broker发送消息

Consumer

  • 消息消费的角色,支持分布式集群方式部署。支持以push推,pull拉两种模式对消息进行消费。同时也支持集群方式和广播方式的消费,它提供实时消息订阅机制,可以满足大多数用户的需求。
  • 工作流程:启动时获取订阅的Topic在那个Broker上,然后找到Broker开始消费消息

下载

  • RocketMQ下载地址
  • bin是可以直接运行的代码,source是源代码,两种都可以启动(以下简称bin和代码)
    Java整合RocketMQ多种消息实现,简单易懂_第1张图片

bin项目启动

  • 在环境变量配置ROCKETMQ_HOME
  • 配置自己的地址
    Java整合RocketMQ多种消息实现,简单易懂_第2张图片
  • 然后在bin目录下进入cmd页面,先启动NameServer再启动Broker
  • NameServer: start mqnamesrv.cmd
  • Broker: start mqbroker.cmd -n localhost:9876 autoCreateTopicEnable=true
  • autoCreateTopicEnable:true为自动创建Topic
    Java整合RocketMQ多种消息实现,简单易懂_第3张图片

代码项目启动

  • 编译完项目以后把distribution下的conf里的两个文件粘过来,在创建一下对应的目录
    Java整合RocketMQ多种消息实现,简单易懂_第4张图片
  • 然后修改broker.conf配置,修改为自己对应的路径
storePathRootDir=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store
#commitlog 存储路径
storePathCommitLog=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\commitlog
#消费队列存储路径
storePathConsumeQueue=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\consumequeue
#消息索引存储路径
storePathIndex=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\index
#checkpoint文件存储路径
storeCheckPoint=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\checkpoint
#abort文件存储路径
abortFile=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\abort
  • 在配置一下启动的环境变量,启动就ok
    Java整合RocketMQ多种消息实现,简单易懂_第5张图片
  • broker同理,但是要修改一下config的配置
    Java整合RocketMQ多种消息实现,简单易懂_第6张图片

收发消息

  • 添加maven依赖
		<dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.0.4</version>
        </dependency>
  • yml文件配置
rocketmq:
  name-server: localhost:9876
  producer:
  	group: my-group

同步消息

  • 发送消息会等待返回
@RestController
public class Producer {

	@Autowired
	RocketMQTemplate rocketMQTemplate;

    @PostConstruct
    public void sendMessage() {
        //同步  
        //如果不区分tag就指定Topic 区分就是topic:tag
        SendResult syncSendResult = rocketMQTemplate.syncSend("test:tagA","hello rocketmq" );
    }

	@Component
	@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
        //指定消费哪个Tag
        selectorExpression = "tagA")
	class ConsumerTest implements RocketMQListener<String> {

	    @Override
	    public void onMessage(String str) {
	        System.out.println(str);
	    }
	}
}
  • 输出内容
    在这里插入图片描述

异步消息

  • 发送消息以后由另一条线程回调方法
@RestController
public class Test{

	@Autowired
	RocketMQTemplate rocketMQTemplate;

    @PostConstruct
    public void sendMessage() {
    	//异步消息
        rocketMQTemplate.asyncSend("test:tagA", "hello rocketmq", new SendCallback() {
        	//发送成功回调方法
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println(sendResult);
            }
            //失败回调方法
            @Override
            public void onException(Throwable e) {
                System.out.println(e);
            }
        });
    }

	@Component
	@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
        //指定消费哪个Tag
        selectorExpression = "tagA")
	class ConsumerTest implements RocketMQListener<String> {

	    @Override
	    public void onMessage(String str) {
	        System.out.println(str);
	    }
	}
}
  • 输出内容
    Java整合RocketMQ多种消息实现,简单易懂_第7张图片

单发消息

  • 不关注返回不关注结果
@RestController
public class Test{

	@Autowired
	RocketMQTemplate rocketMQTemplate;

    @PostConstruct
    public void sendMessage() {
    	//单发 不关注结果
        rocketMQTemplate.sendOneWay("test:tagA","hello rocketmq");
    }

	@Component
	@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
        //指定消费哪个Tag
        selectorExpression = "tagA")
	class ConsumerTest implements RocketMQListener<String> {

	    @Override
	    public void onMessage(String str) {
	        System.out.println(str);
	    }
	}
}
  • 返回只是输出hello rocketmq

顺序消息

  • 顺序消息就是保证消息的顺序性,如果下单场景,下单->支付->发货,像这种保证顺序才有意义的场景下可以使用顺序消息
@RestController
public class Test{

	@Autowired
	RocketMQTemplate rocketMQTemplate;

    @PostConstruct
    public void sendMessage() {
    	//RocketMQ提供了三个实现,默认是SelectMessageQueueByHash
    	//SelectMessageQueueByRandom
        //SelectMessageQueueByMachineRoom
        //也可以自定义实现Order
        //通过id实现分组
//        rocketMQTemplate.setMessageQueueSelector((mqs, msg, arg) -> {
//            long id = Long.parseLong(arg + "");
//            return mqs.get((int) (id % mqs.size()));
//        });

    	buildOrders().forEach( order -> {
           rocketMQTemplate.syncSendOrderly("test:tagE",order,order.getOrderId() + "");
        });
    }
	@Component
	@RocketMQMessageListener(topic = "test",consumerGroup = "order",
	//修改comsumeMode为ConsumeMode.ORDERLY为顺序消费
	//ConsumeMode.CONCURRENT为并发消费
	selectorExpression = "tagE",consumeMode = ConsumeMode.ORDERLY)
	class OrderTest implements RocketMQListener {

	    @Override
	    public void onMessage(Object o) {
	        //顺序消费
	        System.out.println("线程:" +Thread.currentThread().getId() + "消息体:" + o);
	    }
	}
 /**
     * 订单的步骤
     */
    @Data
    private static class OrderStep {
        private long orderId;
        private String desc;
    }

    /**
     * 生成模拟订单数据
     */
    private static List<OrderStep> buildOrders() {
        List<OrderStep> orderList = new ArrayList<OrderStep>();

        OrderStep orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("推送");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        return orderList;
    }
}
  • 输出日志,可以看出一个订单由同一个线程来消费,就保证了顺序
    Java整合RocketMQ多种消息实现,简单易懂_第8张图片

延时消息

  • 等待一定时间后消费者才能去消费
@RestController
public class Test{

	@Autowired
	RocketMQTemplate rocketMQTemplate;

    @PostConstruct
    public void sendMessage() {
    	//延时等级:1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 
    	//7m 8m 9m 10m 20m 30m 1h 2h
    	//1级就是1s 2级就是5s 3级就是10s
    	SendResult syncTimeSendResult = rocketMQTemplate.syncSend("test:tagA",new GenericMessage<>("hello rocketmq"),100000,4);
    }

	@Component
	@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
        //指定消费哪个Tag
        selectorExpression = "tagA")
	class ConsumerTest implements RocketMQListener<String> {

	    @Override
	    public void onMessage(String str) {
	        System.out.println(str);
	    }
	}
}

事务消息

  • 事务情况下保证可靠性
@RestController
public class Test{

	@Autowired
	RocketMQTemplate rocketMQTemplate;

    @PostConstruct
    public void sendMessage() {
    	rocketMQTemplate.sendMessageInTransaction("testProducer","test:tagA", new GenericMessage<>("hello"),null);
    }
	@Component
	//事务消息
	@RocketMQTransactionListener(txProducerGroup = "testProducer")
	class TransactionTest implements RocketMQLocalTransactionListener {
	    //执行事务方法,事务逻辑在此处理,处理完以后再由消费者消费
	    @Override
	    public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
	        //如果返回RocketMQLocalTransactionState.COMMIT
	        //那么这条消息消费者可以消费
	        //如果返回UNKNOWN那么对消费者不可见
	        //然后会调用下边的检查方法
	        System.out.println("执行事务方法");
	        return RocketMQLocalTransactionState.UNKNOWN;
	    }
	
	    //如果执行方法出错,那么会检查本地方法是否成功
	    @Override
	    public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
	   		System.out.println("执行事务方法未通过,检察事务");
	        return RocketMQLocalTransactionState.COMMIT;
	    }
	}

	@Component
	@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
        //指定消费哪个Tag
        selectorExpression = "tagA")
	class ConsumerTest implements RocketMQListener<String> {

	    @Override
	    public void onMessage(String str) {
	        System.out.println(str);
	    }
	}
}
  • 输出日志
    Java整合RocketMQ多种消息实现,简单易懂_第9张图片

广播消费和集群消费

  • 广播模式:消费者组中所有的消费者都会消费一次
  • 集群模式:一个消费者组只有一个消费者会消费到
  • 通过注解的messageModel属性设置,默认集群模式
//messageModel:BROADCASTING 广播模式 
//messageModel:CLUSTERING  集群模式 
@RocketMQMessageListener(topic = "test",consumerGroup = "order",selectorExpression = "tagE",
messageModel = MessageModel.BROADCASTING)

消费者组

  • 可以将多个消费者指定同一个comsumerGroup来让他们组成一个消费者组
  • 一定要保证一个JVM中只有一个组的一个成员
  • 比如下边这种两个消费者都指定了同一个消费者组并且在一个JVM中,那么启动会出错,必须分布式的指定为同一个组才可以
@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
        //不指定就是 * 消费所有tag
        selectorExpression = "tagA")
public class ConsumerTest1 implements RocketMQListener<String> {

    @Override
    public void onMessage(String str) {
        System.out.println(str);
    }
}

@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
        //不指定就是 * 消费所有tag
        selectorExpression = "tagA")
public class ConsumerTest2 implements RocketMQListener<String> {

    @Override
    public void onMessage(String str) {
        System.out.println(str);
    }
}

你可能感兴趣的:(笔记,spring,boot,macos,java)