红包系统架构设计

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

需求分析

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

  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 等方式提高并发能力。

参考资料

欢迎关注公众号:程序员开发者社区

  • 0
    点赞
  • 5
    收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值