Redis本地缓存同步的一个简单方案

/ JavaRedis / 没有评论 / 4058浏览

现在大部分系统使用的都是分布式缓存系统Redis。 但在一些场景下,比如缓存单元很大,单元数不多,变化很小,加载时间很长,如算法模型。 这个时候使用本地缓存比Redis的效率要高很多,但是又要保证集群中各个机器的缓存的一致性,不然就会出现请求耗时不稳定的情况,也有可能出现相同的请求不同服务器返回的结果不一致。 本文介绍了一个简单的实现集群中同步各服务器本地缓存的方案。

实现思路:

整个过程分成两个阶段:初始同步与广播同步

初始同步

程序启动时,一开始没有缓存任何模型数据,进入初始同步阶段。流程如下:

img

监听缓存变更事件

获取缓存事件后,并不立即操作,后续再顺序处理该事件

下面一些操作都用redis命令演示,实际项目中,使用的是jedis

redis> subscribe channel.model

获取缓存的数据id

一般从redis读取缓存的模型id列表

redis> smembers cache.models

缓存所有模型数据

根据上一步读到的id列表,缓存所有模型数据

一般是从数据库或分布式文件系统中加载模型

增量更新

如果到缓存模型数据结束,有监听到缓存变更事件,则依次响应该事件

完成增量更新后,节点接入下一个阶段:广播同步


广播同步

集群中的每个节点都订阅频道channel.model, 接收缓存变更的消息(增、删、改);也在主动变更后,往频道channel.model发布消息来广播给其他节点。消息分为以下三种类型:

redis> publish channel.model add:1
redis> publish channel.model update:1
CacheBuilder.newBuilder()
        .maximumSize(1000)
        .expireAfterAccess(1, TimeUnit.DAYS)
        .removalListener((RemovalListener<Integer, Model>) notification -> {
            final RemovalCause cause = notification.getCause();
            switch (cause) {
                    //缓存到期
                case EXPIRED:
                    //缓存大小限制
                case SIZE:
                    //缓存被垃圾回收
                case COLLECTED:
                    //如果是缓存到期等原因被删除,则需要通知分布式环境下的其他机器也要删除
                    distCacheManager.removeFromCache(notification.getKey());
                    break;
                    //缓存显示删除(这里没有调用是避免事件循环)
                case EXPLICIT:
                    //缓存显示替换(这了没有调用是避免事件循环)
                case REPLACED:
                    break;
                default:
                    log.error("there should not be [{}]", cause);
            }
redis> publish channel.model delete:1

优缺点

优点:

缺点:

注意事项

参考