如何实现一个简单易用的 rocketmq sdk | java 技术论坛-金年会app官方网
2018 年,做为架构负责人,接到一个架构需求:实现一个简单易用的 rocketmq sdk 。
因为各个团队 rocketmq 原生客户端配置起来千奇百怪,有的配置存在风险,各团队负责人都需要一个简洁易用的 rocketmq sdk 。
我立马调研相关开源的方案,当时 rocketmq-spring 项目并没有开源,而阿里云的 ons sdk 是开源的,我只能讲目标转向 阿里云 ons 。
通过学习 ons 的设计方式,我对于 rocketmq 的客户端原理有了进一步了解,同时参考 ons 的设计,也实现了公司内部使用的 rocketmq sdk 。
项目地址:
之所以说简单,就是让用户(开发者)使用 sdk 时,减少心智负担。
举三个例子:
使用原生代码发送消息时,会使用如下的代码:
sendresult sendresult = producer.send(msg, new messagequeueselector() {
@override
public messagequeue select(list<messagequeue> mqs, message msg, object arg) {
integer id = (integer) arg;
int index = id % mqs.size();
return mqs.get(index);
}
}, orderid);
我们可以将 sdk api 简化为:
sendresult send(final producermessage message, final string shardingkey);
开发者不需要定义队列选择器,只需要传递分片键 orderid 即可。
使用原来代码定义消费监听器时,使用如下的代码:
consumer.registermessagelistener(new messagelistenerconcurrently() {
@override
public consumeconcurrentlystatus consumemessage(list<messageext> msgs, consumeconcurrentlycontext context) {
system.out.printf("%s receive new messages: %s %n", thread.currentthread().getname(), msgs);
// 返回消息消费状态,consumeconcurrentlystatus.consume_success为消费成功
return consumeconcurrentlystatus.consume_success;
}
});
监听器内部,对于开发者操作的对象是消息列表 msgs ,很多开发同学想只操作一条消息。
于是,我们可以将 sdk api 简化为:
consumer.subscribe("mytest", new consumerlistener() {
@override
public consumeraction consumer(consumermessage msg) {
byte[] body = msg.getbody();
system.out.println("msg:" new string(body));
return consumeraction.commitmessage;
}
});
开发者在消费时,可以一条一条操作,代码简洁了不少。
同时,很多开发者在使用普通消费、顺序消费时,需要返回延时消费的状态码时,两种消费模式定义的枚举也不相同。我们将枚举做了统一:
/**
* 消费消息的返回结果
*/
public enum consumeraction {
/**
* 消费成功,继续消费下一条消息
*/
commitmessage,
/**
* 消费失败,告知服务器稍后再投递这条消息,继续消费其他消息
*/
reconsumelater;
}
实际场景里,订阅关系不一致是极容易发生的事情,就算是高级别的架构师也会翻车,每次翻车现场都是惨不忍睹。
正确的订阅关系见下图:
代码逻辑角度来看,每个消费者实例内订阅方法的主题、 tag、监听逻辑都需要保持一致。
当订阅关系不一致时,在 broker 端同一个消费组内的各个消费者客户端的订阅信息相互被覆盖,从而导致某个消费者客户端无法拉取到新的消息。
怎么解决呢 ?
我当时想起了阿里技术专家沈询的一句话:
世界上解决一个计算机问题最简单的方法:“恰好”不需要解决它 !
公司内部出现订阅关系一致99%的问题是:消费者组一致的前提下,主题相同,但 tag 不相同。
基于此,我的设计思路就明确了:不开放订阅 tag 的权限!
没想到吧,我就是这么粗暴。
按照这种设计思路,虽然开始有的程序员会有质疑,但你和他梳理好消费者组的定义,以及做好领域划分,对业务来讲,反而清晰了。
我并不认为我们写得多么的好,只是想让同学们理解:
1、成长的第一步就是模仿;
2、把开发者当用户,以用户的体验为先。
我经常去阅读阿里云产品的 sdk , 去思考他们为什么这么设计, 为什么和开源的有所不同,有的时候开始没想明白,但模仿得多了,好像也慢慢懂了。
要紧的是果敢地迈出第一步,对与错先都不管,自古就没有把一切都设计好再开步的事。
别想把一切都弄清楚,再去走路。鲁莽者要学会思考,善思者要克服的是犹豫。
——史铁生
如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!
本作品采用《cc 协议》,转载必须注明作者和本文链接