从 RocketMQ环境搭建_1 我们已经建立了MQ的Server,接下来就是简单的生产和消费的过程。

1. rocketMQ的源码中有个示例代码example  ,我们从Apache官网中可以下载源码source找到example,进行学习。

下载地址:http://rocketmq.apache.org/docs/quick-start/

建立简单的工程,mvn最主要依赖client

  1. <dependency>
  2. <groupId>org.apache.rocketmq</groupId>
  3. <artifactId>rocketmq-client</artifactId>
  4. <version>4.3.</version>
  5. </dependency>

在做transactionProducer时,发现无法消费,问题是需要依赖parent,因此借鉴demo中的mvn依赖:

  1. <parent>
  2. <groupId>org.apache.rocketmq</groupId>
  3. <artifactId>rocketmq-all</artifactId>
  4. <version>4.3.0</version>
  5. </parent>
  6.  
  7. <modelVersion>4.0.0</modelVersion>
  8. <packaging>jar</packaging>
  9. <artifactId>rocketmq-example</artifactId>
  10. <name>rocketmq-example ${project.version}</name>
  11.  
  12. <dependencies>
  13. <dependency>
  14. <groupId>${project.groupId}</groupId>
  15. <artifactId>rocketmq-client</artifactId>
  16. </dependency>
  17. <dependency>
  18. <groupId>${project.groupId}</groupId>
  19. <artifactId>rocketmq-srvutil</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>ch.qos.logback</groupId>
  23. <artifactId>logback-classic</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.javassist</groupId>
  27. <artifactId>javassist</artifactId>
  28. </dependency>
  29. <dependency>
  30. <groupId>io.openmessaging</groupId>
  31. <artifactId>openmessaging-api</artifactId>
  32. </dependency>
  33. <dependency>
  34. <groupId>org.apache.rocketmq</groupId>
  35. <artifactId>rocketmq-openmessaging</artifactId>
  36. <version>4.3.0</version>
  37. </dependency>
  38. </dependencies>

创建Producer类:

  1. /**
  2. * 简单生产者
  3. *
  4. * @author DennyZhao
  5. * @since 2018/10/29
  6. * @version 1.0
  7. */
  8. public class Producer {
  9.  
  10. /**
  11. * main方法
  12. *
  13. * @param args
  14. * @throws InterruptedException
  15. * @throws MQBrokerException
  16. * @throws RemotingException
  17. * @throws MQClientException
  18. * @throws UnsupportedEncodingException
  19. */
  20. public static void main(String[] args) throws MQClientException, RemotingException, MQBrokerException,
  21. InterruptedException, UnsupportedEncodingException {
  22. //创建生产者实例,并确定生产组
  23. DefaultMQProducer producer = new DefaultMQProducer("fruitProducerGroup");
  24. // 指定服务NameServer服务
  25. producer.setNamesrvAddr("192.168.68.137:9876;192.168.68.138:9876;");
  26. // 生产者启动
  27. producer.start();
  28. String[] fruitArray = { "apple", "strawbarry", "pear", "banana", "orange" };
  29. for (String fruit : fruitArray) {
  30. // 创建消息
  31. Message message = new Message("fruit", "common", fruit.getBytes(RemotingHelper.DEFAULT_CHARSET));
  32. // 发送消息
  33. SendResult result = producer.send(message);
  34. SendStatus sendStatus = result.getSendStatus();
  35. // 获取回执
  36. System.out.println(result);
  37. if (sendStatus == SendStatus.SEND_OK) {
  38. System.out.println("信息发送成功!");
  39. } else {
  40. System.out.println("信息发送失败!");
  41. }
  42. }
  43. // 关闭生产者
  44. producer.shutdown();
  45. }
  46. }

