Мы используем Newrelic для измерения производительности нашего приложения Python / Django. Newrelic сообщает, что в нашей системе Memcached занимает в среднем 12ms
отвечать на команды.
Просматривая примерно дюжину веб-представлений (по количеству запросов), я вижу, что некоторые Memcache get
взять на себя 30ms
; Я не могу найти ни одного использования Memcache get
который возвращается менее чем 10ms
.
Подробнее об архитектуре системы:
~0.5ms
Не 10ms
а медленный время отклика для Memcached?
Насколько я понимаю, если вы думаете "Memcache слишком медленный" затем "ты делаешь это неправильно". Так я что делаю неправильно?
Вот результат memcache-top
команда:
memcache-top v0.7 (default port: 11211, color: on, refresh: 3 seconds)
INSTANCE USAGE HIT % CONN TIME EVICT/s GETS/s SETS/s READ/s WRITE/s
cache1:11211 37.1% 62.7% 10 5.3ms 0.0 73 9 3958 84.6K
cache2:11211 42.4% 60.8% 11 4.4ms 0.0 46 12 3848 62.2K
cache3:11211 37.5% 66.5% 12 4.2ms 0.0 75 17 6056 170.4K
AVERAGE: 39.0% 63.3% 11 4.6ms 0.0 64 13 4620 105.7K
TOTAL: 0.1GB/ 0.4GB 33 13.9ms 0.0 193 38 13.5K 317.2K
(ctrl-c to quit.)
** Вот результат top
команда на одном компьютере: ** (Примерно одинаково на всех машинах кластера. Как видите, загрузка ЦП очень низкая, поскольку на этих машинах выполняется только кэш памяти.)
top - 21:48:56 up 1 day, 4:56, 1 user, load average: 0.01, 0.06, 0.05
Tasks: 70 total, 1 running, 69 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.3%st
Mem: 501392k total, 424940k used, 76452k free, 66416k buffers
Swap: 499996k total, 13064k used, 486932k free, 181168k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6519 nobody 20 0 384m 74m 880 S 1.0 15.3 18:22.97 memcached
3 root 20 0 0 0 0 S 0.3 0.0 0:38.03 ksoftirqd/0
1 root 20 0 24332 1552 776 S 0.0 0.3 0:00.56 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
4 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0
5 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kworker/u:0
6 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
7 root RT 0 0 0 0 S 0.0 0.0 0:00.62 watchdog/0
8 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 cpuset
9 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 khelper
...output truncated...
Я обнаружил, что запись происходит быстро, одиночное чтение - безумно медленное, а буферизованное чтение - очень-очень быстрое. Вам нужно выполнить буферизованное чтение с помощью get_many, передав массив ключей, которые вы хотите получить. Вот мой тест:
ЗАПИСАТЬ 100000 записанных (один за другим, но, вероятно, буферизируется за кулисами) за 0,42605304718 секунд, 234712 в секунду
ЧИТАТЬ 100000 с размером сегментов = 10000 прочитано (много) за 0,651949167252 секунды, 153386 в секунду
ЧТЕНИЕ 100000 по одному, чтение (одно) за 86,2907109261 секунду, 1158 в секунду
В моем случае я использую python с pymemcache.
Первое, что приходит в голову: используете ли вы полное доменное имя / DNS для установления соединения с сервером memcache или используете IP-адрес или локальный сокет?
Если вы используете имя хоста, вы можете терять время при разрешении имени.
Попробуйте либо поместить полное доменное имя в / etc / hosts клиентов и серверов и перезапустить, чтобы ничего не кэшировалось, либо измените ссылку на IP-адрес и посмотрите, не заметите ли вы улучшения.
Пока мои исследования показывают, что 10ms
медленный". Под этим я подразумеваю, что сами документы кэша памяти относятся к под-1ms
раз как "ожидаемый". Таким образом, время отклика, которое мы видим, на порядок меньше.
Чего ожидать от производительности: https://code.google.com/p/memcached/wiki/NewPerformance
"Вероятные виновники" медленных ответов memcached выглядят (в грубом порядке вероятности):
Я обратился почти ко всем этим следующим образом:
memcached-top
(https://code.google.com/p/memcache-top/) мы получаем примерно такое же время соединения от нашего приложения, что и при запуске brutis
(https://code.google.com/p/brutis/) с тех же серверов приложений.atop
отчеты, которые мы используем)Слепо задавайте эти параметры конфигурации и надеясь, что они улучшат ситуацию:
/sbin/sysctl -w net.ipv4.tcp_tw_recycle=1
/sbin/sysctl -w net.ipv4.tcp_tw_reuse=1
/sbin/sysctl -w net.ipv4.tcp_fin_timeout=10
Результатов без изменений.
Мы практически не можем диагностировать эту проблему. Мы приближаемся к моменту «установить Redis» и надеемся, что он работает лучше.
Я заметил 2 вещи. Коэффициент попадания очень низкий, должен быть как можно ближе к 100 процентам. У вас есть более 200 МБ свободной памяти, которую вы можете использовать для memcached.
Я только что выполнил очистку memcached, поэтому решил опубликовать пример вывода того, что, как мне кажется, работает. Новая реликвия сообщает о 10,4 мс, потраченных в memcached, поэтому я думаю, что это подсчет нескольких вызовов. Вы работаете на голом железе или виртуально, если вам важна скорость, то виртуальный - не лучший вариант ( http://redis.io/topics/benchmarks )
memcache-top v0.6 (default port: 11211, color: on, refresh: 3 seconds)
INSTANCE USAGE HIT % CONN TIME EVICT/s READ/s WRITE/s
app01:11211 0.5% 49.8% 2994 0.7ms 0.0 75.2K 378.5K
app02:11211 0.5% 51.7% 2992 0.7ms 0.0 76.5K 143.9K
app03:11211 1.0% 69.6% 1469 0.7ms 0.0 42.0K 161.3K
app04:11211 2.0% 52.6% 801 0.5ms 0.0 66.0K 415.9K
app05:11211 2.2% 52.5% 801 0.4ms 0.0 71.9K 171.2K
app06:11211 2.0% 66.4% 800 0.5ms 0.0 135.9K 180.4K
app07:11211 1.9% 52.0% 800 0.6ms 0.0 65.5K 482.4K
app08:11211 1.1% 87.1% 1469 0.7ms 0.0 59.3K 365.3K
db01:11211 1.0% 82.4% 1469 0.5ms 0.0 64.6K 155.4K
elastic01:11211 1.7% 69.9% 737 0.5ms 0.0 44.2K 128.8K
elastic02:11211 1.7% 65.0% 737 0.5ms 0.0 48.2K 155.8K
elastic03:11211 1.8% 68.3% 737 0.6ms 0.0 24.5K 115.7K
elastic04:11211 1.8% 69.5% 737 0.7ms 0.0 95.3K 158.0K
AVERAGE: 1.5% 64.4% 1272 0.6ms 0.0 66.9K 231.7K
TOTAL: 12.1GB/ 1.0TB 16.2K 7.6ms 0.0 869.1K 2.9M
(ctrl-c to quit.)
Проблема с django и memcached в том, что они подключаются к каждому запросу. Так что часть этого времени - это время установки соединения.
Это зависит от того, какую привязку кэша памяти вы используете. Но вы можете поместить что-то подобное в свой wsgi.py
# Fix django closing connection to memcached after every request (#11331)
from django.core.cache.backends.memcached import BaseMemcachedCache
BaseMemcachedCache.close = lambda self, **kwargs: None
В основном это обезьяна исправляет обработчик закрытия, чтобы не закрывать.
Если это не сработает, замените свой класс memcached.
В верхнем выводе я заметил, что вы используете пространство подкачки. Вам нужно заставить его перестать обмениваться местами. Своп убивает производительность memcached.