你们系统的秒杀是如何设计的(面试题)
总结:上分布式架构、上各种缓存技术、搞一搞负载均衡之类的。提高并发的处理能力。防止超卖等问题,就需要使用分布式锁机制。事先将库存同步到redis里面,直接规避了数据库的操作。咱们可以在扣除库存成功之后,很多后续处理都可以基于mq这种异步的形式来完成。这个时候rocketmq的消息确认机制就是蛮合适的。为了公平性,需要对用户的请求。做一些防刷措施。做一些验证码或者做一些ip的限制等等来规避刷单的这种行为。同时,秒杀活动中可能会出现各种异常,比如:网络延迟、系统故障等等,这种不可控的一种情况,需要在系统中进行一些异常处理,比如说我搞搞重试、做做降级等保证系统可以稳定的运行。再有就是安全方面了,可以防止一些恶意的攻击、数据泄露,可以上个https,对请求传递过来的数据做一个加密的处理等。再有就是一个前端的优化,比方说做一些页面的静态化、搞搞cdn加速来提高系统的访问速度。差不多就这些,不过具体的设计方案还是要根据具体的业务场景、系统规模进行一些细微的调整。秒杀这个东西并没有什么固定的答案。
秒杀业务场景如何去设计?
需求:12306抢票。大明星的演唱会。300万人 -> 1万张票。0.5s就空了。
难点在哪里?
1、限流:nginx上做限制(nginx限流主要能够保证我们的网关不被冲垮)、服务层做限制(redis做计数器、使用gateway网关提供的限流的方法)。
2.抗住高并发的TPS,瓶颈就在MySQL定义一张订单表、座位表(1W条数据)
3.安全机制(锁机制确保不能重复抢票)
秒杀的业务流程如何设计
1)管理后台,提前维护秒杀活动-》设计到一些表,进行CURD。
2)运用redis把秒杀的活动上线:数据写入到redis(活动信息(string)+商品信息(hash)+库存信息(string))
rokcetmq不是一次消费一条消息,是一次消费多条消息。说白了就是消费者消费到消息之后,会先进行同类商品的一个汇总,而不是一条一条的更新库存表,减少库存。是分批次更新的,这样效率也就提高了,同时也减轻了数据库的压力。
面试官:如何不重复消费消息,如何保证消息的不丢失?
我们可以借助redis来做,将我们需要校验的信息放到redis里面,再次消费的时候看看redis里面有没有就可以了。
消息不丢失:我们在往mq中发送消息的时候要采用这种可靠的消息发送机制,比如,我们采用同步刷盘的机制来保证生产者发送消息到broker中,当然,rocketmq底层他也有这种重试机制,比方说我第一次没有发送成功会默认进行重试。也就是说,我将消息推送给rocketmq的时候一定要收到rocketmq的ack确认。
当然rocketmq一般情况下是集群部署,我们可以采用同步复制的机制来保证消息最起码同步到一个从节点上。
当我们消费者消费rocketmq集群中的消息的时候,也要先消费,消费成功后在手动提交ack确认。
千万级别的并发,那都是QQ、微信才会有的规模,也就是说在给面试官吹的时候,不要太过了。
redis单机QPS能够达到10万。就说自己的秒杀项目qps是QPS万左右。
秒杀系统是我们电商系统中常见的一种业务模式,用于吸引用户,刺激留存及消费所做的一种活动。秒杀系统的例子:整点秒杀、商品秒杀秒杀系统的特点:
1、瞬时流量极大,过了秒杀时间点流量结束。所以不能用机器堆qps。
2、秒杀商品库存极少,例如1w个用户去抢10瓶茅台。
3、秒杀时间点未到的时候,刷新量极大,静态资源被访问剧增
如果秒杀系统采用堆机器的方式来增加qps那么就太浪费资源了,成本太高。
秒杀系统一般流程:
1、运营策划秒杀活动,选品,在秒杀中台建立秒杀活动,需要距秒杀开始提前一段时间。同时将秒杀数据,库存等信息写入缓存
2、业务方研发根据实际情况来看自身机器是否可以扛得住
3、用户进行秒杀。
针对于以上秒杀系统的特点,我们映射到技术层面上,就有如下一些要考虑的点。
1、高并发,快响应:秒杀一般是C端产品吸引用户的点,需要考虑用户体验。并发量极高,对服务有要求,要抗住并发
2、防止超卖:商品数量有限,不能因为大用户量高并发扣减库存,导致商品超卖,库存变负。
3、防刷子:防止机器人,恶意刷子,去抢占订单,导致正常用户抢不到商品。
4、页面资源访问多:需要考虑静态化,CDN,静态资源缓存及压缩。
5、秒杀按钮:通过前端的按钮进行限制一些请求打到后端。按钮置灰。
6、秒杀真链接隐藏:防止后台交互链接,非秒杀期间漏出
7、异步处理订单后续:秒杀成功后,订单必理交于异步服务
8、订单失败补偿:遇到订单后续处理失败,必须补偿
9、服务降级:遇到紧急情况,可以快速必理
针对于请求和用户的高并发。我们需要在上线之前,首先要做好压测,知道服务qps瓶颈点。针对我们的日常业务秒杀的预估进行服务器的准备。测量tps,寻找薄弱点进行代码优化,服务支撑优化,
一般采用redis+热数据+mg。前端辅以静态化,cdn加速。带宽扩展。集群负载均衡。
==========================================================
双十一秒杀实现
我们可以基于MySQL的行锁来实现,即使并发问题也没事儿。
数据库最多每秒能抗几百个并发就很好了,redis每秒能抗几万个并发。
前端会有一个定时任务,会每隔个几秒中去查询后端的数据库。看看有没有生成订单。
redis单节点抗读并发大概是10万/s,写并发是2万/s。读写混合并发大概是4-5万/s。
redis缓存数据倾斜的问题:这个问题的意思就是比方说我要秒杀10个商品,假设我redis有5个主节点,按理说一个节点应该分配两个商品的信息,但是现在经过redis的hash分片算法运算之后,都分配到了redis集群中的一个节点上面了。这个时候,10万个并发都来操作redis集群中的某一个节点的话,那么就会将我们这个节点打废了。
针对以上这种问题,我们可以采用限流的算法。但是限流是兜底方案了,我们能在业务层面上进行解决就一定先要在业务层面上进行解决。
我们可以使用redistag这种方式来进行解决,{redis1}product:stock:productid 这个时候,我们redis在对key进行hash运算的时候,就不用我们原来的key了,就直接使用{}里面的key进行hash了,通过这种方式,我们就能够很好的让我们商品信息均匀的落在redis cluster集群中的每个节点上了。
关于热点key的问题:
比方说我有一个抢茅台的活动,这个时候我们可以把茅台的信息在redis cluster集群中每个节点都维护一份数据。
然后在代码中我们要进行判断,你是不是热点key,如果是热点key的话,那么我就轮询的去请求redis的每个节点进行库存的扣减。
rocketmq在哪些环节会出现丢消息。
怎样确保消息不丢失,做法,我们可以加一张消息日志表,客户端在往消息中间件中发送消息之前,先将消息发送到消息日志表中。(消息日志表中有标识状态的一列,待处理/已处理)。消息处理完了之后将消息状态改成已处理。因为是顺序写,所以性能会非常快,但是你改库存,那就慢多了。
消息积压的时候,增加消费者的实例数是没有用的。这个时候应该怎么办呢?
我们可以使用在消费消息的时候进行判断,看看当前消息是否超过了1分钟,如果超过1分钟的话,那么我们可以将消息消费到redis中,客户端进行查询的时候,可以先去缓存中进行查询,如果缓存中没有查询到,再查询数据库,当然,需要我们一开始在代码中就要这样写。当然其实我们还是要写一个定时任务,将redis中的数据同步到我们数据库中,生成真实的订单的。最后再讲redis中的数据delete掉。
redis集群崩溃了,这个时候我们可以将redis减库存的那段代码加上try catch ,如果报错的话,我们可以隔一个两三秒重试几次,如果还是不行的话,我们可以使用本地缓存比方说rockDB,搞一个定时任务,去扫这个本地缓存,然后再将其放入到redis缓存中,当然要求我们的redis集群挂掉之后能够快速恢复。
redis主从节点同步数据采用的是异步的方式。
redis主从切换导致的超卖问题,一般是小概率事件,一般情况下我们是不解决的。因为秒杀的时候,厂家都是会多备一些库存的。
如果面试官非要钻牛角尖,这个时候,我们可以回答将redis主从复制的方式由异步复制改成同步复制。这个需要修改redis的c语言源码了。还有一种方法就是不要使用redis从节点了,也就是说搭建redis集群的时候不要加从节点了。还有一种方式就是用数据库进行判断了,减到0的时候,再减的话,就报错就好了。