前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >高并发消息队列补充篇:在所依赖存储不授信的场景下实现柔性事务降级

高并发消息队列补充篇:在所依赖存储不授信的场景下实现柔性事务降级

作者头像
Coder的技术之路
修改2021-05-17 17:22:50
6330
修改2021-05-17 17:22:50
举报
文章被收录于专栏:Coder的技术之路Coder的技术之路
文章出自本人公号,欢迎关注,后台提供高并发系列历史文章整理版下载
文章出自本人公号,欢迎关注,后台提供高并发系列历史文章整理版下载

Part1新公司做设计的些许不适应

在大厂和小厂做研发到底有啥不一样?其他好的坏的方方面面没法细说,咱主要还得说技术方面。

本来大部分的架构体系和思维都是在大厂构建的,到了小厂之后发现,起止是不适用,简直就是不适用(夸大了,?)。其实就本人理解主要是在底层的基础能力的支持程度上有所差异。

很多时候,在大厂待惯了的同学,或者一直在大厂待着的同学,思维惯性是不可避免的,感觉某些能力是理所应当的时候,往往实际情况是无法百分之百契合的。

所以,这种情况下,更要求我们有更强的细节把控能力,在系统设计和实施之前,要把所有涉及到的外部服务、底层支撑程度全都考虑进去,并一一应证,以做到万无一失。

本文阐述一个本人真实的采坑经历,希望帮大家加深对系统设计把控能力的重视。

Part2基础服务支持不到位的坑

2.1项目背景和整理设计思路

项目背景其实还是我们的数据一致性保证长事务引擎。

技术架构的设计思路在《分布式事务从入门到放弃(二)--详述DT引擎一致性原理及设计》一文中已有详述。这里就简单叙述下。(已经被我说了好几次,没办法,只有自己从0 到 1搭起来的,才理解的最深刻)

整体架构如下:

  • 通过状态机来组织和支持多种不同的业务流
  • 通过将外部服务节点化来抽象和规范化参与者的服务
  • 通过节点的异常捕获来感知参与方的执行结果
  • 通过实时或异步的恢复机制,实现柔性事务·

2.2不可缺少的强依赖--存储

想要业务请求保证最终一致,不可能是没有存储参与的一锤子买卖,因为还要考虑本身服务器的抖动,业务上的异步要求等等。所以,存储是一个不可缺少的依赖,如下图所示:

存储服务作用在引擎的整个生命周期:

  • 在请求进入初期,进行上下文落地(因为广告流量只有一次操作,不像普通支付可以允许用户重试,广告场景下,用户的多次操作需要进行分别计费,并且不太适合利用MQ的ack机制进行重试,因为那需要等流程全部执行完,会影响消息消费速率)
  • 在节点执行结束,进行节点执行状态落地(这样,在遇到需要补偿的情况,可以避免冗余调用,防止不需要重试的系统被其他抖动的系统冲击)
  • 在异步恢复时,获取上下文和节点执行状态集合,以完成事务的最终一致性处理。

2.3存储的调研和选择

业界的选择--数据库

对于支付类业务,其实,最好的是用数据库。业务层的订单表相当于业务请求上下文,会将请求的所需信息落地(没有上下文落地其实也没关系,返回用户失败即可)。

节点执行状态数据存在和订单表同库的另一个表中,即可支持一个在一个本地事务内保证分布式事务的最终一致性逻辑。

业务特性决定了数据库不合适

由于种种原因,我们这里不太适合用数据库,一个是广告上下文太大,且绝大多时候没有用,为了少数异常存到订单表的话太浪费;二是目前采用实时库+历史库的方式进行,没有分库,如果增加了中间状态表,目前的并发量,对数据库压力会很大,但目前搞分库又不是那么必要。

所以数据库不太适合。

公司自研存储的选择和使用

正好,公司自研了一套基于rocksdb的高性能存储,在读写性能和数据结构方面基本可以代替MySQL和Redis。在公司内部被广泛使用。

