Article / 文章中心

平安保险基于 SPI 机制的 RocketMQ 定制化应用

发布时间:2022-01-25 点击数:1403
01

为什么选用 RocketMQ

Cloud Native


首要跟咱们聊聊咱们为什么会选用 RocketMQ,在做技能选型的进程中,运用场景应该是最先考虑清楚的,只要确认好了运用场景在做技能选型的进程中才有清晰的目标和衡量的标准。像异步、解耦、削峰填谷这些音讯中间件共有的特性就不逐个介绍了,这些特性是决议你的场景需不需求运用音讯中间件,这儿主要讲述下在确认运用音讯中间件后,又是怎么去选择哪款音讯中间件的。
1 同步双写,确保事务数据安全可靠不丢失


咱们在搭建音讯中间件平台时的定位是给事务体系做事务数据的传输运用,对事务数据的很重要的一个要求便是不允许丢数据,所以选用 RocketMQ 的第一点便是他有同步双写机制,数据在主从服务器上都刷盘成功才算发送成功。同步双写条件下,MQ 的写入功能与异步刷盘异步赋值相比肯定会有所下降,与异步条件下大约会有 20% 左右的下降,单主从架构下,1K 的音讯写入功能仍是能到达 8W+ 的 TPS,对大部分事务场景而言功能是能完全满意要求的,别的对下降的这部分功能能够经过 broker 的横向扩招来补偿,所以在同步双写条件下,功能是能满意事务需求的。
2 多 topic 运用场景下,功能仍旧强悍


第二点,事务体系的运用场景会特别多,运用场景广泛带来的问题便是会创立很多的 topic,所以这时分就得去衡量音讯中间件在多 topic 场景下功能是否能满意需求。我自己在测验的时分呢,用 1K 的音讯随机往 1 万个 topic 写数据,单 broker 状态下能到达2W左右的 TPS,这一点比 Kafka 要强许多。所以多 topic 运用场景下,功能仍旧强悍是咱们选用 topic 的第二个原因。这点也是由底层文件存储结构决议的,像 Kafka、RocketMQ 这类音讯中间件能做到接近内存的读写能力,主要取决于文件的次序读写和内存映射。RocketMQ 中的一切 topic 的音讯都是写在同一个 commitLog 文件中的,可是 Kafka 中的音讯是以 topic 为基本单位安排的,不同的 topic 之间是彼此独立的。在多 topic 场景下就造成了很多的小文件,很多的小文件在读写时存在一个寻址的进程,就有点相似随机读写了,影响整体的功能。
3 支撑事务音讯、次序音讯、推迟音讯、音讯消费失利重试等


RocketMQ 支撑事务音讯、次序音讯、音讯消费失利重试、推迟音讯等,功能比较丰富,比较适合杂乱多变的事务场景运用
4 社区建设活泼,阿里开源体系

别的,在选用音讯中间件时也要考虑下社区的活泼度和源码所运用的开发言语,RocketMQ 运用 Java 开发,对 Java 开发人员就比较友爱,不管是阅览源码排查问题仍是在 MQ 的基础上做二次开发都比较简略一点。社区里同学大都是国内的小伙伴,对咱们参加 RocketMQ 开源奉献也是比较接近的,这儿呢也是期望更多的小伙伴能参加进来,为国内开源项目多做奉献。


02

SPI 机制简介及运用

Cloud Native


介绍完为什么选用 RocketMQ 后,接下来给咱们介绍下咱们是怎么基于 SPI 机制运用 RocketMQ 的。SPI 全称为 (Service Provider Interface) ,是 JDK 内置的一种服务供给发现机制,我个人简略理解便是面向接口编程,留给运用者一个扩展的点,像 springBoot 中的 spring.factories 也是 SPI 机制的一个运用。如图给咱们展示的是 RocketMQ 中 SPI 的一个运用。咱们基于 SPI 机制的 RocketMQ 客户端的运用的灵感也是来自于 MQ 中 SPI 机制的运用。RocketMQ 在完成 ACL 权限校验的时分,是经过完成 AccessValidator 接口,PlainAccessValidator 是 MQ 中的默许完成。权限校验这一块,或许由于安排架构的不一样会有不同的完成办法,经过 SPI 机制供给一个接口,为开发者定制化开发供给扩展点。在有定制化需求时只需求重新完成 AccessValidator 接口,不需求对源码大动干戈。




接下来先给咱们介绍下咱们装备文件的一个简略模型,在这个装备文件中除了 sendMsgService、consumeMsgConcurrently、consumeMsgOrderly 这三个装备项外其他的都是 RocketMQ 原生的装备文件,发送音讯和消费音讯这三个装备项呢便是 SPI 机制的运用,是为详细完成供给的接口。或许有的同学会有疑问,SPI 的装备文件不是应该放在 META-INF.service 途径下么?这儿呢咱们是为了便利装备文件的办理,索性就跟 MQ 装备文件放在了一同。前面也提到了,META-INF.service 仅仅一个默许的途径罢了,为了便利办理做相应的修正也没有违背SPI机制的思维。
咱们再看下这个装备文件模型,这儿的装备项呢包括了运用 MQ 时所要装备的一切选项,proConfigs 支撑一切的 MQ 原生装备,这样呢也就完成了装备与运用完成的解耦,运用端只需呀重视的详细的事务逻辑即可,出产者顾客的完成和顾客消费的 topic 都能够经过装备文件来指定。别的该装备文件也支撑多 nameserver 的多环境运用,在较杂乱的运用中支撑往多套 RocketMQ 环境发送音讯和消费多套不同环境下的音讯。顾客供给了两个接口主要是为了支撑 RocketMQ 的并发消费和次序消费。接下来呢给咱们共享下怎么依据这个装备文件来初始化出产者顾客。首要给咱们先介绍下咱们抽象出来的客户端加载的一个中心流程。
03

