CPCN GEEKRabbitMQ在中金支付的高可用实践

Posted 中金支付

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CPCN GEEKRabbitMQ在中金支付的高可用实践相关的知识,希望对你有一定的参考价值。

通过对RabbitMQ产品的深入探索和研究,中金支付把RabbitMQ的关键特性很好地应用到支付系统中。对RabbitMQ正确地应用,使得支付系统轻松地应对数据一致性、系统解耦、流量削峰、消息广播等问题,极大地提高了服务的可用性和可扩展性,为基于微服务架构的支付系统建设提供有力保障。



 研究背景 

在分布式的系统体系结构当中,如何保证一致性是重点要解决的问题,且对于金融支付系统而言尤为重要。


中金支付的支付系统采用多层次、分布式架构,为了解决层次架构中的数据一致性问题,我们采取柔性事务处理策略,同时引入RabbitMQ消息中间件进行实现。


下文讲述了中金支付在RabbitMQ的“消息高确保”“服务高可用”上的设计和实现机制,而成功解决了一致性问题;同时基于该设计机制,我们也将RabbitMQ成功地应用在任务调度、流量削峰、消息预警等其它场景当中。


 实现目标 

RabbitMQ能够提供高性能消息存储和转发服务,但是要保证生产者正确投递消息,并且消费者能够消费到消息,仍然需要在RabbitMQ的基础上设计合理方案。方案从以下两点进行保证:


1、消息高确保。消息从生产者发出,经过RabbitMQ存储转发,到被消费这个过程,保证不丢失。


2、RabbitMQ高可用。为避免单点故障的发生,采用集群部署的方式,集群中个别节点出现异常时,仍然保证服务可用。


消息高确保的实现

RabbitMQ的消息模型如图1所示,包含生产者(Publisher)、消费者(Consumer)和RabbitMQ消息中间件,生产者发送消息给RabbitMQ的交换机(Exchange),RabbitMQ根据路由策略将消息路由到队列(Queue)上,消费者订阅RabbitMQ队列,消费队列上的消息。

图1  RabbitMQ消息模型图


因此,从以下三个环节进行分析:

1、生产者投递消息,无论投递成功或者失败,都能被生产者知晓。

2、消费者消费消息,无论消费成功或者失败,都能被RabbitMQ服务器知晓。

3、生产者投递消息后,在RabbitMQ服务器中,消息不丢失。


在生产者投递消息环节,将Channel设置为Confirm模式,确保生产者能够知晓消息是否发送至RabbitMQ交换机。


Confirm模式下,生产者和RabbitMQ的交互如图2所示,生产者发送消息至交换机,当交换机收到消息时,RabbitMQ发送Basic.Ack=true返回给生产者,当交换机没收到消息时,RabbitMQ发送Basic.Ack=false返回给生产者,生产者收到Basic.Ack之后,能够明确消息是否发送至交换机。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图2  Confirm模式消息交互图


图3是Confirm方式设置的代码示例,通过Channel类的confirmSelect()方法设置,图4是Wireshark抓包生产者和RabbitMQ交互消息报文。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图3  Confirm模式代码示例图


【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图4  Confirm模式抓包图


生产者通过Confirm方式能够明确消息是否发送至RabbitMQ交换机,但是并不能知晓消息是否已经达到队列,而通过开启Return回调机制能够实现这个效果。


在开启Return回调方式下,生产者和RabbitMQ交互如图5所示,生产者发送消息至交换机,交换机根据路由策略,无法找到匹配的队列,在设置mandatory=true情况下,RabbitMQ将消息退回给生产者,因此,生产者可以知晓消息是否已经到达队列。


图6是设置Return方式消息未发送至队列场景的日志打印,图7是Wireshark抓包生产者和RabbitMQ交互消息报文。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图5  Return回调交互图


【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图6 消息未发送至队列的日志打印图


【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图7  Return回调抓包图


生产者通过Confirm和Return方式知晓消息是否成功发送至RabbitMQ,但RabbitMQ服务器如何才能知晓消息已经被消费?根据场景的需要,采用手动确认或自动确认的方式,来通知RabbitMQ服务器消息已经被消费或拒绝。


在消费确认的场景下,消费者和RabbitMQ交互如图8所示,RabbitMQ给消费者发送消息,消费者接收消息后发送Basic.Ack给RabbitMQ进行消费确认。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图8  消息消费确认交互图


在消费拒绝场景下,消费者和RabbitMQ交互如图9所示,消费者通过Basic.Nack或Basic.Reject进行消息拒绝。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图9 消息拒绝交互图


图10是消费者确认方式的代码示例,图11是Wireshark抓包消费者和RabbitMQ消息报文交互。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图10 消费确认代码示例图


