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)