无题

本文仅仅用于学习,查看了星球内四月份到今天为止大家遇到的面试题,总结了自己认为有价值的。
T1:
抽奖前需要先创建一个抽奖订单(创建抽奖单可能扣减账户次数额度),然后真正执行抽奖。「抽奖订单」的设计,相对于「直接扣减账户中的抽奖次数余额」,能够解决什么实际问题?
xfg回答:
1.抽奖单设计是一种行为记录的流水,有了抽奖单可以做幂等重试,如果后序流程失败了,抽奖单不会被消费,用户可以重新使用抽奖单抽奖。如果是系统随机发奖,还可以系统基于失败的抽奖单自己做重试补偿。这种思想来自于商城下单,有了订单之后才有订单的支付。
2.订单的存在可以让流程有了暂停和继续的操作。如果只是直接扣减账户抽奖次数余额,就只会得到执行结果,那么都是即时状态,过后无法追查校准。

T2:为什么不直接使用内存作为缓存而引入Redis
xfg回答:

    在营销复杂计算场景中,为了提高性能确实会用本地内存 + redis 缓存的方案。但本地内存会有一个问题,就是分布式架构下,在初始和变更数据,需要所有环境保持统一数据,并需要配有动态配置中心来通知更新。需要一定的维护成本。

    一般做这类的系统,以及配置类的,是会存redis一份,之后在拉取到本地内存一份。本地内存与 redis 中数据进行版本校验和定期更新。这个是实际场景方案,所有面试官会追着你这样问。下次可以讲两套方案是一起使用的【不过最好最好案例,流程先跑通,避免解释不清。】

    对于2方案,结合 redis 也有发布订阅能力,可以发完成本地内存更新,这个在《动态线程池组件》中使用了。

T3:
多个用户同时进行权重抽奖时,如何保证这些用户都抽到奖?
xfg回答:凡是能达到权重范围的用户,是运营提前做了预算库存的,所以一定是会给发奖的。

T4:
在抽奖中后环节时,若此时对库存进行了修改,如何去更新缓存和数据库的数据
xfg回答:
一般来说,不太允许更新已经发布的活动的库存,容易造成客诉。所有的运营手段,库存的设置,都是提前申请审批的,不是随意加的。如果要加,可以先更新数据库,更新成功后,添加缓存库存即可。

T5:
对sku下单时,扣减sku库存是先扣redis缓存 然后发MQ消息,通过一个定时任务缓慢更新数据库保证数据最终一致性。如果redis缓存扣减成功之后,redis就挂了,后面的MQ消息也没有发出去,那么重启redis之后 又从DB中重新导入数据,这样就导致了数据不一致,可能出现超卖的情况 怎么解决?
答:使用setnx做了兜底操作,就算获取了旧的库存数据,但之前的锁都在redis里,可以防止超卖。另外xfg补充:一般真挂了,活动就加挡板了,不会对外了。等恢复了,要校准数据,之后才能对外的。另外 redis 挂了,集群都挂了,是重大事故,各个服务也都不可用了。这个时候不会对研发下手,要干的是redis运维。

T6:
dbRouter组件大致实现流程
1、先配置抽奖系统的yml文件,配置多个数据源(就是多个数据库:db01, db02)
2、自定义一个注解,用于AOP切面拦截,拦截后切换数据源,看该分配到哪个库哪个表
3、然后在组件里面实现的切面拦截:数据库路由计算、扰动函数加强散列、计算库表索引、设置到 ThreadLocal 传递数据源,
4、切换数据源
自定义注解实现:db-router 中定义个 @interface 类型就可以。

T7:
如何监控如activityid 等于100301,100302 每分钟接口访问量?
答:手动记录统计,使用本地缓存或者map,把activityId_100301作为Key,在接口方法中让每次访问添加相应的次数。

T8:
关于奖品库存扣减,假设库存是三个,若给一个用户发了5个奖品,如何处理?
这一块结和xfg回答和我自己回看代码,大概是这样:库存扣减成功的准许发放相应的奖品,库存扣减失败的奖品(会有两个),走兜底奖励。每一个库存的扣减都有粒度很细的分布式锁兜底(setnx,decr操作)
ps:对应代码可以查看startegy领域的规则树-库存规则校验结点(RuleStockLogicTreeNode)

T9:
项目的安全性如何保证?
xfg回答:
1.鉴权登录「jwt、spring security」,大营销是一个微服务,登录是其他系统。比如 openai 是有登录的,通过微信公众号鉴权。可以参考这个;网站提示用公众号扫码登录,他们是怎么实现的? | 小傅哥 bugstack 虫洞栈
\2. 数据加密,https、敏感数据 aes 加密【如,openai 的 apikey 可以加密】
\3. 防止SQL 注入、入参数据校验 @Valid
\4. cors 跨域配置,http请求安全头设置,X-Content-Type-Options、X-Frame-Options、X-XSS-Protection
\5. 系统监控;普罗米修斯、在星球的基础教程里有,openai 项目也对接了监控,后续大营销也会对接。还有咱们星球新开的项目,透视业务流程监控。
\6. 依赖漏洞扫描,需要一些工具,公司里是提交代码会被扫描。也可以自己搜索工具扫描 owasp dependency-check
\7. 代码审计,idea 插件类的,检查代码问题,在星球 idea plugin 教程里有

