Cache策略
- 定时过期策略
- 定时过期的好处是Cache节点的个数符合实际需求,不会造成资源滥用和服务器压力
- 定时过期适合访问量较大,实时性要求不高的情况
- 如果访问量小,定时过期会造成Cache命中率低,如果实时性要求高,过期间隔太小,Cache的意义就不大
- 适用情况 : 实时性低
- 全量刷新策略
- 全量刷新的好处是Cache命中率高,Cache实时性高
- 全量数据相比那些Cache key值设置不好的非全量Cache,可能反而更小
- 全量刷新的弊端是有可能造成服务器的压力,如果数据使用率低,就是对资源的滥用
- 全量刷新适合数据量小或者数据使用率高的应用
- 适用情况 : 数据量小
- 定时刷新策略
- 定时刷新的Cache节点个数和Cache大小成正比,需要综合考虑Cache命中率和数据量设定节点个数
- 节点数过大会造成Cache庞大,过小会造成命中率低
- 定时刷新的频率和实时性成正比
- 定时刷新对服务器资源有一定的滥用
- 需要开发人员了解具体服务的访问量数据量,制定合适的节点个数与刷新频率
- 使用情况 : 其他策略无法满足
- 定时过期+磁盘持久化策略
- 过期Cache存磁盘文件,系统下线所有cache持久化
- 分布式Cache机制,互相备份,错开重启
- 可以在一定条件下舍弃数据库
- Cache与访问量,数据量,定时性的关系
- 访问量大,数据量大,实时性高,可以使用复杂的定时刷新,还需要根据实际情况做优化
- 访问量小,数据量大,实时性高,可以使用定时刷新或不用Cache
- 数据量小,实时性高,可以使用全量刷新
- 访问量大,数据量大,实时性低,可以使用定时过期
- 访问量小,数据量大,实时性低,可以使用定时过期或者定时刷新
智能Cache策略
- UserPreference cache
- Subscription cache
- 分时间段的Cache,某些时间段的某些cache不过期,需要通过分析流量制定时间段
穿透优化
- 缓存穿透
- 发生大量不存在的key的访问,会加重对数据库层的压力
- 优化方法
- 缓存空对象key:null
- 空对象使用一个比较短的过期时间
- 用主动刷新策略应对key又被存入数据库的情况
- 实现成本低,占用内存不可控(由非法key和合法key的比例决定)
- 布隆过滤器拦截
- BloomFilter缓存所有存在的key,进行第一层过滤
- 会降低缓存的性能,实现成本高,占用内存可控
- 不使用传统的低性能的数据库
- 缓存空对象key:null
无底洞优化
- 无底洞现象
- 分布式存储随着节点数的增加以及key的随机分布,批量操作的网络传输次数怎加造成性能不增反减
- 优化方法
- 串行IO
- 先将批量查询的key所在的节点做mapping
- 属于相同节点的key合并一组,循环的所有组进行查询
- 并行IO
- 对串行IO作多线程处理
- hash tag
- 将相同hash tag的数据存储在同一个节点
- 一次批量查询只操作相同hash tag的key
- 容易产生数据分布不均衡
- 串行IO
缓存重建优化
- 问题
- 高并发的热点key+数据对象大重建缓慢
- 数据过期等情况造成大量线程来重建缓存,使得服务崩溃
- 优化方法
- 永不过期或者timeToIdle+主动更新
- 互斥锁:Redis可以用setnx实现
- 用户请求不重建缓存,用单独线程合并用户请求重建缓存
热点key集中化优化
其他等待解决疑问
- Server resource的个数大小如何定
- resourcePool的个数与大小
- Manage the CacheManager/Cahce/Entity
- load balance
- Thread Pools线程池
- key生成策略
CacheManager/Cache等实例数量与大小的考虑
- server resource & resource pool
- server resource可以多设置几个,比如每个1-5G这样,设置5个备用,每个可以给一个CacheManager使用
- 一个server resource里可以设置一个或多个resourcePool用于clusteredShared,一个或多个resourcePool用于clusteredDedicated,这个要根据实际需求
- 一旦clusted端建立了CacheManager,此CacheManager所占用的resourcePool就会被分配给这个CacheManager,所以resourcePool的大小应该更具项目实际情况设置,以免造成资源浪费
- 一个pool满了,就使用下一个,而不是增加它的大小,不然会影响所有使用者
- 也可以使得pool的大小动态获取,而不是hard code
- CacheManager
- 不同的业务模块创建不同的CacheManager实例,可以保持业务模块独立性
- 比如说可以单独清除一个CacheManager的所有Cache
- 多个CacheManager,配置代码在不同项目的复用会出现问题,如何解决?
- 用一个项目创建CacheManager,其他项目用缺省的方式连接CacheManager
- 单个CacheManager和多个CacheManager的性能问题?多个CacheManager真的必要么?
- 不同的业务模块创建不同的CacheManager实例,可以保持业务模块独立性
- Cache
- 不同的业务模块创建不同的Cache实例,可以保持业务模块独立性
- 不同的业务模块可以使用不同的key规则
- 可以独立的管理cache,比如删除等操作
- 可以更合理的定制Cache大小,提高cache命中率
- 可以更合理的定制Expiry
- 通过不同的Expiry策略创建不同的Cache实例
- 方便开发,无须每次都创建新的cache
- clusteredDedicated
- 必须指定cache的大小,不适合producer/consumer的方式,因为consumer必须知道producer设置的大小
- 能够更好的更具实际需要利用内存资源
- clusteredShared
- 不需要指定每个cache大小,方便producer/consumer主从互换
- Shared pool的大小必须足够大,而且基本不变,才能方便使用,这样便会造成内存的浪费
- Shared pool的变化会造成所有producer/consumer的配置要变
- clustered继承
- 解决了clusteredDedicated的问题
- 但是如果有两个以上的producer或者spring cache那样自己也是producer,还是必须统一配置
- 不同的业务模块创建不同的Cache实例,可以保持业务模块独立性
- 不方便的地方
- spring cache无须手动create cache,但是ehcache clustered必须手动,因为每个cache的配置更灵活
- withCache/createCache创建新cache,必须用autoCreate,在原来的CacheManager实例里创建新的cache并且连接
- 动态cache配置机制
- 多个Cache不同项目的配置
- 配置服务化[不推荐]
- 将配置信息封装成配置对象
- service提供获取配置对象服务
- 造成client项目依赖service或者cache项目
- 主从互换
- service与client都去判断cluster端是否存在cache,如果不存在,那么创建,否则继承
- 造成cache manage也无法继承
- 无法保证service与client创建cache时使用相同配置
- 适合clusteredShared
- 不适合clusteredDedicated的原因是client必须知道service端设置的大小
- 如果有两个以上的producer,也不适合clustered继承
- 完美主从互换[跨项目组的情况下建议使用]
- 方法1: service提供Cache配置服务,client获取配置创建cache,配置服务使得service必须有服务提供
- 方法2: common jar的形式保证创建cache时使用相同配置
- 方法3: service方提供client代码,client利用client代码创建cache
- 保证service与client创建cache时使用相同配置
- service必须知道自己的cache的配置,无法使用动态cache配置机制
- 需要动态cache配置的时候只适合clusteredShared,否则可以使用clusteredDedicated
- 这个工作需要额外开发,很麻烦啊,两害取其轻,还是使用clusteredShared+动态pool size吧,一点点浪费总比不可控也增加开发/维护难度好
- service主导[不推荐]
- client判断cluster端是否存在cache,如果不存在,那么创建,否则继承
- service判断cluster端配置是否符合自己要求,如何不符合,删除cache重新创建,否则直接创建
- 但是必须所有cache manager close()
- 适合clusteredDedicated
- 配置服务化[不推荐]