Redis
 sql >> Baza danych >  >> NoSQL >> Redis

Jak naprawić Lopsded Hash Slots w Redis?

W Redis podstawową jednostką dystrybucji jest gniazdo skrótu. Rozproszone wersje redis – w tym open source Redis Cluster, komercyjny Redis Enterprise, a nawet AWS ElastiCache – mogą poruszać się tylko po jednym gnieździe danych na raz.

Prowadzi to do interesującego problemu - koślawych automatów. Co się stanie, jeśli jeden slot (lub kilka slotów) będzie zawierał większość danych?

Czy to w ogóle możliwe?

Redis decyduje o gnieździe skrótu dla klucza przy użyciu dobrze opublikowanego algorytmu. Ten algorytm zwykle zapewnia dobrą dystrybucję kluczy.

Ale programiści mogą wpływać na algorytm, określając tag mieszający . Znacznik hash to część klucza ujęta w nawiasy klamrowe {...} . Po określeniu hash-tagu zostanie on użyty do określenia miejsca na hash.

Hash-tag w redis jest tym, co większość baz danych nazwałaby kluczem partycji. Jeśli wybierzesz niewłaściwy klucz partycji, otrzymasz krzywe gniazda.

Na przykład, jeśli twoje klucze są takie jak {users}:1234 i {users}:5432 , redis będzie przechowywać wszystkich użytkowników w tym samym gnieździe skrótu.

Jaka jest poprawka?

Poprawka jest koncepcyjnie proste - musisz zmienić nazwę klucza, aby usunąć nieprawidłowy hash tag. Zmieniam więc nazwę {users}:1234 do users:{1234} a nawet users:1234 powinien załatwić sprawę…

… z wyjątkiem tego, że polecenie zmiany nazwy nie działa w klastrze redis.

Więc jedynym wyjściem jest najpierw zrzucenie klucza, a następnie przywrócenie go pod nową nazwą.

Oto jak to wygląda w kodzie:



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
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Klient Java do podłączenia węzła pamięci podręcznej ElasticCache Redis

  2. Optymalizacja jednoczesnych żądań ImageMagick za pomocą redis/php-resque

  3. Jak ustawić limit czasu odczytu na kliencie redis węzła?

  4. Jak mogę uzyskać wartość z Redis i umieścić ją w zmiennej w NGiNX?

  5. co to jest pamięć podręczna stron, dentries, i-węzły?