创建Consumer类:

  1. /**
  2. * 消費者群體
  3. * @author DennyZhao
  4. * @since 2018/10/29
  5. * @version 1.0
  6. */
  7. public class Consumer {
  8.  
  9. public static void main(String[] args) throws MQClientException {
  10. //创建消费者实例和组
  11. DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("fruitConsumerGroup");
  12. // 指定nameServer服务地址
  13. consumer.setNamesrvAddr("192.168.68.137:9876;192.168.68.138:9876;");
  14. // 订阅消费Topic
  15. consumer.subscribe("fruit", "*");
  16. // 订阅从何地方开始读(先进先出,还是先进后出)
  17. consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
  18. // 添加监听
  19. consumer.registerMessageListener(new MessageListenerConcurrently() {
  20.  
  21. //获取数据,防止一次获取太多无法消化,可一次取单个条数。
  22. public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgList, ConsumeConcurrentlyContext arg1) {
  23. if(msgList != null && msgList.size() > 0) {
  24. MessageExt msg = msgList.get(0);
  25. System.out.println(msg);
  26. try {
  27. System.out.println(new String(msg.getBody(), RemotingHelper.DEFAULT_CHARSET));
  28. } catch (UnsupportedEncodingException e) {
  29. // TODO Auto-generated catch block
  30. e.printStackTrace();
  31. }
  32. }
  33. return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
  34. }
  35.  
  36. });
  37. // 启动消费者
  38. consumer.start();
  39. }
  40. }

※注意:启动最好先启动消费者然后再启动服务者。

从RocketMQ-console中可以看到创建的消费者群和生产者群。至此,简单的生产消费就算大功告成。

配置说明:

1.producer-生产者类型

  • 1. NormalProducer         (普通生产者)
  • 2. OrderProducer           (严格顺序生产者,例如:订单创建,付款,发货等)
  • 3. TransactionProducer  (事务生产者)

msgId和msgKey非常关键:msgId是mq自动生成的,可在控制台message中查找数据。

msgKey大多是业务主键key,用于跟踪数据,比如订单号等。

msg中有个很重要的属性:在producer端放置:msg.putUserProperty([key],  [value]);  //是个map,可放内容,在consumer端获取

主要可选参数:

  1. // 设置超过多大进行compress压缩
  2. producer.setCompressMsgBodyOverHowmuch(1024 * 10);
  3. // 设置发送失败的尝试次数。
  4. producer.setRetryTimesWhenSendFailed(3);
  5. // 设置如果返回值不是send_ok,是否要重新发送
  6. producer.setRetryAnotherBrokerWhenNotStoreOK(false);
  7. // 设置限制最大的文件大小
  8. producer.setMaxMessageSize(1024*50);
  9. // 设置默认主题对应的队列数
  10. producer.setDefaultTopicQueueNums(4);
  11. //创建新的topic
  12. producer.createTopic("1121", "vegetables", 4);
  13. // 设置发送超时时间 ms
  14. producer.setSendMsgTimeout(1000);

OrderProducer 采用将有序内容放在单个queue,保证消费的顺序进行。可参见示例中的order代码。

Producer类不同点展示,发送消息:

  1. // 发送消息
  2. SendResult result = producer.send(message, new MessageQueueSelector() {
  3. public MessageQueue select(List<MessageQueue> msgList, Message message, Object queueId) {
  4. return msgList.get(Integer.valueOf(queueId.toString()));
  5. }}, 0); //这个0表示将这些msg放入到队列0中

Consumer类不同点展示,接受消息:

  1. // 添加监听
  2. consumer.registerMessageListener(new MessageListenerOrderly() {
  3.  
  4. //获取数据,防止一次获取太多无法消化,可一次取单个条数。
  5. public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgList, ConsumeOrderlyContext arg1) {
  6. if(msgList != null && msgList.size() > 0) {
  7. MessageExt msg = msgList.get(0);
  8. System.out.println(msg);
  9. System.out.println(msg.getBody());
  10. }
  11. return ConsumeOrderlyStatus.SUCCESS;
  12. }
  13.  
  14. });

TransactionProducer :

用于解决事务同步,尤其是金融方面,在单体应用中我们可以通过数据库事务来控制,但大的电商系统表和表可能分属于不同的数据库,数据库事务则失效。

比如微信转银行操作:我们从银行扣款100元到微信,如果微信增加100元,而此时出现问题,银行扣款没有成功这样理论上是要回滚微信的增加100元。

一般分布式采用2pc(2 phase commit)模式(两阶段提交协议:预留和确认),安全性高,但是因为长连接导致长时间等待。

