在大厂和小厂做研发到底有啥不一样?其他好的坏的方方面面没法细说,咱主要还得说技术方面。
本来大部分的架构体系和思维都是在大厂构建的,到了小厂之后发现,起止是不适用,简直就是不适用(夸大了,?)。其实就本人理解主要是在底层的基础能力的支持程度上有所差异。
很多时候,在大厂待惯了的同学,或者一直在大厂待着的同学,思维惯性是不可避免的,感觉某些能力是理所应当的时候,往往实际情况是无法百分之百契合的。
所以,这种情况下,更要求我们有更强的细节把控能力,在系统设计和实施之前,要把所有涉及到的外部服务、底层支撑程度全都考虑进去,并一一应证,以做到万无一失。
本文阐述一个本人真实的采坑经历,希望帮大家加深对系统设计把控能力的重视。
项目背景其实还是我们的数据一致性保证长事务引擎。
技术架构的设计思路在《分布式事务从入门到放弃(二)--详述DT引擎一致性原理及设计》一文中已有详述。这里就简单叙述下。(已经被我说了好几次,没办法,只有自己从0 到 1搭起来的,才理解的最深刻)
整体架构如下:
想要业务请求保证最终一致,不可能是没有存储参与的一锤子买卖,因为还要考虑本身服务器的抖动,业务上的异步要求等等。所以,存储是一个不可缺少的依赖,如下图所示:
存储服务作用在引擎的整个生命周期:
对于支付类业务,其实,最好的是用数据库。业务层的订单表相当于业务请求上下文,会将请求的所需信息落地(没有上下文落地其实也没关系,返回用户失败即可)。
节点执行状态数据存在和订单表同库的另一个表中,即可支持一个在一个本地事务内保证分布式事务的最终一致性逻辑。
由于种种原因,我们这里不太适合用数据库,一个是广告上下文太大,且绝大多时候没有用,为了少数异常存到订单表的话太浪费;二是目前采用实时库+历史库的方式进行,没有分库,如果增加了中间状态表,目前的并发量,对数据库压力会很大,但目前搞分库又不是那么必要。
所以数据库不太适合。
正好,公司自研了一套基于rocksdb的高性能存储,在读写性能和数据结构方面基本可以代替MySQL和Redis。在公司内部被广泛使用。
两个版本,一个是paxos强一致版本,读写性能稍弱,但保证数据强一致;另一个是普通版本,读写性能更高,但不保证强一致,即有可能主从切换会丢数据。
对于带金融属性的业务来说,在理论上的读写性能满足业务要求的情况下,当然是首选强一致的版本了。特别是业务上下文,丢失的结果就是该请求的整个异常恢复流程无法被正常唤起。
然而,理想照进现实,由于该版本之前应对的业务场景较为简单,并发也没有我们这么大,一些底层调优不到位导致服务抖动频繁。
如果是在大厂,就像之前用OB,只要OB有承若数据不丢,那基本不用考虑丢失的问题。如果丢了,我想可能大概率就会把锅抛给存储团队,限时优化之类。
但,我们小厂可都是相亲相爱的一家人,怎么能干这种事。所以选了另一个版本,使用更广泛,更成熟的非强一致版本。而数据丢失的问题由业务自己来想办法。
如上图所示,该存储架构采用的是主从模式,数据由主写入,同步到从,当主异常时,进行主从切换,恢复服务。
但是,由于不是强一致协议,写主成功即为成功,当主宕机时,虽然主从切换很快,10秒完成,但还没有来得及同步到从的那部分数据,就会因为因为主从切换而丢失。
怎么办?
为了应对存储不授信的情况,我们引入了消息队列来实现存储的丢失补偿。
如上图所示,引入延迟消息进入处理流程。
用两个时间差来覆盖掉主从切换带来的数据丢失的影响。
那么,更极端的情况,如果整个存储服务持续不可用怎么办?
降级: 自己的命运要把握在自己手中。目的是保证绝大部分服务正常。
本文想从实际的案例出发,给大家提供一种利用消息队列解决问题的思路。希望大家遇到其他问题的时候,可以有所借鉴。毕竟业务场景千千万,只有思路得人心。
高并发系列历史文章微信链接文档