Redis
 sql >> база данни >  >> NoSQL >> Redis

Как да поправите едностранни хеш слотове в Redis

В Redis основната единица за разпространение е хеш слот. Разпределените версии на redis – включително Redis Cluster с отворен код, търговският Redis Enterprise и дори AWS ElastiCache – могат да се движат само 1 слот за данни наведнъж.

Това води до интересен проблем - слотове с изкривени страни. Ами ако един слот (или няколко слота) в крайна сметка разполага с повечето данни?

Въобще възможно ли е това?

Redis решава хеш-слота за ключ, използвайки добре публикуван алгоритъм. Този алгоритъм обикновено гарантира, че ключовете са добре разпределени.

Но разработчиците могат да повлияят на алгоритъма, като посочат хеш маркер . Хеш маркерът е част от ключа, затворена в къдрави скоби {...} . Когато е посочен хеш маркер, той ще се използва за определяне на слота за хеш.

Хеш-тегът в redis е това, което повечето бази данни биха нарекли ключ на дял. Ако изберете грешен ключ за дял, ще получите изкривени слотове.

Като пример, ако вашите ключове са като {users}:1234 и {users}:5432 , redis ще съхранява всички потребители в един и същ хеш слот.

Какво е поправката?

Поправката е концептуална просто - трябва да преименувате ключа, за да премахнете неправилния хеш маркер. Така че преименуване на {users}:1234 до users:{1234} или дори users:1234 трябва да свърши работа...

… с изключение на това, че командата за преименуване не работи в редис клъстер.

Така че единственият изход е първо да изхвърлите ключа и след това да го възстановите срещу новото име.

Ето как изглежда в кода:



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. Redis - Как да конфигурирате персонализирани преобразувания

  2. Laravel 4:Извикване на недефиниран метод Redis::connection()

  3. nginx lua redis бисквитката не се задава

  4. Redis lua кога наистина да го използвам?

  5. Как да четете множество набори, съхранени в Redis, като използвате някаква команда или LUA скрипт