客户端中心流程概况

Cloud Native




图中咱们能够看到,客户端的中心流程咱们抽象成了三部分,分别是发动期、运行期和停止期。首要加载装备文件呢便是加载刚刚介绍的那个装备文件模型,在装备与运用完全解耦的状态下,必须先加载完装备文件才能初始化后续的流程。在初始化出产者和顾客之前应当先创立好运用完成的出产者和顾客的事务逻辑目标 供出产者和顾客运用。在运行期监听装备文件的变化,依据变化动态的调整出产者和顾客实例。这儿仍是要再强调下装备与运用的解耦为动态调整供给了或许。停止期就比较简略了,便是封闭出产者和顾客,并从容器中移除。这儿的停止期指的出产者和顾客的停止,并不是整个运用的停止,出产者和顾客的停止或许出现在动态调整的进程中,所以停止了的实例必定要从容器中移除,便利初始化后续的出产者和顾客。介绍完基本流程后,接下来给咱们介绍下装备文件的加载进程。
1 怎么加载装备文件




装备文件加载这一块的话,流程是比较简略的。这儿主要讲的是怎么去兼容比较老的项目。RocketMQ 客户端支撑的 JDK 最低版本是 1.6,所以在封装客户端时应该要考虑到新老项目兼容的问题。在这儿呢咱们客户端的中心包是支撑 JDK1.6 的,spring 早期的项目装备文件一般都是放在在 resources 途径下,咱们是自己完成了一套读取装备文件的和监听装备文件的办法,详细的咱们能够参阅 acl 中装备文件的读取和监听。在中心包的基础上用 springBoot 又封装了一套主动加载装备文件的包供微服务项目运用,装备文件的读取和监听都用的 spring 的那一套。装备文件加载完之后, 装备文件中运用完成的出产者和顾客是怎么与 RocketMQ 的出产者和顾客相相关的呢?接下来给咱们共享下这方面的内容。
2 怎么将出产顾客与事务完成相关




首要先看下顾客是怎么完成相关的,上图是 MQ 顾客的音讯监听器,需求咱们去完成详细的事务逻辑处理。经过将装备文件中完成的消费逻辑相关到这儿就能完成装备文件中的顾客与 RocketMQ 顾客的相关。顾客的接口界说也是很简略,便是去消费音讯。消费音讯的类型能够经过泛型指定,在初始化顾客的时分获取详细完成的参数类型,并将


MQ 接受到的音讯转换为详细的事务类型数据。由客户端一致封装好音讯类型的转换。对消费音讯的返回值咱们能够依据需求与 MQ 供给的 status 做一个映射,这儿的 demo 仅仅简略显现了下。在获取详细的运用顾客实例的时分,假如你的消费逻辑里运用了 spring 办理的目标,那么你完成的消费逻辑目标也要交给 spring 办理,经过 spring 上下文获取初始化好的目标;假如你的消费逻辑里没有运用 spring 进行办理,能够经过反射的办法自己创立详细的运用实例。



与顾客不一样的是出产者需求将初始化好的 producer 目标传递到运用代码中去,而顾客是去获取运用中完成的逻辑目标,那怎么将 producer 传递到事务运用中去呢?事务代码中完成的出产者需求继承 SendMessage,这样事务代码就获得了 RmqProducer 目标,这是一个被封装后的出产者目标,该目标对发送音讯的办法进行的标准化界说,使之符合公司的相应标准制度,该目标中的办法也会对 topic 的命名标准进行检查,标准 topic 有一个一致的命名标准。
3 怎么动态调整出产顾客




首要谈到动态调整就需求谈一下动态调整产生的场景,假如没有合适的运用场景的话完成动态调整就有点华而不实了。这儿我列举了四个装备文件产生变化的场景:
nameserver产生变化的时分,需求重新初始化一切的出产者和顾客,这个一般是在 MQ 做搬迁或许当时 MQ 集群不可用是需求紧迫切换 MQ;
增减实例的场景只要发动或封闭相应的实例即可,添加运用实例的场景一般是在需求添加一个顾客来消费新的 topic 的,减少顾客一般是在某个顾客产生反常时需求紧迫封闭这个顾客,及时止损。
调整顾客线程的场景中咱们对源码进行了一点修正,让运用端能获取到顾客的线程池目标,以便对线程池的中心线程数进行动态调整。这个的运用场景一般是在当某个顾客消费的数据比较多,占用过多的 CPU 资源时,导致优先级更高的音讯得不到及时处理,能够先将该顾客的线程调小一些。