突然资讯网
首页 >> 科技 >> 正文

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次

日期:2020-02-15 12:24:21 来源:互联网 编辑:小TT 阅读人数:596

1 概述

中间件就是在分布式中间引入一个透明的中间层,隔离服务的提供方和消费方。

2 为什么要引入MQ

2.1何为MQ

队列(MQ)是一种不同应用程序之间(跨进程)的通信方法,用于上下游应用程序之间传递。我们拆分来看:

l :应用程序通过写入和检索出入列队的数据来通信。

l 队列:除去了接收和发送应用程序同时执行的要求。

这样就实现了上游与下游之间的解耦,上游向MQ发送,下游从MQ接收,上游下游互不依赖,它们只依赖MQ。因为有队列的存在,MQ可在上下游之间进行缓冲,把上游信息先缓存起来,下游根据自己的能力从MQ中拉去信息,起到削峰的作用。

2.2 使用MQ带来的好处

2.2.1 解耦

l 什么是耦合

高内聚低耦合,是软件工程中的概念,这里的低耦合是指各个组件之间,尽可能相互独立。通俗一点的理解就是,增加模块间调用透明化,最高的透明度就是不用知道彼此的存在,因此减少接口的复杂性、规范调用的方式及传递的信息,降低产品各模块的依赖,提高重用程度。

l 如何解耦

在企业整体架构中解耦,主要设计两个方面:一是简化减少交互,二是增加一个中间层实现两方的隔离,MQ就是其中的中间层(如下图所示)

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次封装建议 封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处: 5 典型场景 6 哪些场景不适合MQ 7 经验总结和建议(图1)

1 生产者负责:生产并通过SDK或API调用发送给MQ同步发送或者异步发送

2 MQ负责:接收,并持久化到存储同步或异步存储

3 生产者接收来自MQ的响应发送状态或异常

5 消费者执行对应的后续业务操作。

6 对消费结果进行确认消费成功、失败、异常等

2.2.2 削峰填谷

由于闲忙分布不均,QPS常相差几十倍甚至更高,特别是在遇到营销活动时,瞬间流量很可能超过后端的承载能力,这就要考虑通过中间件来缓冲,MQ客户端实例根据自己的处理能力从MQ拉取,以此来减轻或消除后端的瓶颈。

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次封装建议 封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处: 5 典型场景 6 哪些场景不适合MQ 7 经验总结和建议(图2)

2.2.3 异构集成

由于各种原因,我们在企业信息化建设过程中,都会面临软件产品来自不同的厂家只解决某特定领域的问题,这些产品因为封闭的架构无法对外提供服务或缺少核心而无法做大的改造,这就造成了彼此之间很难集成。通过引入MQ可以部分解决该问题,只需要在某个环节生产一条,或者根据做出具体的响应,只需与MQ对接,不必与其他做一对一的对接。

2.2.4异步隔离

为了提供金融服务的整体弹性,需要隔离内部、外部间的依赖。如支付分为两种,一种是同步,这时API调用会因为网络故障而超时,因为服务提供方处理能力限制而得不到及时响应…等多种因素影响,另一种是异步,在一定时效范围内最终到即可,从而提供提高最终用户的体验和交易成功率,提高业务的整体生产率。

3 MQ选型

3.1 关键需求

1 集群支持:为了保证中间件的可靠性,需要提供完备的生产者、消费者、中间件集群方案。

2 持久化的支持:为了避免丢失,需要支持保存到磁盘文件或其它格式存储。

3 重试的支持:处理失败后的支持失败转存或重试,并提供至少投第一次或最多投递一次的配置。

4 分布式事务的支持:为了保证业务的完整性,选择的中间件需要支持分布式。

5 的按序消费:在有些场景下,需要的消费能够按照发送的同样顺序进行处理从而保证顺序执行。

6 的延时支持:在2C业务处理或三方数据源对接中,会遇到延时投递要求,需要支持延投递。

7 堆积和回溯功能:在中间件持久化保存大量时不会对性能有大的影响,支持查询、重发,或者按照时间点来重新消费,以应对某一段时间的重新消费场景。

3.2 其它需要考虑的因素

1 产品与当前技术栈是否匹配,团队人员熟悉源代码更便于对中间件的原理理解和后续功能扩展。

3 产品的高可用性:作为一个金融企业,需要服务的持续可用,作为提高企业弹性的基础平台,集群和高可用是一个必不可少的要求。

4 产品的稳定性:产品可以持续、稳定的提供服务,不需要经常因为资源泄露或性能衰减等问题而重新启动。

