codis刷新缓存/删除所有key/flushall

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/flyfeifei66/article/details/82415112

codis不支持flush命令,使得我们无法清空key,虽然我们大部分时候都不应该让key大量失效,但是总有些系统/场景需要用到。想了很久,可以有个两个办法。

一、使用lua

我们知道codis是支持lua的,那么我们可以发送一个lua脚本,由于只是一句话刷新,这里采用直接发送代码的形式。不过这里有个问题就是lua脚本依然只是通过参数决定将该命令发送到哪一台,算法跟操作普通key一样,也是CRC32(key)%1024。一个集群可能有多个group,因此想刷新所有server不是件易事。

但是我们知道codis一共有1024个桶,所以我们可以构造能hash到这1024个桶的参数,然后发送命名,即可保证后端所有的server被刷新。

1、构造导航数据:

        CRC32 crc32 = new CRC32();
        
        // 寻找每个slot对应的导航参数
        for (int i = 0; i < 1024; i++)
        {
            for (int j = 0; j < Integer.MAX_VALUE; j++)
            {
                crc32.update(String.valueOf(j).getBytes());
                
                Long num = crc32.getValue();
                
                if (num % 1024 == i)
                {
                    guideData.put(Integer.valueOf(i), Integer.valueOf(j));
                    
                    break;
                }
            }
        }

2、依次刷新(这里也可以使用pipeline,但是经测试老报read time out,可能是发送的命令做多,导致结果不能及时返回)

 for (Map.Entry<Integer, Integer> entry : guideData.entrySet())
        {
            jedis.eval("redis.call('flushall')", 1, entry.getValue().toString());
        }

这个方案的优点是简单,易于理解,对codis集群无侵入。缺点一是实现强依赖codis的实现,如果codis的桶数量、hash算法有改变,必须同步做出改变,二是每个server可能对应多个slot,也就是说每个server可能被刷新了N遍,看起来有点二。不过server有数据时刷新才占用时间,如果没有数据,比如空的集群,这1024次flush占用的时间很少,我测试了下几乎秒级,时间上没有浪费。

二、读取zookeeper

codis所有的集群信息都在zk中有注册,可以读取zk上的group数据,获取主server的ip和port,然后使用原生jedis连接server刷新。一个节点信息截图如下:

其中action为空的是主, {state:"synced"}的是从,如果从不synced主,则无法区分。当然无脑刷新所有server也可以。

这个方案的优点是代码看起来逻辑性强,符合正常思维。缺点一是实现复杂,需要操作zk,且zk的数据让不让读需要确认(这里没做代码验证,zk确实有权限控制),codis存储在zk上的数据结构发生变化的话,这里依然需要同步做修改。二是对codis有侵入,这个可能仁者见仁智者见智,zk作为codis的内部的组件(虽然也作为jodis客户端的发现组件),我们不应该把脚深入到codis内部,所有操作应该尽量走proxy。

猜你喜欢

转载自blog.csdn.net/flyfeifei66/article/details/82415112