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

标签: 交易 系统 消息 | 发表时间:2018-12-23 03:00 | 作者:廖雪峰
出处:https://www.liaoxuefeng.com/

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

逻辑解耦

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

适配动态流量

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

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

那么消息系统能保证消息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模式。

相关 [交易 系统 消息] 推荐:

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

- - 廖雪峰的官方网站
分布式应用中,消息系统被大量使用,主要原因有:. 发送方和接收方不需要相互知道对方,一个只管发,一个只管收,大大简化了处理逻辑. 如果发送方发送速度快于接收方的接收速度,消息系统就可以暂时将无法处理的消息缓存起来,让接收方慢慢处理. 没有消息系统时,发送方就不得不配合接收方降低处理速度,从而拖慢了整个系统的性能.

常见开源消息系统

- - Web 开发 : 从后端到前端
消息系统的作用:异步处理、削减峰值、减少组件之间的耦合. 选择消息系统根据业务需要需要考虑以下几个方面:. 其他,如消息丢失和重复的处理. 类似 MEMCACHE 的协议. 1、2 是不错的可选开源组件:. Kafka/MetaQ: 广泛用于 Linkedin 内部 (类似有 Java 版本的国产 MetaQ).

分布式消息系统:Kafka

- - 标点符
Kafka是分布式发布-订阅消息系统. 它最初由LinkedIn公司开发,之后成为Apache项目的一部分. Kafka是一个分布式的,可划分的,冗余备份的持久性的日志服务. 在大数据系统中,常常会碰到一个问题,整个大数据是由各个子系统组成,数据需要在各个子系统中高性能,低延迟的不停流转. 传统的企业消息系统并不是非常适合大规模的数据处理.

kafka分布式消息系统

- - CSDN博客云计算推荐文章
Kafka[1]是linkedin用于日志处理的分布式消息队列,linkedin的日志数据容量大,但对可靠性要求不高,其日志数据主要包括用户行为(登录、浏览、点击、分享、喜欢)以及系统运行日志(CPU、内存、磁盘、网络、系统及进程状态). 当前很多的消息队列服务提供可靠交付保证,并默认是即时消费(不适合离线).

高性能消息系统——Kafka

- - 互联网 - ITeye博客
引用官方原文: “Kafka is a distributed, partitioned, replicated commit log service.”. 它提供了一个非常特殊的消息机制,不同于传统的mq. 官网:https://kafka.apache.org.     传统的MQ,消息被消化掉后会被mq删除,而kafka中消息被消化后不会被删除,而是到配置的expire时间后,才删除.

手机系统消息通知设计的整理和分析

- Hu DongHai - 信息和交互 - UCD大社区
当应用程序不处于前台运行中时,消息通知能将某些信息及时告知用户. 比如收到新消息、收到新邮件、程序下载已完成或者待办事项即将开始等. 目前各移动平台上对消息通知的设计均有所差别,各有利弊. 这里整理了iOS、Android、Palm Web OS、Windows Phone和未揭开面纱的Meego这五个系统对消息通知的处理方式,并分析了它们各自的优缺点.

Jafka - 一个高性能的消息系统

- - BlogJava-首页技术区
Jafka 是一个高性能的分布式消息系统. Jafka已经开源,使用github托管,主页地址: https://github.com/adyliu/jafka. Jafka 1.0版本已经发布,同步到Maven中央仓库. Jafka是由Apache孵化的Kafka(由LinkedIn捐助给Apache)克隆而来.

Tumblr的消息通知系统是如何构建的

- - 博客园_旁观者-郑昀
Tumblr是世界上最流行的轻博客服务之一,2007年成立. 一,MySQL+Memcached. 初期,其通知系统是由 MySQL+Memcached 的传统架构组成. MySQL负担重,表象就是 MySQL 并发事务数常常达到 InnoDB global transaction 最大值,即只能有1023个并发事务(注:特指  mysql5.0/5.1存在的问题,5.5.4以上版本修复).

即时消息应用颠覆移动生态系统格局

- - 互联网的那点事
消息应用是手机的一项重要功能,以短信为主导的消息服务已经发展成一项规模庞大的产业,为全球移动运营商带来了丰厚的收益,预计未来三年消息产业的年营收将达1400亿美元. 不过,一批新兴企业开始推出的OTT消息服务——不依赖无线蜂窝网络,直接在互联网上发送即时消息的服务——正在改变移动生态系统的格局. 从提供Messenger服务的Facebook到位于美国加州圣克拉拉的初创公司WhatsApp——WhatsApp月活跃用户达2亿,以及Twitter和韩国的LINE,他们已经成为抢夺移动用户的最大OTT消息服务提供商,不仅对移动运营商构成威胁,而且还对社交媒体构成威胁.

[转][转]Redis消息通知系统的实现

- - heiyeluren的Blog
链接:http://huoding.com/2012/02/29/146. 最近忙着用Redis实现一个消息通知系统,今天大概总结了一下技术细节,其中演示代码如果没有特殊说明,使用的都是 PhpRedis扩展来实现的. 比如要推送一条全局消息,如果真的给所有用户都推送一遍的话,那么会占用很大的内存,实际上不管粘性有多高的产品,活跃用户同全部用户比起来,都会小很多,所以如果只处理登录用户的话,那么至少在内存消耗上是相当划算的,至于未登录用户,可以推迟到用户下次登录时再处理,如果用户一直不登录,就一了百了了.