sql >> Databáze >  >> NoSQL >> Redis

Jak opravit Lopsided Hash Slots v Redis

V Redis je primární distribuční jednotkou hash slot. Distribuované verze redis – včetně open source Redis Cluster, komerčního Redis Enterprise a dokonce AWS ElastiCache – se mohou přesouvat daty pouze po 1 slotu najednou.

To vede k zajímavému problému - slot-sided slots. Co když jeden slot (nebo několik slotů) skončí s většinou dat?

Je to vůbec možné?

Redis rozhodne o hash-slotu pro klíč pomocí dobře publikovaného algoritmu. Tento algoritmus obvykle zajistí, že klíče jsou dobře distribuovány.

Vývojáři však mohou algoritmus ovlivnit zadáním hash tagu . Hash tag je část klíče uzavřená ve složených závorkách {...} . Když je zadán hash-tag, bude použit k rozhodnutí o hash slotu.

Hash-tag v redis je to, co by většina databází nazvala klíčem oddílu. Pokud zvolíte špatný klíč oddílu, získáte nevychýlené sloty.

Například pokud jsou vaše klíče jako {users}:1234 a {users}:5432 , redis uloží všechny uživatele do stejného hash slotu.

Jaká je oprava?

Oprava je koncepční jednoduché - musíte přejmenovat klíč, abyste odstranili nesprávný hash tag. Takže přejmenování {users}:1234 pro users:{1234} nebo dokonce users:1234 měl by stačit…

… až na to, že příkaz rename nefunguje v clusteru redis.

Takže jediná cesta ven je nejprve vypsat klíč a poté jej obnovit s novým názvem.

Zde je návod, jak to vypadá v kódu:



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. redis paměti a cpu špičky

  2. Konfigurace ověřování MongoDB-CR jako výchozí na MongoDB 3.x

  3. Proč potřebujeme, jaké výhody používat mangustu

  4. MongoDB $ cmp