红包大战考验支付系统,揭秘微信摇一摇背后的技术细节

2016 年 4 月 11 日

编者按

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

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

2016 年春节已经过去了一段时间,微信红包也再次为春节增添了新的欢乐,为春节增添了新的年味,也成为了各种微信群活跃气氛的利器。为了让全国人民顺畅地玩红包,从网络运营商、微信基础消息系统、支付系统,到银行,无不为之付出了大量的人力和物力。作为红包整个环节中的发(即支付)这一步,支付系统承担了重要的责任。

在介绍 2016 年支付系统之前,先简单回顾一下。2015 年,红包支付以迅猛的趋势快速增长。2015 年 5 月,节日红包就已经突破了除夕的峰值。到年底的时候,日常更是已经达到每秒 2 万笔以上的支付峰值。2015 年春节,我们的支付系统为了红包做了充分的准备并顺利完成了春节任务,支撑红包支付突破每秒 1 万笔的峰值。但是回过头来看,虽然对支付系统做过很多次优化,但仍然存在一些不足。

2015 年,我们为红包支付做的优化有以下几项:

  • 支付核心路径梳理简化;
  • 通过预演确定请求访问模型,制定核心模块的支撑容量;
  • 关键模块自我保护机制;
  • 准静态数据多级缓存保护;
  • 非核心功能手工降级。

虽然做了这些优化,在经历过 2015 年春节后,我们发现了一些不足之处:

  • 链路耦合:红包交易对整体支付系统的冲击很大,也一定程度影响到了商业支付;
  • 简单粗暴的旁路保护:核心模块与非核心模块的容量并不平衡,虽然核心模块对非核心模块的异常有自保措施,无法避免非核心模块在高压下过载;
  • 支付异常体验差:支付扣款环节的异常的体验不闭环,支付结果不明确,容易导致用户产生重复支付行为;
  • 降级处理慢:人工降级的决策和实施时间较长,影响业务恢复的及时性;
  • 内部安全风险:为了赶业务目标,内部的部分资金敏感接口处于“裸奔”状态,随时可能成为安全问题的定时炸弹。

针对 2016 年春节,我们定下了支撑峰值每秒 10 万笔的目标,再加上上面提到的不足,系统的可用性保障面临较大的挑战。接下来分享一下我们所做出的准备工作。

一 支付架构

经过详细分析和设计,2016 年春节的红包支付架构引入了几个新的变化。

(点击放大图像)

1 红包交易链路独立

  • 针对红包的交易链路做隔离,除了一些公共服务及收款渠道服务(零钱系统和银行清算系统)以外,彻底和商业支付分开;
  • 链路独立后,一个好处是可以针对红包的特点,大幅简化支付处理逻辑,另一个好处是,可以独立针对红包链路单独做柔性降级处理,而不会影响商业支付的体验。

2 极简红包支付逻辑

  • 针对红包系统的支付下单请求,仅验证内部票据即可,原有的大量鉴权逻辑及支付渠道按规则选择逻辑可以全部裁剪,对周边系统的依赖几乎可以降为零;
  • 针对红包的支付过程快的特点,将交易流程的上下文 session 数据换成高性能、低成本、低容灾级别的全内存服务集群处理,即使某台内存存储的机器故障,也只会影响极短时间的一小部分的用户支付;
  • 针对红包是最简单的支付业务形态的特点,不记录交易单据,以红包业务单据来代替,红包业务系统直接和资金系统进行最终交易对账处理。如此进一步减少红包支付逻辑的复杂度,提高整体可用性。

3 高可靠消息总线解耦非核心模块

  • 建设超高可靠、超大队列容量、灵活控制消费频率的消息总线系统;
  • 解除非核心模块在高压力业务路径中的调用耦合,对红包高峰涌来时产生的巨量内部非核心模块调用进行削峰,减少冲击导致过载。

4 票据系统全程保护调用的安全

  • 支付系统内部接口敏感性高,需要确保接口使用的安全性;
  • 在用户及商户鉴权的同时,生成不可伪造的票据,在业务过程中,由底层中间件系统全程携带票据到各个接口,并进行必要的接口请求合法性验证。

二 高并发下的异常应对

1 多 IDC 容灾

  • 由于业务峰值高,容灾冗余的成本非常大,无法做到完全任意 IDC 故障不影响业务,容灾策略上有所权衡;
  • 所有可以做到业务无 IDC 状态的服务,至少有两个地点的 IDC 服务集群;
  • 每个服务的所有 IDC 服务集群中,最多只能有一个集群,如果发生故障,另外的集群无法全量接管请求量;
  • 万一极端情况出现,降低设计容量,进行业务限流。

2 优先零钱

  • 由于大量高频的群红包绝大比例是小额红包,所以但凡发现用户零钱够,就优先默认帮用户选择零钱来支付(用户也可以手工修改为其他支付方式);
  • 一方面大幅减少群里面小金额红包支付对可控性相对较差的银行渠道的压力,另一方面也降低了支付资金操作接口的耗时,进而降低系统服务处理的并发程度及负载,还可以提升用户的支付体验。

3 自动 QOS

  • 按是否核心链路、重要程度做、是否明显影响用户体验几个方面,对接口作优先级分档排序;
  • 当有高并发请求时,系统监控到有抖动时(服务队列满、系统错误突增、机器负载高、io 高 等),自动从低优先级的接口开始做快速拒绝,逐步恢复系统。

