红包系统架构设计

微信关注公众号(Lambda在线)

第一时间推送最新技术资料

红包系统架构设计

软件系统设计,第一步,确定关键需求。

需求分析

比如红包这个系统,需要有如下:

  1. 包红包
  2. 发红包
  3. 抢红包
  4. 拆红包
  5. 不能抢超,也就是说红包个数,金额是有限的,不能超的。
  6. 支持高并发,例如1亿用户凌晨12点开始抢红包。

上面的 4 方面就是关键需求。

  • 包红包:系统为每个红包设置一个 id ,然后将红包发送个用户,这里需要设置 红包金额,红包个数,要发送的用户,存储这些信息。
  • 发红包,设置完红包参数后,微信支付,完成付款,然后收到付款成功通知,红包系统更新红包订单状态,更新为已支付,并写入红包发送记录表。这样用户可以将用户的红包信息和红包的收发记录发出,红包系统调用微信通知,将红包信息发送到微信群。
  • 抢红包,微信群用户收到红包后,点开,红包系统会校验红包是否被抢完,是否过期。
  • 拆红包,拆红包时,要先查询红包订单,判断是否可拆,计算本次拆的红包金额,记录抢红包流水。

流程如下:

几个问题

抢红包那一刻 时间短,瞬时用户量大。

  1. 为啥有时候抢到了红包,点开后就是没有,说明抢和拆是分开的,抢只能说明交易被受理,扣减库存成功才能真的说被抢到了。

  2. 红包金额怎么算?

  3. 红包金额什么时候算?

  4. 如何计算红包被抢完了?

  5. 如何保证每秒8w的写入?

  6. 如何防止恶意请求?

  7. 领一个红包就更新数据么?

  8. 红包如何入账?

针对上面的问题,可以做出如下思考:

秒杀场景是读多写少的。

第一反应,会想到 Redis 计数,红包个数减到0 表示红包抢完。但是有个问题,Redis 有 decr 原子递减,redis 原子递减会变成负数,还是有超抢问题。

Redis  内嵌了lua 支持,解决了长久以来多个命令组合的问题。有点类似事务,有一定原子性,可以用完成一定事务性操作,可以将扣减操作写在lua脚本里,然后 Redis 去执行,扣减到0 返回 false。这样避免超抢超卖。

但是随之而来又有一个问题? Redis 并发很高么,上亿用户同时请求怎么办 ,QPS 怎么也要到10w。

那就得 对 Redis 做文章:

Redis 集群,主从同步,读写分离。

假设这时候有黑客或黄牛怎么办,在不断的用脚本点击链接或者红包,怎么避免?

链接不能写死,用MD5 进行链接加密,后台验证之后才能通过。否则认为是攻击。

通过 Redis 或者链接加密的方式 已经把大部分交易拦住了,但是这短时间还是有大部分交易,比如凌晨12点10亿人抢5000w个红包,现在放了5000w个请求进来,并发还是很高, 怎么办?这5000w 个人说明抢到红包了,接下来就是拆红包了。

这个时候就需要流量消峰,会想到使用 MQ 队列来排队处理用户请求。阀值或者说库存以 Redis 为主,需要扣减库存。

流量削峰了,使得流量平缓,慢慢处理。

拆红包过程就是主要的业务逻辑,主要包含3步骤:

  1. 锁库存

  2. 插入秒杀记录

  3. 更新库存

拆红包过程:扣减库存和秒杀记录的操作,更新库存就是更新红包发送的订单,还有就是写入秒杀记录就是写入红包领取的信息流水。还需要以用户为中心记录用户整体领了多少红包。最后调用支付系统将拆红包后的金融转入用户余额,成功之后更新抢红包的订单状态为转账成功。

为提高性能,往往将库存信息放到内存 Cache 中, 内存Cache 操作成功后给Server 返回成功,然后异步落 DB 持久化。

基于上面的问题,考虑下微信红包怎么设计?

微信红包用户发一个红包时,有一个系统 ID ,作为这个红包的唯一标识,接着有 包,发 ,抢,拆 都与 ID 关联。红包系统根据 ID ,按照一定规则,垂直上下切分,切分后一个垂直链条上的逻辑 server 服务器,包含一个DB ,同一个红包 ID 的所有请求均路由到同一个 Set 内处理。这样系统之间相互独立,相互解耦。将海量事务操作化成小量。

红包系统架构设计

同一个请求如何路由到同一个逻辑 Server ?

同个红包 ID 的所有请求,按照红包 ID  路由到同一个 Set ,一个逻辑 Server 会存在多个 Server ,但是 这些 Server 共享同一个 DB。

红包系统架构设计

单点 Server 如何请求排队

当红包 ID 路由到同一台Server 上时,请求被受理,此时需要进入队列。串行的执行。

memcached 控制并发

memcached 是用来控制并发的,当队列过载的时候,拒绝服务。具体来说,利用memcached的CAS原子增操作,控制同时进入DB执行拆红包事务的请求数,超过预先设定数值则直接拒绝服务,用于DB负载升高时的降级体验。

双维度分库分表

根据红包ID 的hash 值的基础上做多库多表。在此基础之上,再根据,红包订单的时间进行分表,简单的来说,就是形成 db_xx.t_y_dd 的“库.表”的结构,其中xx|y是红包ID的hash值后三位,dd的取值范围在1~31,代表一个月天数最多31天。

server 还需要进行 包,发,抢,拆,几个操作。可以分别封装成单个微服务,进行分布式部署,提高处理能力。

总结

微信红包系统在解决高并发问题上的设计,主要采用了SET分治、请求排队、双维度分库表等方案,可以使得红包系统Server适应高并发,同时Server采用 Redis 库存扣减防止超卖,异步入 DB 等方式提高并发能力。

参考资料

  • https://cloud.tencent.com/developer/article/1637408
  • https://cloud.tencent.com/developer/article/1097433
  • https://melonshell.github.io/2020/01/23/tech2_wx_red_packet/
  • https://www.zhihu.com/question/54895548/answer/923987542?clicktime=1579081979
  • https://www.cnblogs.com/zyl2016/articles/9928567.html
欢迎关注公众号:程序员开发者社区
微信号:程序员开发者社区
博客:CSDN 王小明
关注我们,了解更多






版权申明:本站内容全部来自于腾讯微信公众号,属第三方自助提交推荐。《红包系统架构设计》的版权归原作者「程序员开发者社区」所有, 文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

程序员开发者社区

程序员开发者社区

分享 读书,旅行,摄影,IT技术,欢迎积极讨论

猜你喜欢