Подтвердить что ты не робот

Как django обрабатывает несколько серверов memcached?

В документации django говорится следующее:

...

Одной из замечательных особенностей Memcached является возможность совместного использования кеша несколько серверов. Это означает, что вы можете запускать демоны Memcached на нескольких машины, и программа будет обрабатывать группу машин как единую кеш, без необходимости дублировать значения кеша на каждой машине. к воспользуйтесь этой функцией, включите все адреса серверов в LOCATION, либо разделенные точкой с запятой, либо как список.

...

Структура кэша Django - Memcached

Как именно это работает? Я прочитал несколько ответов на этом сайте, которые предполагают, что это достигается путем обхода серверов по хэшам ключей.

Вопрос о нескольких серверах memcached

Как MemCacheStore действительно работает с несколькими серверами?

Это хорошо, но мне нужен гораздо более конкретный и подробный ответ. Используя django с pylibmc или python-memcached, как это происходит на самом деле? Является ли порядок IP-адресов в настройке конфигурации? Что делать, если два разных веб-сервера, на которых работает одно и то же приложение django, имеют два разных файла настроек с IP-адресами серверов memcached в другом порядке? Это приведет к тому, что каждая машина использует другую стратегию очертания, которая вызывает дублирование ключей и другую неэффективность?

Что делать, если конкретная машина отображается в списке дважды? Например, что делать, если я должен был сделать что-то вроде этого, где 127.0.0.1 на самом деле является той же машиной, что и 172.19.26.240?

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '127.0.0.1:11211',
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]
    }
}

Что делать, если один из серверов memcached имеет большую емкость, чем другие? Если машина имеет 64 МБ memcached, а машина 2 имеет 128 Мбайт, будет ли учитываться алгоритм очертания и дать машине 2 большую долю ключей?

Я также прочитал, что если memcached-сервер потерян, эти ключи будут потеряны. Это очевидно, когда речь идет о шрапане. Что еще важнее, что произойдет, если сервер memcached опустится, и я оставлю свой IP-адрес в файле настроек? Будет ли django/memcached просто не получить какие-либо ключи, которые были бы отложены на этот неудавшийся сервер, или он поймет, что сервер потерпел неудачу и придумал новую стратегию ошпаривания? Если есть новая стратегия ошпаривания, разумно ли она использует ключи, которые изначально были предназначены для отказавшего сервера, и делить их между оставшимися серверами, или же она придумала совершенно новую стратегию, как если бы первый сервер не существовал и привести к дублированию ключей?

Я пробовал читать исходный код python-memcached и не мог понять это вообще. Я планирую попробовать прочитать код libmemcached и pylibmc, но я решил, что спрашивать здесь было бы легче, если бы кто-то уже знал.

4b9b3361

Ответ 1

Это фактический клиент memcached, который выполняет очертание. Django передает конфигурацию только от settings.CACHES клиенту.

Порядок серверов не имеет значения *, но (по крайней мере для python-memcached) вы можете указать "вес" для каждого из серверов:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
                ('cache1.example.org:11211', 1),
                ('cache2.example.org:11211', 10),
            ],
}

Я думаю, что быстрый взгляд на memcache.py (из python-memcached) и особенно memcached.Client._get_server должен ответить на остальные ваши вопросы:

def _get_server(self, key):
    if isinstance(key, tuple):
        serverhash, key = key
    else:
        serverhash = serverHashFunction(key)

    for i in range(Client._SERVER_RETRIES):
        server = self.buckets[serverhash % len(self.buckets)]
        if server.connect():
            #print "(using server %s)" % server,
            return server, key
        serverhash = serverHashFunction(str(serverhash) + str(i))
    return None, None

Я ожидаю, что другие клиенты memcached будут реализованы аналогичным образом.


Разъяснение по @Apreche: Порядок серверов имеет значение в одном случае. Если у вас несколько веб-серверов, и вы хотите, чтобы все они размещали одни и те же ключи на одних и тех же серверах memcached, вам нужно настроить их с тем же списком серверов в том же порядке с теми же весами

Ответ 2

Я тестировал часть этого и нашел несколько интересных вещей с django 1.1 и python-memcached 1.44.

В django с использованием 2 серверов memcache

cache.set('a', 1, 1000)

cache.get('a') # returned 1

Я посмотрел, какой сервер memcache 'a' был оштрафован на использование двух других настроек django, каждый из которых указывает на один из серверов memcache. Я смоделировал перебои в подключении, установив межсетевой экран между исходным экземпляром django и сервером memcache, в котором хранился "a".

cache.get('a') # paused for a few seconds and then returned None

cache.set('a', 2, 1000)

cache.get('a') # returned 2 right away

Клиентская библиотека memcache обновляет свою стратегию ошпаривания, если сервер не работает.

Затем я удалил брандмауэр.

cache.get('a') # returned 2 for a bit until it detected the server back up then returned 1!

Вы можете читать устаревшие данные, когда сервер memcache падает и возвращается! Memcache не делает ничего умного, чтобы попытаться предотвратить это.

Это может портиться, если вы используете стратегию кэширования, которая долгое время хранит вещи в memcache и зависит от недействительности кэша для обработки обновлений. Старое значение может быть записано на "обычный" кэш-сервер для этого ключа, и если вы потеряете возможность подключения и сделаете недействительность во время этого окна, когда сервер станет доступен снова, вы увидите устаревшие данные, которые вы не сможете использовать к.

Еще одно замечание: я читал о некоторых библиотеках кэширования объектов и запросов, и я думаю, что johnny-cache должен быть защищен от этой проблемы. Он явно не отменяет записи; вместо этого он изменяет ключ, по которому кешируется запрос при изменении таблицы. Поэтому он никогда не будет случайно читать старые значения.

Изменить: я думаю, что моя заметка о работе johnny-cache работает нормально. http://jmoiron.net/blog/is-johnny-cache-for-you/ говорит: "Есть дополнительные чтения кеша при каждом запросе на загрузку текущих поколений". Если поколение хранится в самом кэше, описанный выше сценарий может вызвать чтение устаревшего поколения.

Ответ 3

Думал добавить этот ответ через два года после того, как был задан вопрос, так как он очень сильно оценивается в поиске и потому, что мы нашли ситуацию, когда django разговаривал только с одним из серверов memcached.

С сайтом, работающим на django 1.4.3, python-memcached 1.51, разговаривающим с четырьмя экземплярами memcached, мы обнаружили, что база данных запрашивается гораздо чаще, чем ожидалось. Копаясь дальше, мы обнаружили, что cache.get() возвращал None для ключей, которые, как известно, присутствовали, по крайней мере, в одном из экземпляров memcached. Когда memcached был запущен с параметром -vv, он показал, что вопрос был задан только на одном сервере!

После того, как много волос было потянуто, мы переключили бэкэнд на django.core.cache.backends.memcached.PyLibMCCache (pylibmc), и проблема исчезла.