part1
讲讲最近的项目,都有哪些模块?
司乘双端的登录模块,司机端需要人脸认证
预估订单数据模块
乘客下单模块
司机抢单模块
订单执行的业务逻辑,包括超时订单自动取消
订单支付模块
优惠券模块
你觉得哪个模块比较难?
司机抢单模块
方案1:数据库隔离级别,效率低下,不适合高并发需求
方案2:乐观锁,基于版本号,若并发冲突频繁,大量请求会因版本号不一致导致更新失败。
方案3:加锁解决,从从setnx一直说到redission
优惠券并发超卖怎么解决
思路为
- 乐观锁,增加版本号
- 分布式锁way1,引入Redission,同一时间只能有一个客户端拿到锁key,其它客户端陷入无限等待来尝试获取锁,缺点是多用户同时对一个商品下单的情况下,会基于分布式锁串行化处理,无法同时处理同一个商品的大量下单的请求。
- 分布式锁way2,在way1的基础上,把数据分成很多段,每个段是一个单独的锁,所以多个线程过来并发修改数据的时候,可以并发的修改不同段的数据。例如当前优惠劵有100库存,在redis存放5个库存key,用户下单时对用户id进行%5计算,落在哪个key上就去取哪个,但这个方案复杂度较高,且必须实现当某段锁的库存不足,要能够自动释放锁然后换下一个分段库存再次尝试加锁处理。
redis的key是什么,value是什么
- key,String,订单ID+当前线程ID
- value,Integer,1代表成功,0代表失败
part2
6.分布式锁是锁从哪儿到哪儿
想考察业务逻辑?
从抢单请求触发到订单状态更新的完整流程:
- 司机端发起抢单
- 获取分布式锁
- 执行业务逻辑:检查订单状态是否可以抢单,更新订单状态并关联司机信息
- 服务器返回抢单成功或失败
- finally代码块中调用unlock方法
7.分布式锁就能减少打过来的请求量了吗,去请求锁不还是会打到redis上?
想考察分布式锁的真正效果
并不是减少请求量,而是保证一个订单只能被一个司机接取。
redis能够减少打在数据库上面的请求,因为redis位于内存且数据结构支持高效处理crud操作,所有处理请求的速度远远快于数据库。
part3
8.异步存数据库线程池怎么设计的
想考察线程池是否有实际设计经验
CompletableFuture:CPU密集型,核心线程数=CPU核数+1,最大线程数=核心线程数2,队列容量=任务峰值平均处理时间,拒绝策略AbortPolicy+报警
目的:把串行执行的变为并行方式执行,提高代码执行速度
CompletableFuture提供操作方法,多一个参数,用来传递自定义线程池,如果不进行传递使用默认线程池
具体业务逻辑:
① 订单状态更新(MySQL)
② 费用计算(Redis缓存)
③ 分账记录写入(分库分表)
④ 消息通知推送(RabbitMQ)
9.单线程的线程池不还是串行执行吗
这就发现你小子的鸡爪了吧,使用线程池的目的就是把串行执行的变为并行方式执行,提高代码执行速度
10.如果我数据库连接池是10,响应时间1s,线程池数量应该设置为多少
用户的响应时间是1秒,说明可能有较多的IO等待,属于IO密集型任务。
线程池核心线程数与连接池大小匹配,均为10;最大线程数不超过10,否则多余的线程无法获取连接而一直等待。
理由
1.确保每个活跃线程都能分配到数据库连接,减少资源争抢
2.少量冗余应对突发流量
11.如果响应时间10ms呢,应该设置为多少
用户的响应时间是10ms,说明IO等待不长,属于CPU密集型任务。
核心线程数n+1(n为CPU核心数);最大线程数不应该超过10,否则多余的线程无法获取连接而一直等待。
12.线程池的数量和连接池数量有关系吗
这里才是10和11两个问题想考察的点:线程池参数和连接池数量、响应时间的关系
线程池的大小设置通常需要考虑任务类型。
数据库连接池的大小限制了同时能够执行的数据库操作数量。
线程池参数和连接池参数的关系:线程池的大小应该与连接池的大小协调,避免过多的线程竞争有限的连接资源,最大线程数不能超过连接池数量太多。
线程池参数和响应时间的关系:响应时间长,说明是IO密集型,需要更多线程来避免阻塞、CPU空闲;响应时间短,说明是CPU密集型任务,需要避免多线程导致上下文切换开销。
13.线程是什么
OS中,比进程更小的能独立运行的基本单位,就是线程。
换句话说:线程是进程当中的一条执行流程。
同一个进程内多个线程之间可以共享代码段、数据段、打开的文件等资源,
但每个线程各自都有一套独立的寄存器和栈,这样可以确保线程的控制流是相对独立的。
拓展:线程和进程的比较
1.进程是资源(包括内存、打开的文件等)分配的单位,线程是 CPU 调度的单位;
2.进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和栈;
3.线程同样具有就绪、阻塞、执行三种基本状态,同样具有状态之间的转换关系;
4.线程能减少并发执行的时间和空间开销;
part4
14.你知道事务吗,如果写入数据库失败了会怎么样,redis怎么处理
1.考察对数据库中的事务的理解:ACID
A:原子性,依赖undo log
I:隔离性,依赖MVCC
D:持久性,依赖redo log
C:一致性,依赖AID
2.考察数据库和缓存如何保证一致性
如果数据更新方案是更新数据库+更新缓存,且没有加分布式锁,那么需要直接删除redis里的数据。
如果数据更新方案是先更新数据库,再删除缓存,则影响不大。
15.失败了这时候再去redis看一人一单,原来的用户还能通过吗
因为数据库写入失败的同时,redis做了保证数据一致性的操作,所以用户依然可以发起申请。