面试题答案
一键面试1. 缓存读写策略
- 读策略:
- 先读缓存,再读数据库:应用程序首先尝试从Redis缓存中读取数据。如果缓存命中,直接返回数据,大大提高响应速度。若缓存未命中,则从MySQL数据库读取数据,读取后将数据写入Redis缓存,以便后续相同请求能命中缓存。例如在一个商品详情查询场景,先从Redis查商品信息,没查到再去MySQL查并回写缓存。
- 多级缓存:可以设置多级缓存,如在应用服务器本地设置一级缓存(如Guava Cache),在分布式层面使用Redis作为二级缓存。本地缓存可以快速处理部分请求,减少对Redis的压力,提高整体响应速度。比如在一个高并发的新闻资讯应用中,本地缓存存放热门新闻,Redis作为更全面的缓存。
- 写策略:
- 先写数据库,再写缓存:确保数据的持久性,先将数据写入MySQL数据库,成功后再更新Redis缓存。这样可以避免在写操作过程中因缓存更新成功但数据库写入失败而导致的数据不一致问题。例如用户注册场景,先将用户信息写入MySQL,成功后再把用户相关缓存数据写入Redis。
- 异步更新缓存:对于一些对数据一致性要求不是特别高的场景,可以采用异步更新缓存的方式。在数据库写操作完成后,通过消息队列(如Kafka)异步发送消息通知更新Redis缓存,以减少写操作的响应时间。比如在电商的商品销量统计场景,销量数据写入数据库后,通过消息队列异步更新Redis中的销量缓存。
2. 缓存失效机制
- 设置合理的过期时间:根据业务需求为不同类型的数据设置不同的过期时间。对于变化频繁的数据,如实时股票价格,设置较短的过期时间;对于相对稳定的数据,如商品分类信息,设置较长的过期时间。在Redis中可以使用
EXPIRE
命令来设置过期时间。 - 主动更新:当数据库中的数据发生变化时,及时主动更新Redis缓存中的数据,而不是等待缓存过期。可以通过数据库的触发器或者应用程序在数据更新时同时更新缓存。例如在商品库存更新时,立即更新Redis中对应的库存缓存数据。
3. 缓存雪崩预防
- 随机过期时间:避免大量缓存同时过期,在设置缓存过期时间时,使用一个随机的时间范围,让缓存过期时间分散开来。例如原本设置缓存过期时间为1小时,可以改为在50分钟到70分钟之间随机设置过期时间,这样可以有效降低大量缓存同时过期的概率。
- 二级缓存兜底:设置二级缓存,如在一级Redis缓存失效时,通过二级缓存(如另一组Redis实例或者本地缓存)来提供数据,避免直接大量请求数据库。同时可以对二级缓存设置较长的过期时间或者不设置过期时间,作为一种兜底方案。
- 预热缓存:在系统启动或者业务高峰来临前,提前将热点数据加载到缓存中,避免业务高峰时因缓存未预热导致大量请求直接穿透到数据库。比如在电商大促活动前,提前将热门商品信息、促销规则等数据加载到Redis缓存。
4. 缓存穿透预防
- 布隆过滤器:在应用程序层使用布隆过滤器,当请求到来时,先通过布隆过滤器判断数据是否存在。如果布隆过滤器判断不存在,则直接返回,不会查询数据库和缓存,避免无效请求穿透到数据库。例如在查询用户信息场景中,用布隆过滤器先过滤掉不存在的用户ID请求。
- 空值缓存:当查询数据库发现数据不存在时,同样将这个空值结果缓存到Redis中,并设置一个较短的过期时间。这样后续相同的无效请求会直接命中缓存的空值,而不会穿透到数据库。比如查询一个不存在的商品ID,将空值缓存到Redis,短时间内再次查询该ID就直接从缓存返回空值。
5. 设计健壮架构确保系统稳定性和高性能
- 缓存集群:使用Redis集群,如Redis Cluster,通过分片的方式将数据分布在多个节点上,提高缓存的存储容量和读写性能,同时提供一定的容错能力。当某个节点出现故障时,集群可以自动进行故障转移,保证系统的可用性。
- 监控与报警:部署监控系统(如Prometheus + Grafana)对Redis和MySQL的各项指标进行实时监控,包括缓存命中率、数据库连接数、读写QPS等。设置合理的报警阈值,当指标异常时及时通知运维人员,以便快速定位和解决问题,保障系统的稳定性。
- 限流与降级:在应用层设置限流措施,如使用令牌桶算法或者漏桶算法对请求进行限流,防止过多请求涌入系统,保护后端数据库。同时设置降级策略,当系统压力过大时,对一些非核心业务进行降级处理,如返回默认数据或者提示信息,保证核心业务的正常运行。例如在电商抢购场景中,对商品评论等非核心功能进行限流和降级,确保商品购买等核心业务的性能。
- 数据备份与恢复:定期对MySQL数据库进行备份,对于Redis缓存数据,可以采用RDB(快照)和AOF(追加式日志)两种持久化方式,确保在系统出现故障时能够快速恢复数据,保障系统的稳定性。