5 产品的活跃度:通过github统计数据能看出来这个产品是否经常有人维护,经常有人一些新的功能,经常fix一些bug。

3.3 选型要点及原则

l 搜寻满足关键需求的框架到候选清单。

l 从功能和非功能性需求等几个方面对候选框架进行筛选。

l 在帅选过程中要做好量化记录,避免先有倾向性的结果,后有筛选,这样选型就变成了一场数字游戏。

l 有时要换个角度思考,常用来做比较的可能就是最好的,如很多MQ框架都与Kafka做比较,那么Kafka有可能就是最通用的框架,如果做选型就要对其是否满足自己的需求做重点分析。

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次封装建议 封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处: 5 典型场景 6 哪些场景不适合MQ 7 经验总结和建议(图3)

l 遵循第三眼美女原则,让理性引导感性。

l 适合的就是最好的,不要但纯追求高性能和功能全面。

3.4 选型建议

l 为未来最少三年或五到十年来选择,因为TedNeward在JAVA 服务的序言中总结了技术熟悉的过程4个阶段门外汉、探索者、熟手、。选型到全范围推广结束一年左右的时间就过去了,到大家熟悉和精通又一年过去了,谁都不想在刚熟悉还没用好,当前的产品就不满足要求了,又要重新来过。

l 给出选择的deadline,并按时进入到项目实战准备,再多的理论分析,都不如真正使用过后的感受深入,产品需要成长、团队成员同样需要成长,既然路在远方就赶紧起程。

3.5 候选产品比较

3.5.1 产品特性比较

3.5.2 :

功能:建议搭建POC环境进行验证,除验证相关功能性指标有没有,还要验证好不好用。所以在时要基于MQ提供的功能构建使用场景进行业务功能实现的验证。

疲劳:在一定压力下持续运行24小时、一周或更长时间,稳定性如何?的各项指标如何?是否有缓慢增长的趋势等?

重启或故障演练:分别对注册中心NameServer、Broker、Producer、Consumer的实例进行部分重启(或直接kill)或全部重启(或直接kill)磁盘故障、网络故障等,查看应用的影响,如:在RocketMQ服务是否可以恢复,生产者消费者是否可以恢复服务,是否有丢失,是否有重复等。

3.6 选择RocketMQ的原因

l ActiveMQ的优势在于支持协议多样、文档资料丰富,缺点是性能、顺序投递支持有限。

l Kafka的优势在于高吞吐率,缺点是分布式事务、消费失败重试、延时/定时支持有限。

l RabbitMQ的优势在于与SpringBoot集成好,缺点是分布式事务、延时/定时支持有限。

l RockeMQ的优势在于高吞吐率、顺序、延时、堆积、回溯等支持较好,缺点是支持协议有限,多语言客户端支持有限。

我们最终选择RocketMQ的主要原因如下:

l 金融服务有场景对顺序有严格要求。

l 金融服务有场景对延时需求。

l 为了保证最终一致性需要支持分布式事务。

l 为了保证一致性对账需要MQ中间件支持查询。

l RocketMQ在高一致性(持久化、重试)做的比较好。

l 行内使用的JAVA技术栈,暂不需要多协议和多语言支持。

4 二次封装建议

封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处:

透明—通过引入二次封装SDK胶水层,隐藏具体实现细节

重用—提高基础代码的重用性同时增加的代码的可维护性和可靠性

安全—通过规范操作提高安全性

将规范封装到基础代码中以便在企业内部统一交互标准,具体的规范包括:

topic命名规范

producter命名规范

Consumer命名规范

基于MessageId、key或业务ID的幂等通用方案封装

通过赋义编码规范可以通过名称定位到所属项目、模块等业务场景,以便在出现未知问题时可以快速协调人员进行处理,当然对topic、生产者、消费者等原数据也是必要的,毕竟命名规范能保留的信息有限。通过命名规范还可以避免冲突,比如topic的冲突会或误会导致无法正常消费或者业务流转等问题,消费者GroupID冲突会导致丢失等问题。

通过封装和定制化增强功能如批量信息查询、批量信息重发、对账等。

5 典型场景

RocketMQ是提高整体服务弹性的重要基础中间件,在个类金融交易中承担着重要的角色。

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次封装建议 封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处: 5 典型场景 6 哪些场景不适合MQ 7 经验总结和建议(图4)

4.1 支付场景

下面以活期账户转出服务场景为例来讲解。