而RocketMQ采用两阶段补偿型,TCC(Try-Confirm-Cancel)的简称。

应用场景:买2张票(春运回家,从天津->上海->武汉),先买预留,然后在规定时间内付款则commit,否则过期后rollback.(无论哪个)

异常回溯:在3.2.6+版本的非商业版已经取消,

需要手动回查参见别人的文章RocketMQ事务消息回查设计方案

常对应参数:

  1. /**
  2. * 做数据反查轮询用 UN KNOW,时会用到反查目前已经 deprecated
  3. */
  4. producer.setCheckThreadPoolMaxSize();
  5. producer.setCheckThreadPoolMinSize();
    producer.setCheckRequestHoldMax(200);//回查最大数

生产者修改:添加

  1. sendMessage变化:TransactionSendResult
    producer变化: TransactionMQProducer
    添加监听: TransactionListener
    因非商业3.2.6取消回查:因此 producer.setExecutorService(executorService);没有作用,本来是用于开启多线程进行回查用
  1. /**
  2. * 事务生产者
  3. *
  4. * @author DennyZhao
  5. * @since 2018/10/31
  6. * @version 1.0
  7. */
  8. public class Producer {
  9.  
  10. /**
  11. * main方法
  12. *
  13. * @param args
  14. * @throws InterruptedException
  15. * @throws MQBrokerException
  16. * @throws RemotingException
  17. * @throws MQClientException
  18. * @throws UnsupportedEncodingException
  19. */
  20. public static void main(String[] args) throws MQClientException, RemotingException, MQBrokerException,
  21. InterruptedException, UnsupportedEncodingException {
  22. //创建生产者实例,并确定生产组
  23. TransactionMQProducer producer = new TransactionMQProducer("transProducerGroup");
  24. TransactionListener transListener = new FruitTransactionListener();
  25. // 指定服务NameServer服务
  26. producer.setNamesrvAddr("192.168.68.137:9876;192.168.68.138:9876;");
  27. // // 设置超过多大进行compress压缩
  28. // producer.setCompressMsgBodyOverHowmuch(1024 * 10);
  29. // // 设置发送失败的尝试次数。
  30. // producer.setRetryTimesWhenSendFailed(3);
  31. // // 设置如果返回值不是send_ok,是否要重新发送
  32. // producer.setRetryAnotherBrokerWhenNotStoreOK(true);
  33. // // 设置限制最大的文件大小
  34. // producer.setMaxMessageSize(1024*50);
  35. // // 设置默认主题对应的队列数
  36. // producer.setDefaultTopicQueueNums(4);
  37. // // 设置发送超时时间 ms
  38. // producer.setSendMsgTimeout(1000);
  39. /**
  40. * 做数据反查轮询用
  41. */
  42. // producer.setCheckThreadPoolMaxSize(5);
  43. // producer.setCheckThreadPoolMinSize(2);
  44. // producer.setCheckRequestHoldMax(200);//回查最大数
  45.  
  46. ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2000), new ThreadFactory() {
  47.  
  48. public Thread newThread(Runnable r) {
  49. Thread th = new Thread(r);
  50. th.setName("client-transaction-msg-check-thread");
  51. System.out.println("id:" + th.getId());
  52. System.out.println("name:" + th.getName());
  53. return th;
  54. }
  55. });
  56. producer.setExecutorService(executorService);
  57. /**
  58. * 添加监听
  59. */
  60. producer.setTransactionListener(transListener);
  61.  
  62. // 生产者启动
  63. producer.start();
  64. String[] fruitArray = { "apple-苹果", "strawbarry-草莓", "pear-梨子", "banana-香蕉", "orange-橘子"};
  65. for (String fruit : fruitArray) {
  66. // 创建消息
  67. Message message = new Message("transactionFruit", "common", "key"+fruit, fruit.getBytes(RemotingHelper.DEFAULT_CHARSET));
  68. // 发送消息
  69. TransactionSendResult result = producer.sendMessageInTransaction(message, "abcd");
  70. Thread.sleep(10);
  71. SendStatus sendStatus = result.getSendStatus();
  72. // 获取回执
  73. System.out.println(result);
  74. if (sendStatus == SendStatus.SEND_OK) {
  75. System.out.println("信息发送成功!");
  76. } else {
  77. System.out.println("信息发送失败!");
  78. }
  79. }
  80. int j = 0;
  81. while(j <500) {
  82. Thread.sleep(1000);
  83. j++;
  84. }
  85. // 关闭生产者
  86. producer.shutdown();
  87. }