4 消除支付异常的等待及不明确

  • 前端调用支付流程如果出现非明确的异常(银行收款超时,系统内部抖动,网络异常等),此时扣款渠道有可能已经成功,也有可能未成功,着急的用户可能会连续支付多笔,而胆小的用户也许不敢再发起支付;

  • 在高并发下,这种异常会更加频繁产生,因此需要全面提升支付异常下的体验: a) 在支付流程异常时,发布支付结果未明的事件到可靠消息总线;

    b) 可靠消息总线在一定的用户可接受的等待延迟后,进行扣款渠道的单据结果确认,如果尚未成功,则对当次扣款渠道单据进行锁定,保障后续一定不会再成,如果实际的资金已经发生,则还需要负责及时将资金退回;

    c) 在整个过程中,每一步确认及操作的结果均通过微信支付消息触达到用户来透明信息,减少用户的困惑及等待。

5 其他体验柔性

  • 钱包首页体验柔性 a) 由于在摇红包后或者发红包高峰时,大量用户会进入钱包首页查看零钱,此时对余额和绑卡数据的查询量会非常大,极可能影响收银台的相关功能稳定性;

    b) 针对首页查询设置固定的限流值来保护后端系统,在限流时,钱包首页的零钱将使用客户端的缓存数据,不会自动刷新,并且会挂出延迟公告,需要再进入下一级的零钱界面(大概是首页访问量的 1/7),才会刷新。

  • 朋友圈红包降级 针对朋友圈红包(发红包看图),设计了惊喜体验的巧妙降级逻辑,当支付系统异常时,会不断提高彩蛋(免单)的比例,以减少对支付系统的压力,直至业务恢复或者全部降级。

  • 交易流水记录缓存 如果交易流水查询系统出现异常,客户端及 H5 页面会自动将最近访问到的缓存数据进行展示,并挂出数据延迟公告。

小结

对比 2015 年,2016 年的红包支付系统在高压下的可用性前进了一大步。但是和以往一样,我们依然看到了很多的不足之处,在可用性优化的路上,面对越来越大的压力,永远没有最优的架构和系统。我们会再针对新的问题,继续优化,迎来 2017 年的春节考验,也希望大家继续关注微信红包,见证系统的不断成长。

作者简介

姜楠 毕业之后即投身支付系统后台的设计及开发工作,早期在财付通参与对外清算及交易系统开发,后整体负责了微信支付系统从无到有的设计及搭建,经历了微信支付快速发展过程中的各种性能及可用性挑战,未来目标是在保障系统高资金安全及高可用性的架构设计上不断前行。


感谢陈兴璐对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016 年 4 月 11 日 17:15 3494

评论

发布
暂无评论
发现更多内容

这是一个测试文档

Geek_073cad

# LeetCode 863. All Nodes Distance K in Binary Tree

liu_liu

算法 LeetCode

MySQL的各种日志

超超不会飞

MySQL

知识也会生宝宝?

史方远

个人成长 随笔杂谈

开源分布式文件系统大检阅

焱融科技

sds 存储 开源项目 焱融科技 文件存储

Redis持久化了解一波!

不才陈某

redis 程序员 后端

美团可能会强势涉足 ToB

罗小布

创业 互联网巨头 深度思考 互联网

ARTS - Week Two

shepherd

js algorithm

杂谈-JSONP探索

卡尔

JavaScript, jsonp

Python 自动化办公之"你还在手动操作“文件”或“文件夹”吗?"

JackTian

Python 自动化

一个人,沿着童年的路究竟可以走多远?

zhoo299

童年 NASA 航天

我为什么开始技术写作?

架构精进之路

技术创作

奈学:传授“带权重的负载均衡实现算法”独家设计思路

奈学教育

分布式

Vue生态篇(二)

shirley

Vue

你不知道的SSD那些事

焱融科技

分布式 存储 SSD nvme

Go语言分布式系统配置治理

田晓亮

微服务

从 0 到 1 搭建技术中台之发布系统实践:集泳道、灰度、四端和多区域于一体的设计与权衡

伴鱼技术团队

架构 系统设计 系统架构 系统性思考 架构设计

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (十三)编写测试-生命周期方法

编程道与术

Java 编程 TDD 单元测试 JUnit

Vue生态篇(一)

shirley

JavaScript Vue

我常用的浏览器插件

彭宏豪95

chrome 效率工具 浏览器 插件

patroni 通过服务启动报错

yafeishi

数据库 高可用 AntDB

ARTS 第二周打卡

陈文昕

情绪的力量:如何使用情绪来达成目标

七镜花园-董一凡

情绪

我的 windows 利器

玄兴梦影

工具

架构学习历程

线程池续:你必须要知道的线程池submit()实现原理之FutureTask!

一枝花算不算浪漫

源码分析 并发编程

【Java 25周年有奖征文获奖名单公布!!!】关于Java,你最想赞扬、吐槽、期待的变化是什么?

InfoQ写作平台

写作平台 活动 Java25周年 活动专区

互联网时代的界限管理

非著名程序员

程序员 职场 提升认知 界限管理

程序员修炼的务实哲学

博文视点Broadview

程序员 软件 编程思维 工程师 编程之路

每个人都是领导者的工程团队

hongfei

# LeetCode 215. Kth Largest Element in an Array

liu_liu

算法 LeetCode

红包大战考验支付系统,揭秘微信摇一摇背后的技术细节-InfoQ