背景
近期我们参与研发的项目里,有些功能涉及到数据的异步处理及跨服务联动。比如对某些数据处理之后,需要调用短信或邮件服务对相关用户发送消息提醒,再比如将A服务里的部分数据推送到B服务里。考虑到各个服务之间需要解耦,减少依赖,而且要保证这些消息提醒,数据推送机制的稳定可靠,我决定引入中间件来处理这类问题。受限于客户的生产运维环境要求,只允许我们用阿里ONS。没办法,我只能临时抱佛脚的研究下ONS。
ONS介绍
阿里ONS是阿里巴巴公司推出的一款分布式消息系统。它基于阿里自主研发的可伸缩消息队列RockeMQ,为广大企业提供高效可靠的消息中间件服务。其主要特点是高可靠性、高吞吐量和高可扩展性。其高可靠性得益于其严格的质量保证体系和多重副本机制,能够在保证消息不丢失的同时提供快速的消息传输服务。高吞吐量和高可扩展性则体现在其分布式和可伸缩的架构设计上,能够支持海量消息的实时处理。此外,阿里ONS还具备灵活的消息订阅模式,支持各种类型的消息发布和订阅方式,适用于不同的业务场景。
ONS实践
下面讲述我的ONS实践之路,从创建账号开始吧。
1、创建阿里账号
2、创建专有网络,登入阿里云平台后,在右上角搜索框搜”专有网络“,进入控制台配置,只有创建专有网络之后,才会有VPC ID,才能购买产品。(我在这里卡了好久,之前一直买不了产品。)
没有VPC ID的时候,去购买ONS服务就如同下图,无法购买。
3、购买阿里ONS产品,因为我只是买来玩的,所以就挑了个最便宜的。购买后,需要配置group和topic,如下:
4、Springboot集成阿里Ons, 我花了好长时间在网上找资料,历经辛苦,踩坑无数,都没法正常的发送和接收消息。要知道我的买的服务是按时间收费的,一小时八毛钱呢!眼瞅着我不惜血本充的10块钱都没了,却还没调通,我就心疼得吃不下饭。一个偶然的机会,我在阿里云帮助中心居然看到了springboot的示例源码,我将代码下载之后,修改了下参数,本地执行,居然成功了。这里附上我能执行成功的测试用例:
<!--maven依赖-->
<dependency>
<groupId>com.aliyun.openservices</groupId>
<artifactId>ons-client</artifactId>
<version>1.8.8.5.Final</version>
</dependency>
import com.aliyun.openservices.ons.api.*;
import com.aliyun.openservices.ons.api.Producer;
import java.util.Properties;
public class LocalProducerTest {
public static void main(String[] args) {
Properties properties = new Properties();
// AccessKey ID,阿里云身份验证标识。获取方式,请参见本文前提条件中的获取AccessKey。
properties.put(PropertyKeyConst.AccessKey, "这里填ons的accessKey");
// AccessKey Secret,阿里云身份验证密钥。获取方式,请参见本文前提条件中的获取AccessKey。
properties.put(PropertyKeyConst.SecretKey, "这里填ons的accessSecret");
//设置发送超时时间,单位毫秒。
properties.setProperty(PropertyKeyConst.SendMsgTimeoutMillis, "3000");
// 设置TCP协议接入点,进入控制台的实例详情页面的TCP协议客户端接入点区域查看。
properties.put(PropertyKeyConst.NAMESRV_ADDR, "这里填tcp协议接入地址");
Producer producer = ONSFactory.createProducer(properties);
// 在发送消息前,必须调用start方法来启动Producer,只需调用一次即可。
producer.start();
Message msg = new Message(
"topic名,要与ons服务里配置的一致",
"tag名,可以随便设",
"Hello MQ".getBytes());
// 设置代表消息的业务关键属性,请尽可能全局唯一。以方便您在无法正常收到消息情况下,可通过控制台查询消息并补发。
// 注意:不设置也不会影响消息正常收发。
msg.setKey("ORDERID_100");
try{
producer.send(msg);
System.out.println("send msg succeed");
}catch (Exception e) {
System.out.println("error occurs");
e.printStackTrace();
}
// 在应用退出前,销毁Producer对象。 注意:如果不销毁也没有问题。
producer.shutdown();
}
}
注意测试用例里的accessKey, secretKey, NAMESRV_ADDR和 topic,这四个配对了一般就能成功发送消息,这里把官网提供的代码地址也贴出来:
如何使用Spring框架集成云消息队列RocketMQ版的SDK收发消息?_云消息队列 RocketMQ 版-阿里云帮助中心
踩坑经历
刚刚说了,SpringBoot ONS Demo 是我花了很多功夫,历尽艰辛才找到的,在找到这个Demo之前,我看了以下这些资料:
JAVA整合阿里云ONS(RocketMQ)_ons-client-CSDN博客
消息队列(RocketMQ):springcloud结合阿里分布式开放消息服务(ONS)实现生产者和消费者实例 - 灰信网(软件开发博客聚合)
如何调用消息队列RocketMQ版的TCP协议SDK收发普通消息_云消息队列 RocketMQ 版-阿里云帮助中心
以上的大部分代码最后经证实都是可以跑通的,那么我在找到Demo之前却死活跑不通,为什么呢,下面记录下我的踩坑历程:
1、最开始我的AccessKey, SecretKey设置的有问题,我是借鉴博客里的写法,用的这里的accessKey
实际上应该用这里的key和Secret:
2、网上很多资料说要配置RAM用户,实际上并不需要
3、如果nameSrvAddr 配错,用户名,密码错误,大概率会报这种错:
4、NAMESRV_ADDR加不加http都可以
5、我在前期调试时反复报这个错,error code: FETCH_TOPIC_ROUTE_FAILURE,在网上找到的原因是如下:
实际上是我前期引入的包版本太新了,我在maven服务器上找到的是最新版本2.0.5.Final,结果报错了。
6、之前我配置的NAMESRV_ADDR是VPC专有网络的接入点信息,实际上应该配公网的。在我看来,专有网络应该是阿里云的一系列服务器配置同一个局域网时才会用到。
7、有些测试用例测不通是因为我抄错东西了,我的实例的类型是tcp,但是我看的用例是http。
http的实例源码在以下地址:
如何快速使用HTTP协议的JavaSDK收发消息_云消息队列 RocketMQ 版-阿里云帮助中心
8、还有一点要注意,我在执行这个方法时,MqListener死活捕捉不到消息,后来发现是ConsumerConfig里把Tag限制死了,这种情况下,MqListener只会监听特定Tag的消息,要想全部收到消息,可以把event设为*
9、通过单元测试的main方法发送消息也是没办法监听的,因为这种方式不会装载Consumer,所以收不到消息,所以建议还是把Springboot应用启动后,通过http调用sendMsg方法试试。
10、ONS启动后,会默认记一个日志在c:\用户\[user]\logs下,用于定位ons执行过程的日志,方便定位问题
以上就是我的ONS实践的全部血泪史了,希望各位大佬看过之后能少走一点弯路。