2017年1月28日,正月初一,微信公布除夕夜用户收发微信红包数量——142亿,红包收发峰值数量已达每秒76万个。 百亿红包如何保证并发性能和资金安全? 这给微信带来了超级挑战。 面对挑战,微信红包分析了业界的“闪购”系统解决方案,采用SET、请求排队序列化、二维分库表等设计,形成了独特的高并发、资金安全的系统解决方案。 计划。 实践证明,该方案运行稳定,实现了系统除夕零故障运行。 概括:
1、业务特点:海量并发需求; 严格的安全级别
2、技术难点:并发请求锁; 大型交易级操作; 严格的交易要求
3、解决高并发问题常用的方案:
1、使用内存操作代替实时DB事务操作(优点:内存操作代替磁盘操作,提高并发性能。)
2、使用乐观锁代替悲观锁。 应用于微信红包系统时,会出现以下三个问题:翻滚、返回失败; 大失败与小成功并存。 DB面临着巨大的压力。
4、微信红包系统高并发解决方案:
1.系统是纵向设置、分而治之。
2、逻辑层对请求进行排队,解决DB并发问题。
3.双维数据库表设计,保证系统性能稳定
1、微信红包两大业务特点
与“闪购”活动类似,群里发红包=“闪购”产品上架; 抢红包的动作=“闪购”库存查询; 打开红包=“闪购”
首先,微信红包业务比普通商品“闪购”有更海量的并发需求。
群内有10万用户同时发红包,相当于同时发布了10万个“闪购”活动。 微信群内10万用户同时抢红包,会产生海量并发请求。
其次,微信红包业务需要更严格的安全级别。
微信红包是微信支付旗下提供转账服务的商户。
用户发送红包=购买一笔“钱”(在商家微信红包上),收货地址为微信群。 当用户支付成功后,红包就会“投递”到微信群中。 群内用户打开红包后,微信红包提供将“钱”转入红包用户微信零钱的服务。
基金交易业务比普通商品“闪购”活动具有更高的安全级别要求。 对于普通产品,“闪购”产品由商家提供,库存由商家预设。 在“闪购”期间,可以允许“超卖”和“欠卖”情况。 但对于微信红包来说,100元不能拆分成101元; 当收到99元时,剩余的1元必须在24小时到期后准确返还给发送红包的用户,不能多也不能少。
2、微信红包系统的技术难点
在介绍微信红包系统的技术难点之前,我们先介绍一个简单典型的产品“闪购”系统的架构设计,如下图所示。
系统由接入层、逻辑服务层、存储层和缓存组成。 处理访问请求,承载主要业务逻辑,用于缓存库存数量,DB用于数据持久化。
“闪购”活动对应于数据库中的库存记录。 当用户对商品进行“闪购”时,系统的主要逻辑在于对DB中库存的操作。 一般来说,DB操作流程有以下三个步骤:
A。 锁定库存
b. 插入“闪购”记录
C。 更新库存
A。 锁定库存是为了避免并发请求时出现“超卖”情况。 同时要求这三步操作需要在一个事务中完成(难度:并发请求抢锁)。
该锁被第一个请求占用,直到第一个事务完成并提交,所有后续请求都需要排队等待。 同时参与“闪购”的用户越多,同时向DB发送的请求就越多,请求排队就越严重。
在红包系统的设计中,除了并发请求抢锁之外,还存在以下两个突出的难点:
首先,交易层面的操作规模大。 上面介绍微信红包业务的特点时我们提到,正常情况下会有数以万计的微信群同时发出红包。 这一业务特征映射到了微信红包系统的设计上,即有数以万计的“并发请求抢锁”同时进行。 这使得DB面临的压力比普通单品“库存”被锁定大很多倍。
其次,交易要求严格。 微信红包系统本质上是一个资金交易系统,比普通商品的“闪购”系统有更高的交易级别要求。
3、解决高并发问题的常用方案
普通商品的“闪购”活动系统针对高并发问题有以下方案:
选项一是使用内存操作来代替实时数据库事务操作。
如图2所示,“实时扣库存”行为上移到了内存操作中。 如果内存操作成功,则直接返回,然后异步drop到DB进行持久化。
优点:提高并发性能。
缺点:当内存操作成功但DB持久化失败,或者存在内存故障时,DB持久化会丢失数据,不适合微信红包等资金交易系统。
选项二,使用乐观锁而不是悲观锁。
在产品“闪购”系统中,乐观锁的具体应用方法是在DB的“库存”记录中维护一个版本号。 在更新“库存”之前,首先去DB获取当前的版本号。 当更新库存的事务提交时,检查版本号是否被其他事务修改。 如果版本没有修改,则提交事务,版本号加1; 如果版本号被其他事务修改,则回滚该事务并向上层报告错误。
该方案解决了“并发请求抢锁”的问题,可以提高DB的并发处理能力。
应用于微信红包系统时,会存在以下三个问题:
1、同版本号的并发开红包请求中,只有1个能够成功开红包。 其他请求将回滚事务并返回失败,向用户报告错误。 用户体验是完全不可接受的。
2、会导致部分同时开红包的用户直接返回失败。 相反,那些“手慢”的用户可能会因为并发量减少而成功开红包,这会对用户体验产生负面影响。
3、会带来大量的无效更新请求和事务回滚,给DB造成不必要的额外压力。
四、微信红包系统高并发解决方案 1、系统纵向SET,分而治之。
当微信红包用户发送红包时,微信红包系统会生成一个ID,作为该红包的唯一标识。 后续对这个红包的所有操作,比如发红包、抢红包、拆红包、查询红包详情,都是基于这个ID进行关联的。
红包系统根据红包ID,按照一定的规则(如根据ID的最后一个数字取模等),垂直上下划分红包。 分段后,一条垂直链上的逻辑服务器和DB统称为SET。
每个SET都是相互独立、相互解耦的。 并且所有具有相同红包ID的请求,包括发红包、抢红包、打开红包、查看详情等,都在同一个SET中垂直处理,内聚度很高。 这样,系统就将庞大的红包请求洪流分散成多个互不影响、分而治之的小流,如下图所示。
该方案同时解决了海量交易级操作的问题,将海量降到了少量。
2、逻辑层对请求进行排队,解决DB并发问题。
红包系统是资金交易系统,无法避免DB操作的事务性,因此会存在“并发抢锁”问题。 但如果到达DB的事务操作(即开红包的行为)不是并发的而是串行的,就不会出现“并发抢锁”的问题。
按照这个思路,为了让开红包的事务操作串行进入DB,我们只需要在层将请求以FIFO(先进先出)的方式进行排队就可以达到这样的效果。 因此,问题集中在 FIFO 队列设计上。
微信红包系统设计了分布式、轻量级、灵活的先进先出队列解决方案。 其具体实现如下:
首先,将所有具有相同红包ID的请求发送到同一站点。
上面已经介绍了SET方案。 所有具有相同红包ID的请求都会根据红包ID放入同一个SET中。 但在同一个SET中,会存在多台服务器同时连接同一个DB(基于容灾和性能考虑,多台服务器需要互相备战,平衡压力)。
为了让同一个红包ID的所有请求都走到同一个服务器,微信红包系统除了SET设计外,还根据红包ID的哈希值增加了一层导流,如图如下图。
其次,设计单机请求排队方案。
所有对同一平台的请求被接收进程接收后,都会根据红包ID进行排队。 然后串行进入流程(执行业务逻辑)进行处理,从而达到排队效果,如下图所示。
最后,添加受控并发。
为了防止请求队列超载导致队列降级,从而使所有请求都涌入DB,系统增加了一台与服务器部署在同一台机器上的服务器来控制并发请求数打开同一个红包。
具体来说,通过CAS原子累加操作来控制同时进入DB执行开红包交易的请求数量。 如果数量超过预设值,则直接拒绝服务。 用于DB负载增加时的降级体验。
通过以上三项措施,系统有效控制了DB的“并发抢锁”情况。
3.双维数据库表设计,保证系统性能稳定
红包系统的数据库表规则最初根据红包ID的哈希值划分为多个数据库和表。 随着红包数据量逐渐增大,单表数据量也逐渐增大。 DB的性能与单表数据量有一定的相关性。 当单表数据量达到一定程度时,DB性能会大幅下降,影响系统性能稳定性。 采用冷热分离的方式,将历史冷数据和当前热数据分开存储就可以解决这个问题。
系统在基于红包ID维度的分库表的基础上,增加了循环人才表的维度,形成了二维分库表的特征。
具体来说,分库表规则是这样设计的。 其中,xx/y为红包ID的哈希值后三位,dd的取值范围为01到31,代表一个月的最大天数,31天。
这种双维数据库表的方式,解决了单个数据库表数据量膨胀带来的性能下降问题,保证了系统性能的稳定性。 同时,冷热分离的问题让数据迁移变得简单优雅。
综上所述,微信红包系统解决高并发问题的设计主要采用了SET分治、请求队列、双维分库等方案,将单组DB的并发性能提升8左右次,取得了很好的成绩。