巨大瞬时流量
击垮服务造成瘫痪,或者机器资源高负载,整个请求链路的响应时间拉长。
热点数据问题
秒杀活动抢购的同一个商品,对存储系统是非常大的考验。
刷子流量
刷子通过程序实现接口的高频调用,挤占正常用户的抢购渠道。
DNS:负责域名解析,会将域名请求指定一个实际的ip来处理,客户端浏览器一般会缓存整个ip一段时间。
Nginx:一般被当作反向代理和负载均衡器使用,以及静态资源服务器。当Nginx收到客户端请求后,分发给下游服务器。
Web服务器:业务聚合的地方。
RPC服务:提供支撑业务的基础服务,公司内部调用。
业务隔离:一般会有计划地进行营销策略,制订详细的方案。有一个专门的提报系统。商家或者业务提供参与秒杀的商品编号/活动起止时间/库存量/限购规则/风控规则等基本信息,评估出大致的流量/并发数,评估是否需要扩容,降级限流策略。
系统隔离:秒杀首先进入商品详情页,申请独立的秒杀详情页域名,独立的Nginx,独立的详情页后端服务。秒杀详情页/秒杀结算页/秒杀下单扣减库存是重点关注的对象,需要物理隔离。
数据隔离:数据层的专有部署,设计部署拓扑结构。
微服务体系网关层依赖于tomcat,并发连接数单机几千,并发请求数单机过万,并发处理能力不高,而nginx并发连接数和并发请求数轻松过万,所以需要将网关层统一提升到nginx层。
页面静态化:动静分离的本质是将包含浏览器信息的动态数据和不包含浏览者信息的静态资源区分开,比如商品信息抽象出静态资源。
秒杀前答题:防止机器刷单,错开用户下单时长。
OpenResty
Nginx是应对并发几十万/上百万的网络请求连接场景的,但nginx的底层模块是采用C语言写的,如果在nginx上写业务逻辑很不方便,所以出现了OpenResty。开发人员可以通过lua脚本语言来编写。Lua的线程模型是单线程多协程的模式,同时语法简单。
Nginx服务器启动后,产生一个master进程,master进程产生多个worker进程。Worker进程处理外部请求。一般设置与cpu核数一致。Nginx具有cpu绑定选项,可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。
根据指定商品,创建秒杀活动,指定活动的开始时间/结束时间/库存等。
活动开始之前,由秒杀系统运营后台开启秒杀,canal服务设置秒杀产品库存初始值,往redis cluster集群写入首页秒杀活动信息和秒杀商品库存。String类型,key = miaosha:stock:cache:29,value = 6738232。
查询秒杀商品信息,生成静态页面,上传到OpenResty。
主流营销玩法:预约+秒杀。开放用户预约,只有预约了的用户才具备秒杀抢购资格,这是前期流量管控的核心。
库存扣减:要保证不超卖,查询和扣减两个操作必须是原子性的。Lua脚本可以实现。
// 预加载lua脚本
@PostConstruct
public void init() {
redisScript.setScriptText(STOCK_LUA);
redisScript.setResultType(Long.class);
loadScript(redisScript, STOCK_LUA_NAME);
isLoadScript.set(true);
}
风控的建设是基于用户画像的过程,一个用户画像的基础要素包括手机号/设备号/身份/地址/购物记录/信用值等。针对某个用户检查用户画像中的某些数据,是否触碰了红线,因此,数据越完整,风控判定越准确。
风控会降低接口的响应速度。
访问频次,如果判断某个人在某段时间的访问频率不能超过阈值,要经过大量的计算。
规则引擎
基于规则引擎,配置规则文件,Drools规则支持热更新,可以根据用户的某些信息打上标识,实现风控的逻辑。
实现流程
简单型规则:读取请求报文进行规则判断。比如判断手机号是否合法。
数据画像型规则:在请求报文基础上添加一些风控因子进行补充判断。比如黑名单禁止。布隆过滤器,拿用户的身份去布隆过滤器判断是否存在,判断是否在黑名单内。
累计型规则:对用户以往的交易进行累计计算。设定用户的日交易限额,超过则禁止。
批量计算型规则:比如对同一个用户,统计交易次数/金额等。
复杂事件型规则:比如连续登录失败5次,锁定账户。
机房容灾。
一般搭建多套相同的系统,当其中一个出现故障时,其他系统快速接管,提供业务的持续服务能力。
在多活架构下,对两套系统之间通信线路质量/时延要求很高,业内主流认可的时单向时延2ms以内。
异地双活,当距离较大,这种物理上的时间延迟很高,RT大幅增加。所以异地多活单元化的设计非常复杂,成本高。
同城双活,双机房距离近,通信线路质量好,比较容易实现数据的同步复制,保证高度的数据完整性和数据零丢失。数据单点写入到主机房数据库,然后实时同步到另外一个机房。
双机房的物理专线也必须是高可用的设计,两根以上。
压测主要几种在商品详情页和下单的步骤。
基准测试:主redis和rocketmq。
[roote192-168-65-190 srcl# ab-c 188-n 38888 http://192.168.65.28/seckill.html
ApacheBench(ab)工具对指定 URL 进行 HTTP 压力测试。
升级Redis集群
Redis的连接数会成为瓶颈。
一般通过中间件来减少redis连接数。比如,使用TwemProxy于redis之间建立单链接交互,并通过twemproxy实现分片逻辑。水平扩展twemproxy来增加连接数。
此时twemproxy实例众多,应用维护/配置困难。
LVS+HAProxy高可用架构,建立虚拟IP机制,当主twemproxy挂了,请求会到备twemproxy。
第一级redis 库存总记录
第二级redis 分片
秒杀进行时只扣减本地库存
通过预分配库存的方式,可以让每个应用都有一套独立的库存数据。各个应用处理库存的时候互不干扰。提高并发能力,并且支持横向扩展。各个应用库存扣减的速度不一致,一定程度防止羊毛党。
一定程度解决热点数据的问题。
如果有拼单的情况,两个商品分别位于两个redis主节点,一个用户来抢,库存是有的,但是从任一节点都无法抢购成功。
库存分配服务:秒杀开始时分配库存;单个秒杀服务库存不够时,动态分配库存;剩余库存回收。
库存不足或者库存剩余过多时,通知MQ。