一、对强一致要求比较高的,应采用实时同步方案,即查询缓存查询不到再从DB查询,保存到缓存;更新缓存时,先更新数据库,再将缓存的设置过期(建议不要去更新缓存内容,直接设置缓存过期)。

二、对于并发程度较高的,可采用异步队列的方式同步,可采用kafka等消息中间件处理消息生产和消费。

三、使用阿里的同步工具canal,canal实现方式是模拟mysql slave和master的同步机制,监控DB bitlog的日志更新来触发缓存的更新,此种方法可以解放程序员双手,减少工作量,但在使用时有些局限性。

四、采用UDF自定义函数的方式,面对mysql的API进行编程,利用触发器进行缓存同步,但UDF主要是c/c++语言实现,学习成本高。

@Cacheable(key = "caches[0].name + T(String).valueOf(#userId)",unless = "#result eq null")@CachePut(key = "caches[0].name + T(String).valueOf(#user.userId)")@CacheEvict(key = "caches[0].name + T(String).valueOf(#userId)" )@Caching(evict = {@CacheEvict(key = "caches[0].name + T(String).valueOf(#userId)" ),                  @CacheEvict(key = "caches[0].name + #result.name" )})@Cacheable:查询时使用,注意Long类型需转换为Sting类型,否则会抛异常@CachePut:更新时使用,使用此注解,一定会从DB上查询数据@CacheEvict:删除时使用;@Caching:组合用法      具体注解的使用可参考官网注意:注解方式虽然能使我们的代码简洁,但是注解方式有局限性:对key的获取,以及嵌套使用时注解无效,如下所示

1.先定义一个RedisCacheConfig类用于生成RedisTemplate和对CacheManager的管理

2.定义一个redisUtil类用于存取缓存值

3.实现类

异步实现通过kafka作为消息队列实现,异步只针对更新操作,查询无需异步,实现类如下

1.pom文件需依赖

2.生产者代码

3.消费者代码

4.application.yml配置

5.实现类

注意:kafka与zookeeper的配置在此不介绍

先要安装canal,配置canal的example文件等,配置暂不介绍

穿透:频繁查询一个不存在的数据,由于缓存不命中,每次都要查询持久层。从而失去缓存的意义。

解决办法: 持久层查询不到就缓存空结果,查询时先判断缓存中是否exists(key) ,如果有直接返回空,没有则查询后返回,

注意insert时需清除查询的key,否则即便DB中有值也查询不到(当然也可以设置空缓存的过期时间)

雪崩:缓存大量失效的时候,引发大量查询数据库。解决办法:①用锁/分布式锁或者队列串行访问

②缓存失效时间均匀分布

热点key:某个key访问非常频繁,当key失效的时候有打量线程来构建缓存,导致负载增加,系统崩溃。

解决办法:

①使用锁,单机用synchronized,lock等,分布式用分布式锁。

②缓存过期时间不设置,而是设置在key对应的value里。如果检测到存的时间超过过期时间则异步更新缓存。

③在value设置一个比过期时间t0小的过期时间值t1,当t1过期的时候,延长t1并做更新缓存操作。

4设置标签缓存,标签缓存设置过期时间,标签缓存过期后,需异步地更新实际缓存  具体参照userServiceImpl4的处理方式

一、查询redis缓存时,一般查询如果以非id方式查询,建议先由条件查询到id,再由id查询pojo

二、异步kafka在消费端接受信息后,该怎么识别处理那张表,调用哪个方法,此问题暂时还没解决

三、比较简单的redis缓存,推荐使用canal

参考文档