前言

前阵子加入业务部门的技术计划评审,故事的背景是这样:业务部门上线一个专为公司高管应用的零碎。这个零碎技术架构形如下图

按理来说这个零碎因为受众很小,能够说基本上没并发,业务也没很简单,但就是这么一个零碎,间断2次呈现数据库宕机,而导致系统无奈失常运行。因为这几次事变,业务部门负责人组织这次技术计划评审,主题如何防止再次出现相似这种故障?

过后有个比拟资深的技术,他提出当数据库呈现宕机时,能够切换到redis,redis外面缓存热点数据,另外一个技术说他同意这个计划,但他提出不须要用到redis,间接用本地缓存即可。因为tomcat是集群部署,就等于本地缓存也具备了集群能力。而如果切换成redis,redis也可能会挂景象。

而后那个说用redis的技术又说,用本地缓存,如果数据变更,其余集群的本地缓存如何感知数据曾经发生变化,他感觉还是用redis靠谱,首先redis容量必定是比本地缓存高,而且redis也能够部署集群,可用性能够失去保障,利用redis集中存储,当数据产生变更,其余集群也能够感知到。

在他们争论不休的状况下,有人提出不然就同时应用,当数据库挂了,切换到redis,redis挂了,应用本地缓存。这个计划失去不少人的批准,包含这两个争论不休的技术。但应用这种计划,就得思考多级缓存数据如何同步。

铺垫了那么多,才刚要说明天的主题,多级缓存数据如何进行同步

多级缓存数据同步

1、计划一:应用MQ或者canal进行同步

计划如下图


如果是应用MQ来同步,实现计划大抵如下,数据产生变更,业务零碎发送变更数据到MQ,其余零碎从MQ生产。

如果是应用canal,实现计划大抵如下,数据产生变更,canal会接到到变更的binlog,业务零碎编写canal tcp客户端,和canal进行交互获取变更数据

2、计划二:利用redis6提供的客户端缓存机制

计划如下图


redis6客户端缓存实现机制原理,官网有具体文档介绍,感兴趣大家能够查看如下链接
https://redis.io/docs/manual/client-side-caching/

这边就讲下如何应用

如何应用redis6客户端缓存

前置条件:redis服务端版本必须是>=6。lettuce版本>=6 目前java的redis客户端找了一圈,貌似只有lettuce 6反对,其余客户端预计前期会反对

1、我的项目中pom引入lettuce GAV
  <dependency>            <groupId>io.lettuce</groupId>            <artifactId>lettuce-core</artifactId>            <version>6.1.8.RELEASE</version>        </dependency>
2、利用lettuce6提供的ClientSideCaching进行实现
    /**     * 客户端缓存同步     *     */    public String getClientCacheValue(Map<String,String> clientCache,String key){        StatefulRedisConnection<String, String> connect = redisClient.connect();      //  Map<String,String> clientCache = new ConcurrentHashMap<>();        CacheFrontend<String,String> frontend = ClientSideCaching.enable(CacheAccessor.forMap(clientCache),                connect, TrackingArgs.Builder.enabled().noloop());        return frontend.get(key);    }
3、测试
    @Override    public void run(ApplicationArguments args) throws Exception {        while(true){            System.out.println(lettuceRedisTemplate.getClientCacheValue("zhangsan"));            TimeUnit.SECONDS.sleep(1);        }    }

redis外面的zhangsan数据未产生变更时,


控制台输入的数据为

咱们将redis zhangsan的明码改成9999,

看本地缓存是否立马捕捉到


控制台发现明码曾经改成9999

总结

由示例咱们能够看出redis6提供了一个很好的多级缓存同步的实现计划。

咱们再聊下那个技术评审的后续,前面业务部门并没有采纳当mysql宕机,应用redis作为兜底,也没采纳本地缓存,更没采纳两者联合的计划。

不晓得大家散会的时候,有没有这样的领会,有时候咱们在聊一个货色,前面聊着聊着就发散进来,把方向搞丢了。业务部门他们须要数据库宕机的解决方案吗,看着像是,其实他们更外围的须要,是业务零碎不宕机。

奥卡姆剃刀定律:如无必要,勿增实体。其实不论加redis或者本地缓存,额定都减少系统维护老本。因为零碎自身不简单,加了缓存,就要额定思考缓存数据一致性等

前面业务部门的解决形式,是将本人搭建的mysql,切换成云厂商的mysql。这样的益处是,云厂商的mysql会更稳固,其次当呈现问题,能够找云厂商进行解决,毕竟云厂商的运维能力是比拟强的,花钱买心安

这次事变会让业务部门那么器重,次要是应用方是高管,如果是个别使用者,挂就挂吧,大不了重启,应用对象不一样,应急解决形式就不一样

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-localcache-redis-sync