两个版本,一个是paxos强一致版本,读写性能稍弱,但保证数据强一致;另一个是普通版本,读写性能更高,但不保证强一致,即有可能主从切换会丢数据。

对于带金融属性的业务来说,在理论上的读写性能满足业务要求的情况下,当然是首选强一致的版本了。特别是业务上下文,丢失的结果就是该请求的整个异常恢复流程无法被正常唤起。

然而,理想照进现实,由于该版本之前应对的业务场景较为简单,并发也没有我们这么大,一些底层调优不到位导致服务抖动频繁。

如果是在大厂,就像之前用OB,只要OB有承若数据不丢,那基本不用考虑丢失的问题。如果丢了,我想可能大概率就会把锅抛给存储团队,限时优化之类。

但,我们小厂可都是相亲相爱的一家人,怎么能干这种事。所以选了另一个版本,使用更广泛,更成熟的非强一致版本。而数据丢失的问题由业务自己来想办法。

Part3消息队列的介入

3.1非强一致存储为啥会丢数据

如上图所示,该存储架构采用的是主从模式,数据由主写入,同步到从,当主异常时,进行主从切换,恢复服务。

但是,由于不是强一致协议,写主成功即为成功,当主宕机时,虽然主从切换很快,10秒完成,但还没有来得及同步到从的那部分数据,就会因为因为主从切换而丢失。

怎么办?

3.2消息队列登场

为了应对存储不授信的情况,我们引入了消息队列来实现存储的丢失补偿。

如上图所示,引入延迟消息进入处理流程。

  • 当节点执行发生异常时,发送当前业务上下文到消息队列。如果是正常执行的情况则无需发送。
  • 消息的延迟间隔,要大于主从切换的时间,并且需要小于定时任务的触发间隔。比如,主从切换需要10s,那延迟消息的延迟间隔就设置为30s , 接收消息都重新插入上下文到存储。在节点异常一分钟之后,被定时任务捞取,执行处理。

用两个时间差来覆盖掉主从切换带来的数据丢失的影响。

3.3更进一步--存储降级

那么,更极端的情况,如果整个存储服务持续不可用怎么办?

降级: 自己的命运要把握在自己手中。目的是保证绝大部分服务正常。

  • 监控系统。用于收集和汇报操作存储时的异常,并统计错误率和超时率
  • 一旦错误率和超时率达到阈值(比如持续30s,所有服务全部超时)执行关联脚本。
  • 脚本负责触发配置中心的配置切换,由正常模式切换为柔性模式。
  • 柔性模式下,所有涉及存储读写的操作将被忽略,以保障绝大部分请求可以正常执行。
  • 遇到执行异常的节点,将上下文发送至消息队列,消费时不再插入存储,而是改为直接消费。

Part4总结

本文想从实际的案例出发,给大家提供一种利用消息队列解决问题的思路。希望大家遇到其他问题的时候,可以有所借鉴。毕竟业务场景千千万,只有思路得人心。

高并发系列历史文章微信链接文档

  1. 垂直性能提升 1.1. 架构优化:集群部署,负载均衡 1.2. 万亿流量下负载均衡的实现 1.3. 架构优化:消息中间件的妙用 1.4. 存储优化:mysql的索引原理和优化 1.5. 索引优化补充篇:explain索引优化实战 1.6. 存储优化:详解分库分表
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Coder的技术之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Part1新公司做设计的些许不适应
  • Part2基础服务支持不到位的坑
    • 2.1项目背景和整理设计思路
      • 2.2不可缺少的强依赖--存储
        • 2.3存储的调研和选择
          • 业界的选择--数据库
          • 业务特性决定了数据库不合适
          • 公司自研存储的选择和使用
      • Part3消息队列的介入
        • 3.1非强一致存储为啥会丢数据
          • 3.2消息队列登场
            • 3.3更进一步--存储降级
            • Part4总结
            相关产品与服务
            对象存储
            对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档