Назад | Перейти на главную страницу

Медленный Memcached: в среднем 10 мс memcached `get`

Мы используем Newrelic для измерения производительности нашего приложения Python / Django. Newrelic сообщает, что в нашей системе Memcached занимает в среднем 12ms отвечать на команды.

Просматривая примерно дюжину веб-представлений (по количеству запросов), я вижу, что некоторые Memcache get взять на себя 30ms; Я не могу найти ни одного использования Memcache get который возвращается менее чем 10ms.

Подробнее об архитектуре системы:

Не 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, передав массив ключей, которые вы хотите получить. Вот мой тест:

  1. ЗАПИСАТЬ 100000 записанных (один за другим, но, вероятно, буферизируется за кулисами) за 0,42605304718 секунд, 234712 в секунду

  2. ЧИТАТЬ 100000 с размером сегментов = 10000 прочитано (много) за 0,651949167252 секунды, 153386 в секунду

  3. ЧТЕНИЕ 100000 по одному, чтение (одно) за 86,2907109261 секунду, 1158 в секунду

В моем случае я использую python с pymemcache.

Первое, что приходит в голову: используете ли вы полное доменное имя / DNS для установления соединения с сервером memcache или используете IP-адрес или локальный сокет?

Если вы используете имя хоста, вы можете терять время при разрешении имени.

Попробуйте либо поместить полное доменное имя в / etc / hosts клиентов и серверов и перезапустить, чтобы ничего не кэшировалось, либо измените ссылку на IP-адрес и посмотрите, не заметите ли вы улучшения.

Пока мои исследования показывают, что 10ms медленный". Под этим я подразумеваю, что сами документы кэша памяти относятся к под-1ms раз как "ожидаемый". Таким образом, время отклика, которое мы видим, на порядок меньше.

Чего ожидать от производительности: https://code.google.com/p/memcached/wiki/NewPerformance

"Вероятные виновники" медленных ответов memcached выглядят (в грубом порядке вероятности):

  1. плохой дизайн приложения (или ошибка)
  2. перегрузка сети
  3. обмен
  4. высокая загрузка ЦП из приложений-со-арендаторов
  5. ударил какое-то соединение макс
  6. государственные межсетевые экраны
  7. плохие конфигурации TCP

Я обратился почти ко всем этим следующим образом:

  1. В соответствии с memcached-top (https://code.google.com/p/memcache-top/) мы получаем примерно такое же время соединения от нашего приложения, что и при запуске brutis (https://code.google.com/p/brutis/) с тех же серверов приложений.
  2. Время отклика остается неизменным в течение дня, несмотря на то, что наша система имеет четкое время пиковой загрузки; время отклика никогда не бывает "резким", как можно было бы ожидать, если бы это было проблемой перегрузки. (Также наш хостинг-провайдер утверждает, что предоставляет этим экземплярам гораздо больше Мбит / с, чем atop отчеты, которые мы используем)
  3. Замечено, что в системах много свободной памяти (и нет iowait)
  4. Низкая загрузка ЦП всего кеша
  5. Только обслуживание 10-20 одновременных подключений на сервер
  6. Мы использовали брандмауэр с отслеживанием состояния (через iptables), но когда мы удалили все записи с отслеживанием состояния, производительность не изменилась.
  7. Слепо задавайте эти параметры конфигурации и надеясь, что они улучшат ситуацию:

    /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.