1. ホーム
  2. データベース
  3. レディス

redis クラスタの実装は同じプレフィックスを持つキーをクリーンアップします。

2022-01-15 09:19:10

redis クラスタが同じ接頭辞を持つキーのクリーンアップ

最近redisクラスタのアラートが多くて、1日に50通以上来るので、無駄なキー(3000万くらい)がメモリを占有していて、メモリが足りないのが本当に困る(詳細は割愛)。この部分のメモリが解放できないのです。

オリジナルの定期的なクリーンアップスクリプトのロジック

Redisのリンクを開き、内部的に1000万から7億までのデータをループし、一括削除に行くためにプレフィックスを追加し、この方法は、広いキャストネットのクリーンアップに属する、徹底的な方法は、時間がかかるだけでなく、効果的ではありません。

なぜなら、redisに存在しない数字もあるでしょうし、何より7億個以上の数字があると、この部分のデータがクリアされずにスケーラビリティが悪くなってしまうからです。

(1) では、どうやって掃除するのでしょうか?redisクラスタにはキーというメソッドがないので、このキーのバッチを迅速かつ正確に見つけるにはどうしたらいいのでしょうか?

Redis Clusterが提供するgetClusterNodesメソッドでredis-clusterの各ノードを取得し、そのノードのJedisペアを一つずつ取得して、個々のJedisペアで同じプレフィックスのキーを取得すればいいのです

(2) キーセットを取得したら、次にこれらのキーを繰り返し、JedisClusterCRC16.getSlot(key)メソッドでキーがある場所を探し、同じスロット内のキーを一括削除します。これにより、一つ目は削除する必要があるキーがredis cluster内に存在することを確認し、二つ目は一括削除で効率化を図ることができます。

具体的なコード

Map<String, JedisPool> clusterNodes = jedis.getClusterNodes();
                String keysPattern = keyPrefix + ":*";
                long countX = 0;
                long sTime = System.currentTimeMillis();
                for (Map.Entry<String, JedisPool> entry : clusterNodes.entrySet()) {  
                    Jedis jedisNode = entry.getValue().getResource();  
                    logger.info("redisip:{},port:{}" , jedisNode.getClient().getHost(), jedisNode.getClient().getPort());
                    if (!jedisNode.info("replication").contains("role:slave")) {  
                          Set<String> keys = jedisNode.keys(keysPattern);
                          logger.info("length of keys:{}" , keys.size());
                          Map<Integer, List<String>> map = new HashMap<>(6600);  
                          long countTmp = 0;
                            for (String key : keys) { int slot = JedisClusterCRC16.getSlot(key);
                                /**
                                 * When performing multi-key operations in cluster mode, these keys must be on the same slot.
                                 * otherwise it will report :JedisDataException 
                                 *                                // group the keys by slot, and submit the keys of the same slot together  
                                if (map.containsKey(slot)) {  
                                    map.get(slot).add(key);  
                                } else {  
                                     List<String> keyList = new ArrayList<String>();
                                     keyList.add(key);
                                     map.put(slot, keyList);  
                                    }
                                 
                            }
                            long count = 0;
                            for (Map.Entry<Integer, List<String>> integerListEntry : map.entrySet()) {  
                                count += jedisNode.del(integerListEntry.getValue().toArray(new String[integerListEntry.getValue().size()])));  
                                logger.info("Deleted:{} of",count);
                                countX++;
                            }  
                     }
                }
// logger.info("Deletion complete, total deleted:{}",countX);
                    logger.info("Deleting userid key task finished, total number of keys deleted:{},time spent:{}", countX , System.currentTimeMillis() - sTime);

redis cluster (jedis) bulk delete same prefix

public Set<String> getByPrefix(String key) {
        Set<String> setResult = new HashSet<>();
        try {
            ShardedJedis jedis = redisDataSource.getJedisClient();
            Iterator<Jedis> jedisIterator = jedis.getAllShards().iterator();
            while(jedisIterator.hasNext()){
                setResult = jedisIterator.next().keys(key+"*");
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return setResult;
    }

上記は私の個人的な経験ですが、参考にしていただき、BinaryDevelopをもっとサポートしていただければと思います。