监听:

  1. 因回查被取消因此:checkLocalTransaction(MessageExt msg)没有作用了,所以如果
  1. LocalTransactionState.UNKNOW 将无法处理,会使得topic一直处于不显示状态。
  1. /**
  2. * 事务执行监听
  3. * @author DennyZhao
  4. *
  5. */
  6. public class FruitTransactionListener implements TransactionListener {
  7.  
  8. /**
  9. * 执行事务,事务成功commit,不成功rollback,未知unknown
  10. * msg Message
  11. * arg 附加参数,用于处理传递内容加以判断,使用
  12. *
  13. */
  14. public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
  15. System.out.println((String) arg);
  16. // 执行事务处
  17. // 假设以水果入库为例:苹果,香蕉 commit,梨子 rollback, 橘子和草莓不知道怎么处理
  18. System.out.println(msg + "---executeLocal");
  19. System.out.println(msg.getTransactionId());
  20. String fruit = "";
  21. try {
  22. fruit = new String(msg.getBody(), RemotingHelper.DEFAULT_CHARSET);
  23. } catch (UnsupportedEncodingException e) {
  24. e.printStackTrace();
  25. return LocalTransactionState.ROLLBACK_MESSAGE;
  26. }
  27.  
  28. if(StringUtils.contains(fruit, "苹果")
  29. || StringUtils.contains(fruit, "香蕉")) {//提交
  30. return LocalTransactionState.COMMIT_MESSAGE;
  31. }else if(StringUtils.contains(fruit, "梨")) {//回滚
  32. return LocalTransactionState.ROLLBACK_MESSAGE;
  33. }else { //通过轮询去处理
  34. return LocalTransactionState.UNKNOW;
  35. }
  36. }
  37.  
  38. /**
  39. * 轮询反查,对于unknow的内容,进行反查获取结果
  40. */
  41. public LocalTransactionState checkLocalTransaction(MessageExt msg) {
  42. System.out.println(msg + "---checkAgain");
  43. String fruit = "";
  44. try {
  45. fruit = new String(msg.getBody(), RemotingHelper.DEFAULT_CHARSET);
  46. } catch (UnsupportedEncodingException e) {
  47. e.printStackTrace();
  48. return LocalTransactionState.ROLLBACK_MESSAGE;
  49. }
  50. //从库中反查知道库中 存在葡萄,不存在橘子
  51. if(StringUtils.contains(fruit, "葡萄")) {//提交
  52. return LocalTransactionState.COMMIT_MESSAGE;
  53. }else if(StringUtils.contains(fruit, "橘子")) {//回滚
  54. return LocalTransactionState.ROLLBACK_MESSAGE;
  55. }
  56. return LocalTransactionState.UNKNOW;
  57. }

错误说明:

1. No route info of this topic

因在启动broker时,参数中未设置可自动创建topic,因此生产者创建topic被认为不合法,需要在console中先创建topic,或者服务端先创建topic。

2. transactionProducer 生产后无法消费

mvn依赖中缺少 <parent>rocketmq-all</parent>导致。

3. 事务回查无效

版本 3.2.6 后rocketmq取消了事务回查机制,如果丢失需要自己手动通过key值回查.