1 出于安全考虑我们每笔用户活期账户转出都要发送一条短信,这时通过RPC调用即可实现,如下图所示:

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次封装建议 封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处: 5 典型场景 6 哪些场景不适合MQ 7 经验总结和建议(图5)

2) 随着业务发展及出于安全和反欺诈考虑,建设了反欺诈服务,需要在每笔转出时发送支出场景的埋点数据,这个时候有两种方案,一种是继续使用RPC调用,如下图所示,这时转出操作响应时间可能是处理耗时A+短信调用时间B+反欺诈服务调用时间C(也有可能是通过异步RPC调用:响应时间转出操作时间+Max(B,C),除了耗时之外,的故障点也多了,如果反欺诈服务或者短信服务宕机了,那么很大可能活期账户转出服务会随之宕掉(如果使用了熔断和隔离,可以很大程度规避跨间的调用异常影响)

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次封装建议 封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处: 5 典型场景 6 哪些场景不适合MQ 7 经验总结和建议(图6)

3 另第二种解决方案是未雨绸缪,既然现在有第二个服务需要了解事件,那么以后是不是还会有第三个、第N个呢?如下图所示。这时活期账户转出服务的稳定性会进一步降低,复杂度急剧上升,在处理登录逻辑的同时需要考虑N个的关联需求。

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次封装建议 封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处: 5 典型场景 6 哪些场景不适合MQ 7 经验总结和建议(图7)

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次封装建议 封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处: 5 典型场景 6 哪些场景不适合MQ 7 经验总结和建议(图8)

4.1 三方延时调用

在与银行外部对接的时候,会有需要在发送服务请求N秒后,去获得响应结果的异步请求。在使用RocketMQ的延时前,都是通过将数据落地到数据库或Redis缓存中,通过定时轮询任务来操作。这样做有以下缺点:

l 非通用方案,每个都需要单独维护一个轮询任务。

l 数据量大了以后轮询会影响数据库性能。

l 轮询时间不宜设置过低,常以分钟为单位轮询,时效性差,如果时间过短对数据库压力也会增加。

l 针对轮询失败的重试机制需要各自实现。

使用RocketMQ后有以下优点:

l 通用延时方案,生产延时和消费隔离。

l 支持高并发,具备较好的横向扩展能力。

l 时效性大幅提升,可以精确到秒级。

不过,当前版本还不支设置时间精度,只能按照特定的messageDelayLevel来设置,这就要在搭建RocketMQ时提前最好延时级别的规划或者对RocketMQ延时源码进行扩展以支持指定时间精度。

6 哪些场景不适合MQ

既然MQ有这么多优点,那么所有的调用都使用MQ岂不是很好?无处不在的经济学告诉我们:凡有收益必有代价。

MQ的不足:

1 在支持灵活性的同时,增加了的整体复杂度。

Java架构师-为什么RocketMQ是金融核心系统消息中间件的第一选择 1 概述 2 为什么要引入MQ 3 MQ选型 4 二次封装建议 封装主要是对业务、技术和数据进行抽象和封装,封装具有如下好处: 5 典型场景 6 哪些场景不适合MQ 7 经验总结和建议(图9)

2因为异步调用的延时大于RPC同步调用是,所以会出现短暂的不一致性

3无法做到事务的强一致,需要分布式事务方案来处理

4服务的消费方要做幂等设计,来规避重复调用的问题

所以在软件的正常功能中,并不需要去刻意的寻找队列的使用场景,而是当出现性能瓶颈时,去查看业务逻辑是否存在可以异步处理的耗时操作,如果存在的话便可以引入队列来解决。否则盲目的使用队列可能会增加维护和的成本却无法得到可观的性能提升,那就得不偿失了。

7 经验总结和建议

遇到的那些坑

l Topic队列数设置不合理导致负载不均衡,影响RocketMQ的Broker的稳定。

l 堆积导致投递延时时间变长。

l 因为消费者的集群ID设置不规范,导致A消费者消费了B的。

l 因为Topic设置的不合理导致一个Broker节点的宕机导致消投递和消费异常。

l Topic、消费者GroupID相关命名不规范,导致运行一段时间后RocketMQ的Topic混乱无法清理回收资源。

当故障是不可避免的,就需要在应用程序设计的时候考虑通过一系列机制具备自我、自我恢复、自我配置等自治功能,随着云原生架构的流行,面对负载的加重和不断发生的各类故障,MQ不会是弹性设计的唯一选择,但也许是一个不错的选择,值得一试。

本文相关词条概念解析:

封装

封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。是为实现各式各样的数据传送,将被传送的数据结构映射进另一种数据结构的处理方式。

网友评论