百亿级微信红包的高并发资金交易系统设计方案

前言

2017年1月28日,正月初一,微信公布了用户在除夕当天收发微信红包的数量——142亿个,而其收发峰值也已达到76万每秒。百亿级别的红包,如何保障并发性能与资金安全?这给微信带来了超级挑战。面对挑战,微信红包在分析了业界“秒杀”系统解决方案的基础上,采用了SET化、请求排队串行化、双维度分库表等设计,造成了独特的高并发、资金安全系统解决方案。实践证实,该方案表现稳定,且实现了除夕夜系统零故障运行。redis

本文将为读者介绍百亿级别红包背后的系统高并发设计方案,包括微信红包的两大业务特色、微信红包系统的技术难点、解决高并发问题一般使用的方案,以及微信红包系统的高并发解决方案。数据库

1、微信红包的两大业务特色

微信红包(尤为是发在微信群里的红包,即群红包)业务形态上很相似网上的普通商品“秒杀”活动。用户在微信群里发一个红包,等同因而普通商品“秒杀”活动的商品上架;微信群里的全部用户抢红包的动做,等同于“秒杀”活动中的查询库存;用户抢到红包后拆红包的动做,则对应“秒杀”活动中用户的“秒杀”动做。安全

不过除了上面的相同点以外,微信红包在业务形态上与普通商品“秒杀”活动相比,还具有自身的特色:服务器

  1. 首先,微信红包业务比普通商品“秒杀”有更海量的并发要求。微信红包用户在微信群里发一个红包,等同于在网上发布一次商品“秒杀”活动。假设同一时间有10万个群里的用户同时在发红包,那就至关于同一时间有10万个“秒杀”活动发布出去。10万个微信群里的用户同时抢红包,将产生海量的并发请求。
  2. 其次,微信红包业务要求更严格的安全级别 。微信红包业务本质上是资金交易。微信红包是微信支付的一个商户,提供资金流转服务。用户发红包时,至关于在微信红包这个商户上使用微信支付购买一笔“钱”,而且收货地址是微信群。当用户支付成功后,红包“发货”到微信群里,群里的用户拆开红包后,微信红包提供了将“钱”转入折红包用户微信零钱的服务。资金交易业务比普通商品“秒杀”活动有更高的安全级别要求。普通的商品“秒杀”商品由商户提供,库存是商户预设的,“秒杀”时能够容许存在“超卖”(即实际被抢的商品数量比计划的库存多)、“少卖”(即实际被抢的商户数量比计划的库存少)的状况。可是对于微信红包,用户发100元的红包绝对不能够被拆出101元;用户发100元只被领取99元时,剩下的1元在24小时过时后要精确地退还给发红包用户,不能多也不能少。 以上是微信红包业务模型上的两大特色。

2、 微信红包系统的技术难点

方案一,普通秒杀架构

在介绍微信红包系统的技术难点以前,先介绍下简单的、典型的商品“秒杀”系统的架构设计,以下图所示。 普通秒杀架构微信

  • 优势:这个方案的优势是用内存操做替代磁盘操做,提升了并发性能。
  • 缺点:在内存操做成功但DB持久化失败,或者内存Cache故障的状况下,DB持化会丢数据,不适合微信红包这种资金交易系统。

方案二,使用乐观锁替代悲观锁。

所谓悲观锁,是关系数据库管理系统里的一种并发控制的方法。它能够阻止一个事务以影响其用户的方式来修改数据。若是一个事务执行的操做对某行数据应用了锁,那只有当这个事务把锁释放,其余事务才可以执行与该锁冲突的操做。对应于上文分析中的“并发请求抢锁”行为。架构

所谓乐观锁,它假设多用户并发的事务在处理时不会彼此互相影响,各事务可以在不产生锁的状况下处理各自影响的那部分数据。在提交数据更新以前,每一个事务会先检查在该事务读取数据后,有没有其余事务又修改了该数据。若是其余事务有更新的话,正在提交的事务会进行回滚。并发

商品“秒杀”系统中,乐观锁的具体应用方法,是在DB的“库存”记录中维护一个版本号。在更新“库存”的操做进行前,先去DB获取当前版本号。在更新库存的事务提交时,检查该版本号是否已被其余事务修改。若是版本没被修改,则提交事务,且版本号加1;若是版本号已经被其余事务修改,则回滚事务,并给上层报错。分布式

这个方案解决了“并发请求抢锁”的问题,能够提升DB的并发处理能力。memcached

可是若是应用于微信红包系统,则会存在下面三个问题高并发

  • 若是拆红包采用乐观锁,那么在并发抢到相同版本号的拆红包请求中,只有一个能拆红包成功,其余的请求将事务回滚并返回失败,给用户报错,用户体验彻底不可接受。
  • 若是采用乐观锁,将会致使第一时间同时拆红包的用户有一部分直接返回失败,反而那些“手慢”的用户,有可能由于并发减少后拆红包成功,这会带来用户体验上的负面影响。
  • 若是采用乐观锁的方式,会带来大数量的无效更新请求、事务回滚,给DB形成没必要要的额外压力。