【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图11 消息消费确认抓包图


从客户端的角度,已经确保生产者正确发送和消费者可靠消费,从RabbitMQ服务端的角度,还需要一些机制的配合。我们启用队列、交换机、消息的持久化,在客户端声明交换机和队列时,将durable设置成true,声明队列和交换机持久化。在发送消息时,RabbitMQ根据客户端声明,将交换机、队列、消持久化到磁盘,声明持久化之后,在Confirm模式下,RabbitMQ接收消息后,先将消息落盘,然后将Basic.Ack=true返回给生产者,确保消息不丢失。


图12是队列交换机的代码配置示例,图13是RabbitMQManagement显示队列属性为D,表示持久化。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图12 持久化XML配置图


【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图13  RabbitMQ Management持久化配置


RabbitMQ高可用的实现

实现了消息高确保,在服务端和客户端正常运行的情况下,至少保证消息的可靠传递。当服务端出现故障,还需要RabbitMQ提供高可用的能力来保障服务的连续性,在服务宕机或者重启情况下,需要保证以下四点来实现高可用:

1、数据可恢复;

2、支持负载均衡,流量分发到正常节点上;

3、支持节点间数据同步,故障时失效转移;

4、支持水平伸缩。


为满足持久化,负载均衡,水平伸缩等需求,采用了Cluster集群部署方案,如图14所示,采用了Disk+RAM方案设置集群节点类型。Disk+RAM节点方案既支持消息持久化,又能通过RAM节点提升集群性能。为避免网络流量集中在单个节点上,采用了HAProxy实现负载均衡,将客户端的流量分发到集群各个节点。同时为提供高可靠的负载均衡,使用了KeepAlived工具,将两台HAProxy服务器构造热备组,实现故障转移,保证了HAProxy的高可用。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图14集群部署物理架构图


RabbitMQ Management显示集群部署如图15所示。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图15 RabbitMQ Management显示集群部署图


集群部署+负载均衡并不能够实现集群节点故障失效转移。还是会存在节点宕机,队列不可用的情况。


如图16所示,队列只在单个节点上创建,其他节点上不存在,一旦宕机,队列服务将不可用。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图16普通模式队列分布图


为避免单点问题,采用镜像模式,构建消息中间件集群。引入镜像队列机制,可将队列镜像到集群中其他节点上,集群中的一个节点失效了,队列能够自动切换到镜像队列中的另外一个节点上,以保证服务的可用性。


如图17所示,通过镜像队列模式设置集群,每个节点上都存在队列服务,一个节点宕机故障失效转移,从而避免了单点问题,提升了RabbitMQ消息中间件的可用性。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图 17 镜像模式队列分布图


 案例介绍 

使用RabbitMQ解决分布式系统最终一致性问题

解决分布式系统一致性问题,通常采用非事务消息进行系统间状态同步,如图18所示,上游系统状态修改成功后,发送消息至MQ,下游系统A、B、C消费消息,更新状态。达到系统间状态最终一致。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图18 分布式系统一致性解决方案


RabbitMQ实现分布式系统应用间解耦

问题场景如图19所示,上游系统调用下游系统,一旦下游系统故障或架构变更,会导致上游系统调用失败,导致服务不可用。

【CPCN GEEK】RabbitMQ在中金支付的高可用实践

图19系统耦合图


解决方案如图20所示,使用消息中间件进行服务间解耦,上游系统将请求发送至RabbitMQ,下游系统消费消息中间件的消息。上游系统不再同步调用下游系统,避免因下游系统故障导致服务不可用,即可实现服务间解耦。

图20 解耦方案图


 总结和展望 

采用集群部署方案,使用Disk+RAM方式配置集群节点,并采用镜像模式配置集群,实现了消息中间件的高可用。生产端通过采用Confirm信道和Return回调方案,确保生产者正确发送消息。在消费端,通过消费者消息确认机制,确保消息可靠消费。


未来支付系统可采用Federation方式部署,跨越集群界限,打通多地机房间的消息传递。也可以在高并发场景中进行高并发缓冲。在需要限流场景下,可以使用队列长度设置,实现限流。亦可利用死信队列特性,实现延时队列。




以上是关于CPCN GEEKRabbitMQ在中金支付的高可用实践的主要内容,如果未能解决你的问题,请参考以下文章

springcloud eureka 高可复用。

中国移动支付竞争已经纵深化:不仅仅体现在支付!

支付宝架构师眼中的高并发架构

支付宝架构师眼中的高并发

支付宝架构师眼中的高并发架构,真是绝了!

直播预告丨京东到家支付平台的高可用架构设计实践