T10:
Rabbit MQ 消息,有 task 来保证消息被成功发送。若mq消息消费失败,会发生什么情况?
答:消费失败会有异常抛出,在消费者端代码已经做了try-catch处理,之后mq会重新消费。
验证成功:在消费者端代码人为制造异常,会不断尝试消费
image.pngimg

T11:
关于抽奖系统是不是高并发,与传统秒杀系统的区别与联系?
xfg回答:

    春晚红包正是抽奖的形式,拼多多一进页面就有各种【转转转】来获得一个券,支付完成又一个转转转。直接领券远没有抽奖来的刺激,即使是发券,也是用抽奖方式更多。 (故抽奖系统也是高并发场景)

    每秒的请求量如果超过1000tps,打到库上资源竞争,都会出现大量的数据库连接等待。一般一个应用分配的数据库连接池也就那么20来个。如果都打到库上,都能把库打挂。

T12:
关于Redis挂掉之后的措施?
答:
1、代码中要做好redis的降级处理,比如说当前在操作Redis时候,先手动的进行try catch,如果redis挂掉之后,首先不会影响主业务流程,我们可以执行本地数据库查询啊,或者执行ehcache这种缓存啊,我觉得应该都是OK的。(做好异常处理,本地缓存预案)
2、其次挂掉之后,可以触发个定时任务和MQ去做检测之类的。
3、redis 就要多套进行备份,可以切换使用。

T13:
用redis 的set nx实现分布锁,为什么用set nx可以实现分布锁锁,set nx不是单节点的吗?
1.setnx是原子操作,确保只有一个客户端能成功获取锁。其余客户端全部失败。(什么是原子性?Redis的原子性操作指的是在执行过程中不会被其他操作打断,即操作要么完全执行成功,要么完全不执行,从而保证数据的一致性和可靠性。)
2.超时机制,set nx 可以设置额外参数 表示超时时间,保证出现异常情况下 锁依然能够释放。
3.避免竞态条件 多个客户端同时尝试获取锁时,确保只有一个客户端能够成功获取锁,保证了锁的互斥性
4.redis是分布式缓存,对分布式服务都可见

T14:
系统的数据怎么判定是否该放入缓存中(redis),判定的具体衡量标准是什么?
xfg回答:
\1. 有几个指标可以看;访问评率、数据大小、更新频次生命周期、热点数据、命中率、生成数据成本(像是大营销预热抽奖概率数据)。
\2. 实际业务中综合考量,能提高系统的承载量,吞吐量的都可以添加缓存来处理。以及缓存+本地缓存。

T15:
关于redis,延迟队列与数据库的数据一致性问题:
redis已经扣减但没有存入延迟队列就宕机了怎么办?
定时任务读取任务但还未扣减数据库,数据库宕机了怎么办?

答:本抽奖系统是用来应对高并发场景的,本身并不保证数据的强一致性问题,而是保证数据的最终一致性。在本系统中数据最终一致性方案的体现:发奖扣减奖品库存时使用延迟队列+定时任务的方式趋势更新奖品库存,扣减sku库存时使用延迟队列+定时任务趋势更新奖品库存,并在库存扣减为0时发放mq消息,提升了性能。如果redis宕机了、那企业中几乎就是所有服务也就停了,研发的职责是保证组件可用的前提下,系统可用。如果宕机了,也只能降级服务。组件恢复后,校验数据,在重新上线活动。

T16:
如果用户签到两次,如何防止获得多次抽奖充值?
根据当前日期作为业务字段,拼接上用户名,返利类型,构成唯一ID,保证用户一天只能签到一次。(mysql底层是如何实现唯一键约束的?通过在需要唯一性约束的列上创建唯一索引来实现的。唯一索引使用B+树等数据结构,它可以快速检索并保证索引列的唯一性。)

T17:
关于库存扣减那块
比如说某个奖品的库存是100,先通过decr扣减库存 然后按照库存锁的思路,假设已经消费了四个库存 也就是99,98,97,96这四个库存上了锁,然后呢假设后台运营增加了60个库存,库存从100变成到了160,然后后续流程从160正常扣减 这时候有个问题,如果用户又连续消费到了99,98,97,96这几个库存,由于这几个库存都上了锁,所以用户连续几次都消费失败,抛出异常了。这种设计给用户造成的体验是不是不太好?
xfg回答:
1.动态添加库存的场景,不能和0做比较了,要和总量去比。之后锁的方式是 incr 往上添加值,96、97、98、99,之后再有新的库存,继续加之后和总量比。
2.对库存锁的key添加过期时间,设置为活动过期后往后添加一天。

T18:
QPS与TPS的理解?
QPS(每秒查询数),TPS(每秒事务数)。
QPS 是用来衡量一个系统每秒能处理多少查询请求的指标。它通常用于评估如搜索引擎、数据库系统或Web服务器等高并发场景的性能。
TPS 是用来衡量一个系统每秒能处理多少事务的指标。事务一般是指一组操作的组合,它们要么全部成功,要么全部回滚。TPS更侧重于电商网站、银行等需要事务完整性的应用场景。

T19:
incr防止超卖和decr防止超卖代码上如何实现,在业务上来讲有什么差别
incr防止超卖的实现: - 从0开始累加,直到达到缓存中记录的库存个数,就不再卖出商品。 - 从库存开始累加-1,和decr差不多
使用场景:动态添加库存
decr防止超卖的实现: - 扣减库存,当库存扣减为-1,则说明库存不足
使用场景:库存活动开始时就已固定好,后续很难或者无法再改变