sql >> データベース >  >> NoSQL >> Redis

Redisで偏ったハッシュスロットを修正する方法

    Redisでは、配布の主要な単位はハッシュスロットです。分散バージョンのredis(オープンソースのRedisクラスター、商用のRedis Enterprise、さらにはAWS ElastiCacheを含む)は、一度に1スロットしかデータを移動できません。

    これは興味深い問題につながります-片側スロット。 1つのスロット(またはいくつかのスロット)にほとんどのデータが含まれる場合はどうなりますか?

    それも可能ですか?

    Redisは、十分に公開されているアルゴリズムを使用して、キーのハッシュスロットを決定します。このアルゴリズムは通常、キーが適切に分散されていることを確認します。

    ただし、開発者はハッシュタグを指定することでアルゴリズムに影響を与えることができます。 。ハッシュタグは、中かっこで囲まれたキーの一部です{...} 。ハッシュタグを指定すると、ハッシュスロットの決定に使用されます。

    redisのハッシュタグは、ほとんどのデータベースがパーティションキーと呼ぶものです。間違ったパーティションキーを選択すると、スロットが偏ってしまいます。

    例として、キーが{users}:1234のような場合 および{users}:5432 、redisはすべてのユーザーを同じハッシュスロットに保存します。

    修正は何ですか?

    修正は概念的に シンプル-間違ったハッシュタグを削除するには、キーの名前を変更する必要があります。したがって、名前を{users}:1234に変更します。 users:{1234}へ またはusers:1234 トリックを行う必要があります…

    …renameコマンドがredisクラスターで機能しないことを除いて。

    したがって、唯一の解決策は、最初にキーをダンプしてから、新しい名前に対して復元することです。

    コードでの表示は次のとおりです。

    
    
    from redis import StrictRedis
    try:
        from itertools import izip_longest
    except:
        from itertools import zip_longest as izip_longest
    
    
    def get_batches(iterable, batch_size=2, fillvalue=None):
        """
        Chunks a very long iterable into smaller chunks of `batch_size`
        For example, if iterable has 9 elements, and batch_size is 2,
        the output will be 5 iterables - each of length 2. 
        The last iterable will also have 2 elements, 
        but the 2nd element will be `fillvalue`
        """
        args = [iter(iterable)] * batch_size
        return izip_longest(fillvalue=fillvalue, *args)
    
    
    def migrate_keys(allkeys, host, port, password=None):
        db = 0
        red = StrictRedis(host=host, port=port, password=password)
    
        batches = get_batches(allkeys)
        for batch in batches:
            pipe = red.pipeline()
            keys = list(batch)
            for key in keys:
                if not key:
                    continue
                pipe.dump(key)
                
            response = iter(pipe.execute())
            # New pipeline to run the restore command
            pipe = red.pipeline(transaction=False)
            for key in keys:
                if not key:
                    continue
                obj = next(response)
                new_key = "restored." + key
                pipe.restore(new_key, 0, obj)
    
            pipe.execute()
    
    
    if __name__ == '__main__':
        allkeys = ['users:18245', 'users:12328:answers_by_score', 'comments:18648']
        migrate_keys(allkeys, host="localhost", port=6379)
    
    

    1. 統合テストの実行時に埋め込まれたMongoDB

    2. 複数のdjangoサイトがあるセロリ

    3. mongodbのネストされた配列にデータを挿入しています

    4. セットメンバーのTTL