微信红包订单存储架构变迁的最佳实践
geek1202
8年前
<h3><strong>微信红包的由来 </strong></h3> <p>南方企业一直有过年找老板“逗利是”的习俗,每年春节后开工的第一天,腾讯大厦都会排上长长的队伍,集体上楼找老板们领红包。按照广东习俗,已经结婚的同事也要给未婚同事发红包,这一天腾讯员工就在春茗和寻找红包中度过。</p> <p>由此孵化了一个内部项目,通过微信来收发红包,把这个公司全员娱乐活动与最活跃的IM平台微信结合起来。最初这个项目并没有预期对外,但是入口不小心开放后,成为了现象级产品。2014年开始爆发性增长,每年的发放量都是上一年的若干倍。根据腾讯公布的数据,到2016年春节,已经是每秒十万次支付,每天近十亿订单的系统。</p> <p>微信红包本质是小额资金在用户帐户流转,有发、抢、拆三大步骤。在这个过程中对事务有高要求,所以订单最终要基于传统的RDBMS,这方面是它的强项,最终订单的存储使用互联网行业最通用的MySQL数据库。支持事务、成熟稳定,我们的团队在MySQL上有长期技术积累。但是传统数据库的扩展性有局限,需要通过架构解决。</p> <h3><strong>前端流量控制 </strong></h3> <p>发十亿红包,难在哪里?大量用户在同一时间发抢红包,瞬间产生每秒数万次的请求,除夕可能成百千万次;这个量级的请求如果不加以疏导处理直接到达后台,必定会导致后端服务过载甚至崩溃。主要思路是缩短关键业务流程,分离可以通过异步、缓存等方式解决的问题,减轻系统压力,加快响应速度,在存储层前面建上一座大坝。</p> <p>CGI无状态</p> <p>接入层无状态,逻辑层也无状态,可以方便地水平扩展。但依赖MySQL事务保证交易完整,保证红包系统的精简,减少瓶颈的存在。</p> <p>资源静态化</p> <p>利用腾讯强大的基础资源优化部署,尽量把动态内容转为静态资源。静态资源和CGI分离,静态资源通过CDN就近接入,减少用户和CGI的交互,减少内网、访问延时和数据请求。</p> <p>业务流程异步化</p> <p>微信红包的发、抢、拆背后都有多个内部环境,关键流程精简,非关键流程和后续业务逻辑进入异步队列进行处理,减少了用户的等待时间,也极大降低了峰值雪崩的概率。繁多的非关键链路也不会影响到主流程。</p> <p>过载保护</p> <p>前端保护后端,能在前端处理,就不传递到后端。前端需要按后端能力做削峰限流;客户端、接入层、逻辑层逐层控制流量;前端更容易容错处理,全力保护存储层。微信的过载保护在客户端已提前预埋了策略,在连接失败或超时情况下会有相应提示,减少用户重复请求次数。接入层针对频繁发出请求的客户端限制响应速度,并对系统负载划分出若干等级,达到不同阈值时引导客户端使用不同限速速率;在异常情况出现时,异步限流降速减轻服务器端压力防止过载。</p> <p>多级读缓存</p> <p>发一个群红包,抢红包的请求量远大于发红包,如果已经领过完全可以拒绝。逻辑层增加缓存,类似可以缓存的请求都缓存起来,进一步减少存储层流量。</p> <p>订单写缓存</p> <p>订单系统有很多请求不会真正完成全流量,创建这些废单不但浪费存储资源,还会挤占逻辑层和数据层的处理能力,影响其他交易。订单在完成支付前可以先落在缓存中,完成支付后再持久化。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/d8e1f92f6cacb398241b7a088535acd6.jpg"></p> <h3><strong>存储层的高可用设计 </strong></h3> <p>在数百倍千倍的业务增长下,存储层很难简单无限扩容,一方面设备成倍增加的成本巨大,另一方面存储层瓶颈堆积不一定能解决问题。</p> <p>读写分离</p> <p>写请求需要在主机上,实时读也需要走主机。有大量对延时不那么敏感,又影响性能的查询,完全可以放到从机。读写分离策略是MySQL分布式的入门,简洁地提高了系统容量。</p> <p>水平切分</p> <p>数据的水平切分,实质就是分库分表;选取一张数据表按照主要纬度把数据拆分开。实现存储层的平行扩展。有效降低了单台数据库机器的负载,也减小了服务不可用的可能性。单台数据库宕机只会导致部分数据不能访问。主要需要考虑路由规则的选定,方便扩缩容以及数据的均衡分布。</p> <p>垂直切分</p> <p>数据表除了水平切分,行内数据可以按属性进一步分开。核心表只保留最关键的字段,保证数据文件短小紧凑。以红包为例,昵称和祝福语这类较长的信息,不属于核心数据,完全可以切分到别的机器上,进一步提升核心数据库的容量。不同数据适合的存储类型也不一样,这类重复率高的长字符串更适合NoSQL存储,对存储空间和性能都是节约极大。</p> <p>空间换时间</p> <p>按不同纬度组织表,比如按订单属性和用户属性进行组织;适应不同的请求场景,避免复杂的查询。不同纬度的表可以通过对账对齐,非核心表可以适当冗余,减少多次请求。</p> <p>锁的优化</p> <p>多人争抢红包通过数据库事物来保证,必然存在竞争MySQL行锁。核心事物必须尽量精简,避免死锁。同一个订单的所有请求,尽量在逻辑层进程预排队后通过一个连接发送请求到数据库。</p> <p>冷热分离</p> <p>核心数据库存放高频数据,其他数据可以定时移到成本低的冷数据库中。这样可以为核心数据库使用最好的SSD设备,快速设备容量较小较贵,不可能在全量数据上使用。同时可以保证数据表的容量不会一直积累,大表也会导致性能下降。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/3ef8be9c42015a73c0e00c3fc417cb59.jpg"></p> <h3><strong>异地多活 </strong></h3> <p>当系统足够大时,就必须开始考虑异地部署的问题,让数据尽可能离用户更近。而且进一步的高可用不能局限在同一地域,必须跨数据中心跨城多活才能抵御系统性风险。因为跨城的几十毫秒延时,微信红包的异地活动设计为多数据中心相互独立。非灾难灰度不会将其他数据中心的数据导入到线上。</p> <p>就近接入</p> <p>以微信红包系统的异步部署为例,第一个好处是用户就近接入,减少跨城的穿越流量。根据发送者的地域标志数据落地到不同数据中心,在不同地域实现业务闭环。</p> <p>数据分离</p> <p>当前的网络技术限制,使用光纤也无法保证跨城数据的同步延时问题。所以微信红包的跨城数据中心并不进行数据实时同步。不同区域各自承载业务流量,地域上实现平衡,各地的订单数据各自独立存储。</p> <p>异地容灾</p> <p>如果出现地域性故障,我们需要有机制去保证服务可用性。有了异步部署,假如深圳出现系统性故障,那么我们可以直接把请求接入上海。各数据中心独立部署,如果某地系统达到最大容量,可以进行跨地域分流。</p> <h3><strong>有损服务和柔性降级 </strong></h3> <p>我们遇到最多的问题就是海量请求,通过分布式系统来实现海量请求,根据CAP理论不能同时保证一致性和高可用,必须有取舍。我们首先保证可用性,同时实现最终一致性。有以下原则。</p> <p>有损服务</p> <p>要追求高可用性,可以牺牲部分数据一致性和完整性从而保证核心功能。在资源一定的前提下,满足用户的核心需求。微信红包的核心点是抢、拆红包,系统必须尽最大可能保证核心步骤流畅,但在瓶颈时立即降级防止引起系统雪崩。但是要保证数据能最终对齐,金融属性的系统数据安全硬要求。</p> <p>柔性可用</p> <p>柔性可用是在有损服务价值观支持下的方法,结合具体场景提供不同级别的用户体验,保证尽可能成功返回关键数据。把握用户在每一个场景中的核心需求,设计不同层次满足核心诉求的办法。系统首先要实现容灾和自动切换;其次逻辑资源应该隔离;服务过载时必须自动快速拒绝。</p> <h3><strong>结束语 </strong></h3> <p>本文简单介绍了微信红包的存储层服务设计准则,在业务从起步到小跑再到腾飞的过程中,背后的海量服务能力将对其最终成败有着越来越深远的影响。在互联网爆发性增长中,海量服务能力决定项目成败,必须在项目初期就做好海量服务的准备。</p> <p> </p> <p> </p> <p>来自:http://mp.weixin.qq.com/s/HTDSZWpYrHeqShzDOuz3kg</p> <p> </p>