基于以上缘由,微信红包系统不能采用乐观锁的方式解决并发抢锁问题。

4、微信红包系统的高并发解决方案

综合上面的分析,微信红包系统针对相应的技术难点,采用了下面几个方案,解决高并发问题。

1.系统垂直SET化,分而治之。

微信红包用户发一个红包时,微信红包系统生成一个ID做为这个红包的惟一标识。接下来这个红包的全部发红包、抢红包、拆红包、查询红包详情等操做,都根据这个ID关联。

红包系统根据这个红包ID,按必定的规则(如按ID尾号取模等),垂直上下切分。切分后,一个垂直链条上的逻辑Server服务器、DB统称为一个SET。

各个SET之间相互独立,互相解耦。而且同一个红包ID的全部请求,包括发红包、抢红包、拆红包、查详情详情等,垂直stick到同一个SET内处理,高度内聚。经过这样的方式,系统将全部红包请求这个巨大的洪流分散为多股小流,互不影响,分而治之,以下图所示。 输入图片说明 这个方案解决了同时存在海量事务级操做的问题,将海量化为小量。

2.逻辑Server层将请求排队,解决DB并发问题。

红包系统是资金交易系统,DB操做的事务性没法避免,因此会存在“并发抢锁”问题。可是若是到达DB的事务操做(也即拆红包行为)不是并发的,而是串行的,就不会存在“并发抢锁”的问题了。

按这个思路,为了使拆红包的事务操做串行地进入DB,只须要将请求在Server层以FIFO(先进先出)的方式排队,就能够达到这个效果。从而问题就集中到Server的FIFO队列设计上。

微信红包系统设计了分布式的、轻巧的、灵活的FIFO队列方案。其具体实现以下:

首先,将同一个红包ID的全部请求stick到同一台Server。

上面SET化方案已经介绍,同个红包ID的全部请求,按红包ID stick到同个SET中。不过在同个SET中,会存在多台Server服务器同时链接同一台DB(基于容灾、性能考虑,须要多台Server互备、均衡压力)。

为了使同一个红包ID的全部请求,stick到同一台Server服务器上,在SET化的设计以外,微信红包系统添加了一层基于红包ID hash值的分流,以下图所示。 输入图片说明

其次,设计单机请求排队方案。

将stick到同一台Server上的全部请求在被接收进程接收后,按红包ID进行排队。而后串行地进入worker进程(执行业务逻辑)进行处理,从而达到排队的效果,以下图所示。 输入图片说明

最后,增长memcached控制并发。

为了防止Server中的请求队列过载致使队列被降级,从而全部请求拥进DB,系统增长了与Server服务器同机部署的memcached,用于控制拆同一个红包的请求并发数。

具体来讲,利用memcached的CAS原子累增操做(利用redis的原子操做也能够达到目的),控制同时进入DB执行拆红包事务的请求数,超过预先设定数值则直接拒绝服务。用于DB负载升高时的降级体验。

经过以上三个措施,系统有效地控制了DB的“并发抢锁”状况。

3.双维度库表设计,保障系统性能稳定

红包系统的分库表规则,初期是根据红包ID的hash值分为多库多表。随着红包数据量逐渐增大,单表数据量也逐渐增长。而DB的性能与单表数据量有必定相关性。当单表数据量达到必定程度时,DB性能会有大幅度降低,影响系统性能稳定性。采用冷热分离,将历史冷数据与当前热数据分开存储,能够解决这个问题。

处理微信红包数据的冷热分离时,系统在以红包ID维度分库表的基础上,增长了以循环天分表的维度,造成了双维度分库表的特点。

具体来讲,就是分库表规则像db_xx.t_y_dd设计,其中,xx/y是红包ID的hash值后三位,dd的取值范围在01~31,表明一个月天数最多31天。

经过这种双维度分库表方式,解决了DB单表数据量膨胀致使性能降低的问题,保障了系统性能的稳定性。同时,在热冷分离的问题上,又使得数据搬迁变得简单而优雅。

综上所述,微信红包系统在解决高并发问题上的设计,主要采用了SET化分治请求排队双维度分库表等方案,使得单组DB的并发性能提高了8倍左右,取得了很好的效果。

5、总结

微信红包系统是一个高并发的资金交易系统,最大的技术挑战是保障并发性能与资金安全。这种全新的技术挑战,传统的“秒杀”系统设计方案已不能彻底解决。在分析了业界“秒杀”系统解决方案的基础上,微信红包采用了SET化、请求排队串行化、双维度分库表等设计,造成了独特的高并发、资金安全系统解决方案,并在平时节假日、2015和2016春节实践中充分证实了可行性,取得了显著的效果。在刚刚过去的2017鸡年除夕夜,微信红包收发峰值达到76万每秒,收发微信红包142亿个,微信红包系统的表现稳定,实现了除夕夜系统零故障。

文章转自:http://www.infoq.com/cn/articles/2017hongbao-weixin

相关文章
相关标签/搜索