面试题答案
一键面试缓存策略选择
- 本地缓存
- 适用场景:适用于单机应用或对缓存数据一致性要求不高的场景。例如,在一个小型的单服务器Web应用中,应用内的某些配置信息很少变动,使用本地缓存可以减少对外部存储的访问,提高响应速度。
- 优点:访问速度极快,因为数据存储在应用进程内,无需网络开销。
- 缺点:数据共享困难,多实例环境下难以保证缓存一致性;缓存容量受限于应用服务器内存大小。
- 分布式缓存
- 适用场景:在微服务分布式系统中广泛适用,尤其是多实例、跨节点的应用场景。比如电商系统中,商品的基本信息、库存等数据,多个微服务可能会频繁读取,适合使用分布式缓存。
- 优点:可扩展性强,能通过增加节点来扩展缓存容量;支持多实例共享缓存数据,保证数据一致性。
- 缺点:存在网络开销,相比本地缓存,访问速度略慢;需要额外的维护和管理,如集群配置等。
实际业务场景缓存方案设计 - 以电商商品详情为例
- 缓存策略选择:选择分布式缓存,如Redis。电商系统通常是分布式架构,多个微服务(如商品展示微服务、订单微服务等)可能需要读取商品详情数据,分布式缓存能满足多实例共享数据的需求。
- 缓存数据结构设计:使用Redis的哈希(Hash)结构存储商品详情。例如,以商品ID作为Key,商品的各个属性(如名称、价格、描述等)作为Hash的Field和Value。
// 示例代码(Java + Jedis) Jedis jedis = new Jedis("localhost", 6379); String productId = "12345"; jedis.hset("product:" + productId, "name", "Sample Product"); jedis.hset("product:" + productId, "price", "19.99"); // 读取商品名称 String productName = jedis.hget("product:" + productId, "name");
- 缓存过期策略:为商品详情设置合理的过期时间,如24小时。可以在添加缓存时设置过期时间。
jedis.setex("product:" + productId, 24 * 60 * 60, productDetailsJson);
缓存更新和一致性问题解决
- 缓存更新策略
- 读写穿透:写操作时,先更新数据库,再更新缓存。读操作时,先查询缓存,若缓存不存在则查询数据库,并将结果写入缓存。
- 异步更新:写操作更新数据库后,通过消息队列异步更新缓存。这样可以避免写操作时直接更新缓存带来的性能问题,但要注意消息队列的可靠性。
- 缓存一致性问题解决
- 缓存版本号:为缓存数据设置版本号,每次数据更新时,版本号加1。读取数据时,不仅读取数据本身,还读取版本号,若发现版本号不一致则重新从数据库加载数据。
- 分布式锁:在更新缓存时,使用分布式锁(如Redis的SETNX命令实现简单的分布式锁),确保同一时间只有一个实例可以更新缓存,避免并发更新导致的数据不一致问题。但要注意锁的粒度和锁的释放,防止死锁。