RocketMQ入门(生产者)_2的更多相关文章

  1. RocketMQ入门(消费者)_3

    消费者角色: 1. 推式(一般建议用推式) 2. 拉式 消费模式: 1. 集群(cluster)                --均衡负载消费 2. 广播(broadcasting) --发布和订阅 ...

  2. RocketMQ入门(2)最佳实践

    转自:http://www.changeself.net/archives/rocketmq入门(2)最佳实践.html RocketMQ入门(2)最佳实践 一.服务端安装部署 我是在虚拟机中的Cen ...

  3. 必须先理解的RocketMQ入门手册,才能再次深入解读

    RocketMQ入门手册 RocketMQ是一个分布式.队列模型的开源消息中间件,前身是MetaQ,是阿里研发的一个队列模型的消息中间件,后开源给apache基金会成为了apache的顶级开源项目,具 ...

  4. RocketMQ入门到入土(二)事务消息&顺序消息

    接上一篇:RocketMQ入门到入土(一)新手也能看懂的原理和实战! 一.事务消息的由来 1.案例 引用官方的购物案例: 小明购买一个100元的东西,账户扣款100元的同时需要保证在下游的积分系统给小 ...

  5. RocketMQ入门(3)拉取消息

    转自:http://www.changeself.net/archives/rocketmq入门(3)拉取消息.html RocketMQ入门(3)拉取消息 RocketMQ不止可以直接推送消息,在消 ...

  6. RocketMQ入门(1)

    转自:http://www.changeself.net/archives/rocketmq入门(1).html RocketMQ入门(1) RocketMQ是一款分布式.队列模型的消息中间件,具有以 ...

  7. 【rocketmq学习笔记】rocketmq入门学习

    基本介绍 rocketmq是阿里巴巴团队使用java语言开发的一款基于发布订阅模型的分布式消息队列中间件,是一款低延迟,高可用,拥有海量消息堆积能力和灵活拓展性的消息队列. 特点 可以实现集群无单点故 ...

  8. 消息队列之-RocketMQ入门

    简介 RocketMQ是阿里开源的消息中间件,目前已经捐献个Apache基金会,它是由Java语言开发的,具备高吞吐量.高可用性.适合大规模分布式系统应用等特点,经历过双11的洗礼,实力不容小觑. 官 ...

  9. 轻松搞定RocketMQ入门

    RocketMQ是一款分布式.队列模型的消息中间件,具有以下特点: 能够保证严格的消息顺序 提供丰富的消息拉取模式 高效的订阅者水平扩展能力 实时的消息订阅机制 亿级消息堆积能力 RocketMQ网络 ...

随机推荐

  1. MySQL Hardware--CentOS 6修改CPU性能模式

    cpufrequtils命令 ## 安装: yum install cpufrequtils ## 查看CPU信息: cpufreq-info -m 输出CPU信息为: analyzing CPU : ...

  2. 树莓派3 Raspberry系统安装samba

    默认Raspberry不自带samb,需要手动安装. 如果默认的rasp源不好用的话,可以使用下面从网上找的: deb http://mirrors.cqu.edu.cn/Raspbian/raspb ...

  3. Django 00-socket、wsgi及初始django学习心得

    HTTP基本原理1.http简述:http协议永远都是客户端发起请求,服务端回送请求.客户端和服务端本质上是一个socket客户端和服务端,http协议可以说是基于socket的再上层封装2.http ...

  4. Java面向对象程序设计的六大基本原则

    1.开闭原则(Open Close Principle) 定义:一个软件实体如类.模块和函数应该对扩展开放,对修改关闭. 开放-封闭原则的意思就是说,你设计的时候,时刻要考虑,尽量让这个类是足够好,写 ...

  5. security cookie 机制(2)--- 初始化___security_cookie

    在 cookie 检查中,必定先要取出初始的 cookie 值: 0011392E A1 14 70 11 00       mov         eax,dword ptr [___securit ...

  6. Centos 7 修改日期和时间的命令

    timedatectl set-ntp no //关闭时间动态更新timedatectl set-time "YYYY-MM-DD HH:MM:SS" //设置时间和日期timed ...

  7. shibie

    var mStream: TMemoryStream; vcode: ..] of AnsiChar; buffer: array of AnsiChar; begin mStream := TMem ...

  8. oc 语法基础

    1:https://mp.weixin.qq.com/s/IqICB4aW2vZdU0382S9sTA  <1-7高质量OC代码> 2:https://blog.csdn.net/qq_3 ...

  9. squid 3.5 window x64

    下载1: https://download.csdn.net/download/runliuv/11131620 下载2: 链接: https://pan.baidu.com/s/1A_o_Xvg1y ...

  10. python简明教程代码

    #!user/bin/env python #-*- coding:utf-8 -*- # code001 print('hello world') (only one quotation mark, ...