交易系统的消息服务如何保证100%可靠

栏目: 数据库 · 发布时间: 7年前

内容简介:分布式应用中,消息系统被大量使用,主要原因有:发送方和接收方不需要相互知道对方,一个只管发,一个只管收,大大简化了处理逻辑。如果发送方发送速度快于接收方的接收速度,消息系统就可以暂时将无法处理的消息缓存起来,让接收方慢慢处理。

分布式应用中,消息系统被大量使用,主要原因有:

逻辑解耦

发送方和接收方不需要相互知道对方,一个只管发,一个只管收,大大简化了处理逻辑。

适配动态流量

如果发送方发送速度快于接收方的接收速度,消息系统就可以暂时将无法处理的消息缓存起来,让接收方慢慢处理。

没有消息系统时,发送方就不得不配合接收方降低处理速度,从而拖慢了整个系统的性能。

那么消息系统能保证消息100%可靠到达吗?

答案是否定的。

因为消息系统是网络调用,只要涉及到网络,就不可能100%可靠,因为通信双方不可能无限次给对方发ACK确认。

那么消息系统如何尽可能保证消息的可靠达到呢?

一般来说,消息系统可以实现3种消息传输模式:

  • At least once;
  • At most once;
  • Exactly once.

这3种模式分别是:

  • 消息保证至少发送成功一次,也就是可能会重复发送;
  • 消息只保证最多发送一次,那就是要么成功,要么失败;
  • 消息保证发送成功且仅发送成功一次,这种理想情况基本不存在,也没有任何基于网络的消息系统能实现这种模式。

所以大部分消息系统都按照At least once来设计。

但是并不是说消息系统就能保证所有消息能100%可靠达到,只要是网络,就存在丢消息的可能性。

如果涉及到交易系统这类绝对不能丢消息的应用,怎么才能保证100%不丢消息,并保证所有消息处理一次且仅处理一次?

首先我们要排除分布式事务消息,因为这种模式不但对数据库提出了XA两阶段提交的要求(需要昂贵的商用数据库),还对消息服务器提出了XA的要求(只有少数如WebLogic的JMS提供此功能),并且性能十分差劲。

而非事务型消息系统,如ActiveMQ、RabbitMQ、Kafka等,不保证100%可靠性。

涉及到交易系统的订单消息,如果一个都不能丢,通过非100%可靠的消息系统,如何保证100%的可靠性?

仅仅依靠消息服务是无法保证的,我们必须在设计上做出更多的容错和自动恢复的机制,来保证100%的可靠性。

以定序服务为例,如果订单已经持久化到数据库中,并且经过定序,下一步,如何保证定序后的订单通过消息发送给撮合服务100%可靠?

解决方法需要从发送方和接收方同时考虑。

考虑接收方处理消息的逻辑,首先要保证接收方能处理重复消息,因此需要对每个订单的消息进行编号,也就是给每个消息标记一个递增的ID(只需要递增,不一定要求连续),这样,接收方维护一个当前ID,凡是收到比当前ID小的消息,直接丢弃。

但是,如果一个消息序列例如 A-B-C-D 在发送过程中丢掉了某个消息,变成了 A-B-D ,接收方如何能检测出丢失?

除了给每个消息附上一个唯一递增ID外,只需要发送方同时给每个消息附加上一条消息的ID,就可以形成一个微型“区块链”,利用这个链表,接收方很容易识别出漏掉的消息。

如果接收方识别出消息遗漏,它应该怎么从该错误恢复呢?方法也很简单,只需向接收方暴露数据库接口,让接收方自己从数据库中根据ID读取漏掉的消息,就相当于接收方总是能有序且无遗漏地处理所有消息。

假设正常的消息流如下所示:

┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│id=1 │ │id=2 │ │id=3 │ │id=4 │
│pid=0│ │pid=1│ │pid=2│ │pid=3│
│msg-A│ │msg-B│ │msg-C│ │msg-D│
└─────┘ └─────┘ └─────┘ └─────┘

由于接收方可以根据递增ID去重,因此,重复发送消息可以被正常处理:

┌─────┐ ┌─────┐ ┌─────┐ ╔═════╗ ╔═════╗ ┌─────┐
│id=1 │ │id=2 │ │id=3 │ ║id=2 ║ ║id=3 ║ │id=4 │
│pid=0│ │pid=1│ │pid=2│ ║pid=1║ ║pid=2║ │pid=3│
│msg-A│ │msg-B│ │msg-C│ ║msg-B║ ║msg-C║ │msg-D│
└─────┘ └─────┘ └─────┘ ╚═════╝ ╚═════╝ └─────┘

如果消息出现丢失:

┌─────┐ ┌─────┐ ┌ ─ ─ ┐ ┌─────┐
│id=1 │ │id=2 │         │id=4 │
│pid=0│ │pid=1│ │     │ │pid=3│
│msg-A│ │msg-B│         │msg-D│
└─────┘ └─────┘ └ ─ ─ ┘ └─────┘

那么,接收方只需要根据当前ID去数据库查询,直到读取到最新的ID为止:

┌───────────┐      ┌───────────┐      ┌───────────┐
│  Sender   │─────>│    MQ     │─────>│ Receiver  │
└───────────┘      └───────────┘      └───────────┘
      │                                     │
      │                                     │
      │                                     │
      │                                     │
      │            ┌───────────┐            │
      └───────────>│ Database  │<───────────┘
                   └───────────┘

整个过程中,极少量消息丢失不会对系统的可用性造成影响,这样就极大地减少了系统的运维成本和线上排错成本。

对于那些不太需要100%严格有序的消息队列,例如清算消息,就不需要这么复杂的设计,超时重发+定时扫描未处理的消息就足够了。

最后,无论是发送方还是接收方,为了提高收发消息的效率,应该总是使用批处理的方式。测试显示一次收发一条消息和一次收发10条消息时间上并无明细差异,而发送方采用batch落库+batch发送可以显著地提高TPS,当然,这需要消息服务器支持batch模式。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数据分析技术白皮书

数据分析技术白皮书

伍海凤、刘鹏、杨佳静、马师慧Sara、李博、Shirley Song、Zinc、李晓艳 / 2016-8-11 / 0

关于数据分析技术白皮书(Analytics Book 中文版),主要内容围绕: 1. 分析(Analytics):网站分析 & APP分析 2. 谷歌分析工具的原理、部署与使用 3. 开源网站分析工具的原理、部署与使用 4. Log日志分析原理 5. 网站分析的维度与指标定义 6. 如何炼成为一个互联网数据分析师 请访问书的数据分析技术白皮书官网“免费”阅......一起来看看 《数据分析技术白皮书》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具