螺竹编程
发布于 2024-05-19 / 17 阅读
0

Java面试题/数据库与缓存:缓存面试题

缓存基础

什么是缓存?为何要用缓存?

缓存是一种存储数据的临时存储区域,用于存储经常访问的数据,以便提高访问速度和性能。使用缓存可以减少对底层数据源(如数据库)的访问次数,从而提高系统的响应时间和吞吐量。

缓存有哪些常见的类型?

常见的缓存类型包括内存缓存、分布式缓存和浏览器缓存。内存缓存用于在应用程序内部存储数据,以减少对其他资源的访问。分布式缓存用于在分布式系统中共享数据,并提供高可用性和可扩展性。浏览器缓存用于存储网页资源,以便重复访问时不需要再次下载。

缓存可以在哪些层次上实现?

缓存可以在多个层次上实现,包括以下几个层次:

  1. 应用程序级缓存:在应用程序内部实现的缓存,用于存储应用程序特定的数据,如结果集、计算结果等。

  2. 数据库级缓存:位于数据库系统内部的缓存,用于存储数据库查询的结果集,以避免频繁的磁盘访问。

  3. 分布式缓存:位于应用程序和数据库之间的缓存层,用于缓存频繁访问的数据,以减少对数据库的负载。

  4. CDN(内容分发网络)缓存:位于网络边缘的缓存节点,用于存储静态资源(如图片、CSS、JavaScript文件等),以提供更快的访问速度。

缓存相关算法有哪些?

  1. 最近最少使用(Least Recently Used, LRU)算法:LRU算法基于最近使用的原理,将最近最少使用的数据从缓存中淘汰。每当访问缓存中的数据时,该数据的访问记录被更新,保持最近使用的数据在缓存中保留。

  2. 先进先出(First-In-First-Out, FIFO)算法:FIFO算法按照数据进入缓存的顺序进行淘汰。当缓存达到最大容量时,最早进入缓存的数据会被淘汰。

  3. 最不经常使用(Least Frequently Used, LFU)算法:LFU算法基于数据的访问频率,淘汰最不经常使用的数据。每当访问缓存中的数据时,该数据的访问计数器增加。当缓存达到最大容量时,访问计数最低的数据会被淘汰。

  4. 最常使用(Most Frequently Used, MFU)算法:MFU算法与LFU算法相反,它淘汰访问频率最高的数据。每当访问缓存中的数据时,该数据的访问计数器增加。当缓存达到最大容量时,访问计数最高的数据会被淘汰。

  5. 随机替换(Random Replacement)算法:随机替换算法是一种简单的缓存替换策略,随机选择要淘汰的数据。它不考虑数据的访问模式或频率,而是随机选择一个数据进行淘汰。

常见的缓存工具与框架有哪些?

  • 本地缓存:Guava LocalCache、Ehcache、Caffeine。

  • 分布式缓存:Redis、Memcached、Tair。

使用缓存带来的问题

使用缓存之后带来了哪些问题?

  • 缓存何时写入?

  • 缓存如何失效?

  • 缓存和数据库的一致性保证?

  • 如何避免缓存穿透?

  • 如何避免缓存击穿?

  • 如何避免缓存雪崩?

如何解决缓存穿透的问题?

缓存穿透是指对于一个不存在于缓存中的数据,每次请求都会穿透缓存层,直接访问底层数据源。为了解决缓存穿透问题,可以采取以下措施:

  • 使用布隆过滤器(Bloom Filter)等技术,在查询缓存前进行快速过滤,判断数据是否存在;

  • 在底层数据源中存储一个空值标记,表示该数据不存在,避免对缓存的重复穿透;

  • 设置短期的缓存过期时间,以避免大量请求同时穿透缓存。

如何解决缓存击穿的问题?

缓存击穿是指针对一个热点数据,缓存失效后,大量请求同时涌入底层数据源,导致数据源压力过大。为了解决缓存击穿问题,可以采取以下措施:

  • 使用互斥锁或分布式锁,使得只有一个请求能够重新生成缓存,其他请求等待缓存生成完成;

  • 使用热点数据预加载,提前生成热点数据的缓存,避免缓存失效时的高并发请求;

  • 设置较短的缓存过期时间,并采用异步更新缓存的方式,减少缓存失效的影响。

如何进行缓存更新和缓存失效处理?

缓存更新是指在底层数据发生变化时,及时更新缓存中的数据。常见的缓存更新策略有:

  • 主动更新:在数据变更时,主动更新缓存中的数据。

  • 延迟更新:当数据发生变更时,并不立即更新缓存,而是等待一段时间后更新,以减少对底层数据源的压力。

  • 异步更新:在数据变更时,通过异步任务或消息队列等机制,异步地更新缓存,减少对请求响应时间的影响。

缓存失效处理可以通过以下方式实现:

  • 基于时间的过期策略:设置缓存的过期时间,让缓存在一定时间后自动失效。

  • 基于事件的失效策略:监听底层数据的变化事件,当数据发生变化时,通知缓存进行失效处理。

  • 手动失效:在特定的业务操作中,手动标记缓存为失效状态,以触发缓存的刷新或重新加载。

如何解决缓存雪崩的问题?

缓存雪崩是指在某个时间点,缓存中的大量数据同时失效或过期,导致大量的请求直接访问后端系统,造成后端系统负载剧增,甚至引起系统崩溃。

解决缓存雪崩问题通常采用以下策略:

  1. 合理设置缓存过期时间:通过合理设置缓存数据的过期时间,避免大量缓存同时失效。可以采用随机的方式设置过期时间,分散缓存的失效时间点,减少雪崩的风险。

  2. 引入缓存数据的自动刷新机制:在缓存数据过期之前,提前异步刷新缓存数据。当缓存数据过期时,仍然可以提供旧数据,同时异步更新新数据到缓存中,确保缓存数据的及时有效性。

  3. 数据预热:在系统低峰期,提前加载缓存中的热点数据,避免在高峰期由于大量请求直接访问后端系统而引起的缓存雪崩。通过定时或手动方式,提前将热门数据加载到缓存中,确保缓存的有效性。

如何处理缓存数据的一致性问题?

处理缓存数据一致性问题的常见方法包括:

  1. 主动刷新(Cache Refresh):定期或在数据发生变化时,立即刷新缓存中的数据,确保缓存数据与源数据保持一致。

  2. 延迟刷新(Lazy Refresh):当缓存数据被请求时,检查源数据是否发生变化,如果发生变化,则刷新缓存数据。

  3. 失效标记(Invalidation):在源数据发生变化时,通过标记缓存数据为无效状态,下一次请求时重新获取最新数据并更新缓存。

  4. 双写策略(Write-through):每次写操作都更新缓存和源数据,确保数据的一致性。

其他

缓存如何存储POJO对象

  • 将POJO对象序列化后进行存储。

  • 使用哈希数据结构进行存储。