# cache-study **Repository Path**: oschinachen/cache-study ## Basic Information - **Project Name**: cache-study - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-04-07 - **Last Updated**: 2022-04-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 书籍信息 # 深入理解分布式缓存:从原理到实践 pdf存放位置 我的网盘 > 电子书 > 深入分布式缓存 - 从原理到实践-完整版(带标签).pdf ## 第3章: 手写缓存, 参考 https://github.com/mfcliu/demo_cache,和本书第三章内容 ## 第4章 ehcache 1. java工程使用 https://www.baeldung.com/ehcache 2. spring boot集成ehcache3 https://springframework.guru/using-ehcache-3-in-spring-boot/ 3. https://howtodoinjava.com/spring-boot2/ehcache3-config-example/ ### 测试 http://localhost:8080/rest/calculate/areaOfCircle?radius=6 ### Ehcache的适用场景 1. 比较少的更新数据表的情况下 1. 做为hibernate缓存时,在进行修改表数据(save,update,delete等等)的时候,EhCache会自动把缓存中关于此表的所有缓存全部删除掉。能达到同步,但对于经常修改的表来说,就失去了缓存的意义 2. 对并发要求不是很严格的情况 1. 多台应用服务器中的缓存是不能进行实时同步的 3. 对一致性要求不高的情况下 1. Ehcache本地缓存,目前无法很好的解决不同服务器间缓存同步的问题,所以在一致性高的场合下,建议使用Redis、Memcached等集中式缓存 ### Ehcache 瓶颈点 1. 缓存漂移: 每个应用节点只管理自己的缓存,在更新某个节点的时候,不会影响到其它的节点,这样数据之间可能就不同步了 2. 数据库瓶颈: 1. 单例应用来说,缓存可以保护数据库的读风暴; 2. 但集群环境下每一个节点都要定期保持数据最新,节点越多,要维持这样的情况对数据的开销也越大 ### 实际工作中的应用 项目中使用集中式缓存流程 ![](images/4-5请求查询缓存过程.png) 存在的问题: 缓存系统因为某些原因宕机,造成服务无法访问,那么大量的请求将直接穿透数据库,对数据库造成巨大的压力 解决方案一: 使用Ehcache作为集群式缓存的二级本地缓存,这样当缓存系统宕机后,服务器应用的本地缓存还能继续抗住大量请求 使用Ehcache作为二级缓存 ,可能会出现本地缓存与缓存系统之间出现数据不一致的情况(因为实际生产环境中必定是多台服务器分别部署)。 > 怎么保证不同服务器间Ehcache本地缓存数据的同步问题? 方案一、定时轮询 每台应用服务器定时轮询Redis缓存,比较缓存数据的版本号与本地Ehcache缓存的版本号大小,如果本地Ehcache的缓存版本号小于Redis缓存的版本号,则可以获取最新的缓存,然后同步更新本地Ehcache缓存,否则跳过本次轮询 ![](images/4-6请求查询缓存过程.png) 缺点:每台服务器定时轮询的时间点可能不一样,那么不同服务器刷新缓存的时间点可能也不一样,这样就会产生数据不致的问题,对一致性要求不是很高的时候可以使用 方案二、主动通知 引入消息队列,使每台应用服务器的Ehcache同步侦听MQ消息,通过MQ推送或者拉取的方式,这样一定程度上可以达到同步更新数据 ![](images/4-7主动通知.png) 缺点: 因为不同服务器之间的网络速度的原因,所以也不能完全达到强一致性。(基于此原理使用Zookeeper等分布式协调通知组件也是如此) 如果要使用强一致性缓存,集中式缓存是最佳的选择 ### Guava Cache适用场景 1. 愿意消耗一些本地内存空间来提升速度 2. 更新锁定,当请求查询某一个key的时候,如果不存在则从源中读取,然后再回填到本地缓存中,这时如果并发量非常大,可能会有多个请求同时从源中读取数据,然后再回填到本地缓存,造成多次执行的情况。 1. Guava Cache可以使用CacheLoader的load方法加以控制,对同一个key,只让一个请求去源中读取数据,而其它请求阻塞等待结果。 ### Guava Cache的创建方式 1. CacheLoader 2. Callable callback ### 缓存数据删除 1. 被动删除 1. 基于数据大小的删除 2. 基于过期时间的删除 3. 基于引用的删除 2. 主动删除 1. 单独删除: Cache.invalidate(key) 将某个key的缓存值直接设置为无效 2. 批量删除: Cache.invalidateAll(keys) 将一批key的缓存直接设置为无效 3. 删除所有数据: Cache.invalidateAll() 删除所有缓存数据 ### 并发场景下的使用 Guava Cache可以在CacheLoader的load方法中加控制,对于**同一个key**,只让一个请求去源中读取数据,而其它请求阻塞等待结果,但是只让一个请求从源中读取数据返回后回填数据到缓存,而其它的请求等待,这样虽然对后端服务不造成压力,但其它所有的请求都被blocked了, 针对这种情况,Guava Cache提供了一个refreshAfterWrite定时刷新数据配置项,刷新时只有一个请求回源取数据,其它请求会阻塞一个固定的时间段,如果在这个时间段内没有获得新值直接返回旧值,这样请求被blocked情况就变的可控。 ![](images/4-9缓存定时刷新.png) ## 第五章 Memcached 集中式缓存 过时的技术,业务开发中没有用到,过时的技术,常做为反面教材出现,了解即可 ### Memcached 特征 1. 协议简单: 使用简单的基于文本协议或者二进制协议 2. 基于libevent的事件处理: 1. libevent将linux的epoll、bsd类操作系统的kqueue等事件处理功能封装成统一接口。 3. 内置内存存储方式:(不会持久化,重启消失) 4. 客户端分布式: 尽管“分布式”缓存服务器中,但服务器并没有分布式功能,各Memcached实例也不会互相通信以共享信息。它的分布式通过客户端实现的 ![](images/5-3Memcached基本结构.png) ### Memcached的一些问题 1. 无法备份,重启无法恢复 2. 无法查询 3. 没有提供内置的安全机制 4. 单点故障failover (可以通过主从模式解决) ![](images/5-4主从缓存结构.png) ## 第七章 Redis 探秘 ![](images/7-1Redis数据结构.png) ## 社交场景架构进行: 从数据库到缓存 它山之石 典型社交类系统的特征: 1. 大数据量 2. 高访问量 3. 非均匀性