支付宝架构师眼中的高并发架构

高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:秒杀活动,定时领取红包等。
日用户流量大,但是比较分散,偶尔会有用户高聚的情况;

场景:用户签到,用户中心,用户订单,等
支付宝架构师眼中的高并发架构
方案如:

用户签到获取积分
1、计算出用户分布的key,redis hash中查找用户今日签到信息
2、如果查询到签到信息,返回签到信息
3、如果没有查询到,DB查询今日是否签到过,如果有签到过,就把签到信息同步redis缓存。
4、如果DB中也没有查询到今日的签到记录,就进行签到逻辑,操作DB添加今日签到记录,添加签到积分(这整个DB操作是一个事务)
5、缓存签到信息到redis,返回签到信息
6、注意这里会有并发情况下的逻辑问题,如:一天签到多次,发放多次积分给用户。

用户订单
1、这里我们只缓存用户第一页的订单信息,一页40条数据,用户一般也只会看第一页的订单数据
2、用户访问订单列表,如果是第一页读缓存,如果不是读DB
3、计算出用户分布的key,redis hash中查找用户订单信息
4、如果查询到用户订单信息,返回订单信息
5、如果不存在就进行DB查询第一页的订单数据,然后缓存redis,返回订单信息

用户中心
1、计算出用户分布的key,redis hash中查找用户订单信息
2、如果查询到用户信息,返回用户信息
3、如果不存在进行用户DB查询,然后缓存redis,返回用户信息

其他业务
上面例子多是针对用户存储缓存,如果是公用的缓存数据需要注意一些问题,如下
注意公用的缓存数据需要考虑并发下的可能会导致大量命中DB查询,可以使用管理后台更新缓存,或者DB查询的锁住操作。
博文《大话Redis进阶》对更新缓存问题和推荐方案的分享。
二、消息队列
秒杀、秒抢等活动业务,用户在瞬间涌入产生高并发请求
场景:定时领取红包,等
服务器架构图
支付宝架构师眼中的高并发架构
说明:

场景中的定时领取是一个高并发的业务,像秒杀活动用户会在到点的时间涌入,DB瞬间就接受到一记暴击,hold不住就会宕机,然后影响整个业务

像这种不是只有查询的操作并且会有高并发的插入或者更新数据的业务,前面提到的通用方案就无法支撑,并发的时候都是直接命中DB;

设计这块业务的时候就会使用消息队列的,可以将参与用户的信息添加到消息队列中,然后再写个多线程程序去消耗队列,给队列中的用户发放红包
方案如:

定时领取红包
1、一般习惯使用 redis的 list
2、当用户参与活动,将用户参与信息push到队列中
3、然后写个多线程程序去pop数据,进行发放红包的业务
4、这样可以支持高并发下的用户可以正常的参与活动,并且避免数据库服务器宕机的危险

附加:
通过消息队列可以做很多的服务。

如:定时短信发送服务使用sset(sorted set),发送时间戳作为排序依据,短信数据队列根据时间升序然后写个程序定时循环去读取sset队列中的第一条,当前时间是否超过发送时间,如果超过就进行短信发送

异步
那么像这种高并发业务我们要如何设计开发方案可以降低数据库服务器的压力呢?

如:
自动弹窗签到,双11跨0点的时候并发请求签到接口
双11抢红包活动
双11订单入库

设计考虑:
1、逆向思维,压力在数据库,那业务接口就不进行数据库操作不就没压力了
2、数据持久化是否允许延迟?
3、如何让业务接口不直接操作DB,又可以让数据持久化?

方案设计:
1、像这种涉及数据库操作的高并发的业务,就要考虑使用异步了
2、客户端发起接口请求,服务端快速响应,客户端展示结果给用户,数据库操作通过异步同步
如何实现异步同步
1、使用消息队列,将入库的内容enqueue到消息队列中,业务接口快速响应给用户结果(可以温馨提示高峰期延迟到账)
2、然后再写个独立程序从消息队列dequeue数据出来进行入库操作,入库成功后刷新用户相关缓存,如果入库失败记录日志,方便反馈查询和重新持久化
这样一来数据库操作就只有一个程序(多线程)来完成,不会给数据带来压力

补充:
1、消息队列除了可以用在高并发业务,其他只要有相同需求的业务也是可以使用,如:短信发送中间件等
2、高并发下异步持久化数据可能会影响用户的体验,可以通过可配置的方式,或者自动化监控资源消耗来切换时时或者使用异步,这样在正常流量的情况下可以使用时时操作数据库来提高用户体验
3、异步同时也可以指编程上的异步函数,异步线程,在有的时候可以使用异步操作,把不需要等待结果的操作放到异步中,然后继续后面的操作,节省了等待的这部分操作的时间
支付宝架构师眼中的高并发架构