面试题答案
一键面试综合内存缓存与持久化缓存方案
- 内存缓存:选用Redis作为内存缓存,因其具备高性能读写能力,适合处理高并发场景。将高频访问的交易数据(如近期交易记录、用户账户余额等)存储在Redis中。例如,采用哈希结构存储用户账户信息,以用户ID为键,账户详细信息为哈希值。
- 持久化缓存:采用磁盘型数据库(如MySQL)作为持久化缓存,用于存储所有交易数据,保证数据的持久性。在MySQL中设计合理的表结构,如交易记录表包含交易ID、交易时间、交易金额、交易双方等字段。
缓存穿透处理
- 布隆过滤器:在缓存之前,先使用布隆过滤器。当查询请求到来时,先通过布隆过滤器判断数据是否存在。如果布隆过滤器判断不存在,则直接返回,不再查询缓存和数据库,避免大量无效请求穿透到数据库。例如,在系统启动时,将数据库中所有的交易ID加载到布隆过滤器中。
- 空值缓存:当查询数据库后发现数据不存在,将空值也缓存起来,并设置较短的过期时间。下次同样的请求过来时,直接从缓存中获取空值,而不查询数据库。
缓存雪崩处理
- 设置不同过期时间:避免大量缓存数据在同一时间过期。对于内存缓存中的数据,设置随机的过期时间,在一定时间范围内(如1 - 2小时)随机取值作为过期时间。
- 二级缓存:构建二级缓存结构,如一级缓存使用Redis,二级缓存使用本地缓存(如Guava Cache)。当一级缓存失效时,先从二级缓存获取数据,若二级缓存也没有,再查询数据库,并将数据同时更新到一级和二级缓存中。
- 缓存预热:系统启动时,预先将部分热点数据加载到缓存中,避免系统刚启动时大量请求同时查询数据库。
高并发下的数据一致性问题处理
- 读写锁:在更新数据时,使用读写锁。写操作获取写锁,此时其他读写操作都被阻塞,保证写操作的原子性。读操作获取读锁,多个读操作可以同时进行,但不能与写操作同时进行。例如,在更新用户账户余额时,先获取写锁,更新完成后释放锁。
- 事务机制:在数据库层面,利用事务保证数据的一致性。对于涉及多个操作的交易,如转账操作,将扣除一方账户余额和增加另一方账户余额的操作放在一个事务中。如果其中任何一个操作失败,整个事务回滚。
- 缓存更新策略:采用“先更新数据库,再删除缓存”的策略。在更新数据库成功后,立即删除对应的缓存数据。当下次请求到来时,会重新从数据库加载数据并更新到缓存中。同时,为了防止删除缓存失败,可以引入消息队列,将删除缓存的操作发送到消息队列中,确保最终一致性。