zoukankan      html  css  js  c++  java
  • 揭秘微信红包:架构、抢红包算法、高并发和降级方案

    编者按

    与传统意义上的红包相比,近两年火起来的“红包”,似乎才是如今春节的一大重头戏。历经上千年时代传承与变迁,春节发红包早已成为历史沉淀的文化习俗,融入了民族的血脉。按照各家公布的数据,除夕全天微信用户红包总发送量达到80.8亿个,红包峰值收发量为40.9万个/秒。春晚直播期间讨论春晚的微博达到5191万条,网友互动量达到1.15亿,网友抢微博红包的总次数超过8亿次。

    为此,InfoQ策划了“春节红包”系列文章,以期为读者剖析各大平台的红包活动背后的技术细节。本文为微信篇。

    微信红包在经过15年春晚摇一摇之后,2015年上半年业务量一度呈指数级增长。尤其是微信红包活跃用户数的大量增长,使得2016除夕跨年红包成为极大挑战。为了应对16年春节可预知的红包海量业务,红包系统在架构上进行了一系列调整和优化。主要包括异地架构、cache系统优化、拆红包并发策略优化、存储优化一系列措施,为迎接2016春节红包挑战做好准备。 下面介绍最主要的一些思路。

    架构

    微信用户在国内有深圳、上海两个接入点,习惯性称之为南、北(即深圳为南,上海为北)。用户请求接入后,不同业务根据业务特性选择部署方式。微信红包在信息流上可以分为订单纬度与用户纬度。其中订单是贯穿红包发、抢、拆、详情列表等业务的关键信息,属于交易类信息;而用户纬度指的是红包用户的收红包列表、发红包列表,属于展示类信息。红包系统在架构上,有以下几个方面:

    南北分布

    1、订单层南北独立体系,数据不同步

    用户就近接入,请求发红包时分配订单南北,并在单号打上南北标识。抢红包、拆红包、查红包详情列表时,接入层根据红包单号上的南北标识将流量分别引到南北系统闭环。根据发红包用户和抢红包用户的所属地不同,有以下四种情况:

    1) 深圳用户发红包,深圳用户抢

    订单落在深圳,深圳用户抢红包时不需要跨城,在深圳完成闭环。

    2) 深圳用户发红包,上海用户抢

    订单落在深圳,上海用户抢红包,在上海接入后通过专线跨城到深圳,最后在深圳闭环完成抢红包。

    3) 上海用户发红包,上海用户抢

    订单落在上海,上海用户抢红包时不需要跨城,在上海完成闭环。

    4) 上海用户发红包,深圳用户抢

    订单落在上海,深圳用户抢红包,从深圳接入后通过专线跨城到上海,最后在上海闭环完成抢红包。

    系统这样设计,好处是南北系统分摊流量,降低系统风险。

    2、用户数据写多读少,全量存深圳,异步队列写入,查时一边跨城

    用户数据的查询入口,在微信钱包中,隐藏的很深。这决定了用户数据的访问量不会太大,而且也被视为可旁路的非关键信息,实时性要求不高。因此,只需要在发红包、拆红包时,从订单纬度拆分出用户数据写入请求,由MQ异步写入深圳。后台将订单与用户进行定时对账保证数据完整性即可。

    3、支持南北流量灵活调控

    红包系统南北分布后,订单落地到深圳还是上海,是可以灵活分配的,只需要在接入层上做逻辑。例如,可以在接入层中,实现让所有红包请求,都落地到深圳(无论用户从上海接入,还是深圳接入),这样上海的红包业务系统将不会有请求量。提升了红包系统的容灾能力。同时,实现了接入层上的后台管理系统,实现了秒级容量调控能力。可根据南北请求量的实时监控,做出对应的调配。

    4、DB故障时流量转移能力
    基于南北流量的调控能力,当发现DB故障时,可将红包业务流量调到另外一边,实现DB故障的容灾。

    预订单

    支付前订单落cache,同时利用cache的原子incr操作顺序生成红包订单号。优点是cache的轻量操作,以及减少DB废单。在用户请求发红包与真正支付之间,存在一定的转化率,部分用户请求发红包后,并不会真正去付款。

    拆红包入账异步化

    信息流与资金流分离。拆红包时,DB中记下拆红包凭证,然后异步队列请求入账。入账失败通过补偿队列补偿,最终通过红包凭证与用户账户入账流水对账,保证最终一致性。

    这个架构设计,理论基础是快慢分离。红包的入账是一个分布事务,属于慢接口。而拆红包凭证落地则速度快。实际应用场景中,用户抢完红包,只关心详情列表中谁是“最佳手气”,很少关心抢到的零是否已经到账。因为只需要展示用户的拆红包凭证即可。

    发拆落地,其他操作双层cache

    1、Cache住所有查询,两层cache

    除了使用ckv做全量缓存,还在数据访问层dao中增加本机内存cache做二级缓存,cache住所有读请求。

    查询失败或者查询不存在时,降级内存cache;内存cache查询失败或记录不存在时降级DB。

    DB本身不做读写分离。

    2、DB写同步cache,容忍少量不一致
    DB写操作完成后,dao中同步内存cache,业务服务层同步ckv,失败由异步队列补偿,定时的ckv与DB备机对账,保证最终数据一致。

    高并发

    微信红包的并发挑战,主要在于微信大群,多人同时抢同一个红包。这种情况,存在竞争MySQL行锁。为了控制这种并发,团队做了以下一些事情:

    1、请求按红包订单路由,逻辑块垂直sticky,事务隔离

    按红包订单划分逻辑单元,单元内业务闭环。服务rpc调用时,使用红包订单号的hash值为key寻找下一跳地址。对同一个红包的所有拆请求、查询请求,都路由到同一台逻辑机器、同一台DB中处理。

    2、Dao搭建本机Memcache内存cache,控制同一红包并发个数

    在DB的接入机dao中,搭建本机内存cache。以红包订单号为key,对同一个红包的拆请求做原子计数,控制同一时刻能进DB中拆红包的并发请求数。

    这个策略的实施,依赖于请求路由按红包订单hash值走,确保同一红包的所有请求路由到同一逻辑层机器。

    3、多层级并发量控制
    1) 发红包控制

    发红包是业务流程的入口,控制了这里的并发量,代表着控制了红包业务整体的并发量。在发红包的业务链路里,做了多层的流量控制,确保产生的有效红包量级在可控范围。

    2) 抢红包控制

    微信红包领取时分为两个步骤,抢和拆。抢红包这个动作本身就有控制拆并发的作用。因为抢红包时,只需要查cache中的数据,不需要请求DB。对于红包已经领完、用户已经领过、红包已经过期等流量可以直接拦截。而对于有资格进入拆红包的请求量,也做流量控制。通过这些处理,最后可进入拆环节的流量大大减少,并且都是有效请求。

    3) 拆时内存cache控制

    针对同一个红包并发拆的控制,上文已经介绍。

    4、DB简化和拆分

    DB的并发能力,有很多影响因素。红包系统结合红包使用情境,进行了一些优化。比较有借鉴意义的,主要有以下两点:

    1) 订单表只存关键字段,其他字段只在cache中存储,可柔性。

    红包详情的展示中,除了订单关键信息(用户、单号、金额、时间、状态)外,还有用户头像、昵称、祝福语等字段。这些字段对交易来说不是关键信息,却占据大量的存储空间。

    将这些非关键信息拆出来,只存在cache,用户查询展示,而订单中不落地。这样可以维持订单的轻量高效,同时cache不命中时,又可从实时接口中查询补偿,达到优化订单DB容量的效果。

    2) DB双重纬度分库表,冷热分离

    使用订单hash、订单日期,两个纬度分库表,也即db_xxx.t_x_dd这样的格式。其中,x表示订单hash值,dd表示01-31循环日。订单hash纬度,是为了将订单打散到不同的DB服务器中,均衡压力。订单日期循环日纬度,是为了避免单表数据无限扩张,使每天都是一张空表。

    另外,红包的订单访问热度,是非常典型的冷热型。热数据集中在一两天内,且随时间急剧消减。线上热数据库只需要存几天的数据,其他数据可以定时移到成本低的冷数据库中。循环日表也使得历史数据的迁移变得方便。

    红包算法

    首先,如果红包只有一个,本轮直接使用全部金额,确保红包发完。

    然后,计算出本轮红包最少要领取多少,才能保证红包领完,即本轮下水位;轮最多领取多少,才能保证每个人都领到,即本轮上水位。主要方式如下:

    计算本轮红包金额下水位:假设本轮领到最小值1分,那接下来每次都领到200元红包能领完,那下水位为1分;如果不能领完,那按接下来每次都领200元,剩下的本轮应全部领走,是本轮的下水位。

    计算本轮红包上水位:假设本轮领200元,剩下的钱还足够接下来每轮领1分钱,那本轮上水位为200元;如果已经不够领,那按接下来每轮领1分,计算本轮的上水位。

    为了使红包金额不要太悬殊,使用红包均值调整上水位。如果上水位金额大于两倍红包均值,那么使用两倍红包均值作为上水位。换句话说,每一轮抢到的红包金额,最高为两倍剩下红包的均值。

    最后,获取随机数并用上水位取余,如果结果比下水位还小,则直接使用下水位,否则使用随机金额为本轮拆到金额。

    柔性降级方案

    系统到处存在发生异常的可能,需要对所有的环节做好应对的预案。下面列举微信红包对系统异常的主要降级考虑。

    1、 下单cache故障降级DB

    下单cache有两个作用,生成红包订单与订单缓存。缓存故障情况下,降级为直接落地DB,并使用id生成器独立生成订单号。

    2、 抢时cache故障降级DB

    抢红包时,查询cache,拦截红包已经抢完、用户已经抢过、红包已经过期等无效请求。当cache故障时,降级DB查询,同时打开DB限流保护开关,防止DB压力过大导致服务不可用。

    另外,cache故障降级DB时,DB不存储用户头像、用户昵称等(上文提到的优化),此时一并降级为实时接口查询。查询失败,继续降级为展示默认头像与昵称。

    3、 拆时资金入账多级柔性

    拆红包时,DB记录拆红包单据,然后执行资金转账。单据需要实时落地,而资金转账,这里做了多个层级的柔性降级方案:

    大额红包实时转账,小额红包入队列异步转账 所有红包进队列异步转账 实时流程不执行转账,事后凭单据批量入账。

    总之,单据落地后,真实入账可实时、可异步,最终保证一致即可。

    4、 用户列表降级

    用户列表数据在微信红包系统中,属于非关键路径信息,属于可被降级部分。

    首先,写入时通过MQ异步写,通过定时对账保证一致性。

    其次,cache中只缓存两屏,用户查询超过两屏则查用户列表DB。在系统压力大的情况下,可以限制用户只查两屏。

    调整后的系统经过了16年春节的实践检验,平稳地度过了除夕业务高峰,保障了红包用户的体验。

    作者介绍

    方乐明,2011年毕业于华南理工大学通信与信息系统专业,毕业后就职于财付通科技有限公司。微信支付团队组建后,主要负责微信红包、微信转账、AA收款等支付应用产品的后台架构。

    原文:http://www.infoq.com

    http://cxy.liuzhihengseo.com/522.html

  • 相关阅读:
    hdu 2222 Keywords Search
    Meet and Greet
    hdu 4673
    hdu 4768
    hdu 4747 Mex
    uva 1513 Movie collection
    uva 12299 RMQ with Shifts
    uva 11732 strcmp() Anyone?
    uva 1401
    hdu 1251 统计难题
  • 原文地址:https://www.cnblogs.com/8hao/p/5383143.html
Copyright © 2011-2022 走看看