Первоначально написал Ярон Долев
Redis предоставляет широкий спектр инструментов, направленных на улучшение и поддержание эффективного использования базы данных в памяти. Хотя его уникальные типы данных и команды точно настраивают базы данных для обслуживания запросов приложений без какой-либо дополнительной обработки на уровне приложений, неправильная конфигурация или, скорее, использование готовой конфигурации может (и делает) приводить к эксплуатационным проблемам и производительности проблемы.
Несмотря на неудачи, которые стали причиной многих головных болей, решения существуют, и они могут быть даже проще, чем предполагалось.
В этой серии статей будут освещены некоторые наиболее раздражающие проблемы, возникающие при использовании Redis, а также советы по их решению. Они основаны на нашем реальном опыте работы с тысячами экземпляров базы данных Redis.
В наших предыдущих статьях этой серии обсуждались буфер репликации Redis и время ожидания . В этом посте мы расскажем вам о еще одном типе буфера, который поддерживает Redis, о клиентском буфере. В некоторых случаях этот жучок может оказаться причиной многих головных болей, если его не трогать.
Клиентские буферы
Вы, наверное, уже знаете, что Redis — это база данных в памяти, что означает, что все данные управляются и обслуживаются непосредственно из RAM. Это позволяет Redis обеспечивать беспрецедентную производительность, обслуживая десятки и сотни тысяч запросов с задержкой менее миллисекунды. ОЗУ на сегодняшний день является самым быстрым средством хранения данных, предлагаемым на сегодняшний день технологией — чтобы понять значения задержки, взгляните на следующее:
Latency Comparison Numbers -------------------------- L1 cache reference 0.5 ns Branch mispredict 5 ns L2 cache reference 7 ns 14x L1 cache Mutex lock/unlock 25 ns Main memory reference 100 ns 20x L2 cache, 200x L1 cache Compress 1K bytes with Zippy 3,000 ns Send 1K bytes over 1 Gbps network 10,000 ns 0.01 ms Read 4K randomly from SSD* 150,000 ns 0.15 ms Read 1 MB sequentially from memory 250,000 ns 0.25 ms Round trip within same datacenter 500,000 ns 0.5 ms Read 1 MB sequentially from SSD* 1,000,000 ns 1 ms 4X memory Disk seek 10,000,000 ns 10 ms 20x datacenter roundtrip Read 1 MB sequentially from disk 20,000,000 ns 20 ms 80x memory, 20X SSD Send packet CA->Netherlands->CA 150,000,000 ns 150 ms Notes ----- 1 ns = 10-9 seconds 1 ms = 10-3 seconds * Assuming ~1GB/sec SSD Credit ------ By Jeff Dean: http://research.google.com/people/jeff/ Originally by Peter Norvig: http://norvig.com/21-days.html#answers Contributions ------------- Some updates from: https://gist.github.com/2843375 Great 'humanized' comparison version: https://gist.github.com/2843375 Visual comparison chart: http://i.imgur.com/k0t1e.png Nice animated presentation of the data: http://prezi.com/pdkvgys-r0y6/latency-numbers-for-programmers-web-development/
Redis, по названию и дизайну, является удаленным сервером, и это означает, что клиенты (обычно) подключаются к нему по сети. В этом случае запрос клиента займет значительно больше времени для возврата клиенту, чем фактическая загрузка данных из ОЗУ ЦП Redis. Непосредственное следствие этой разницы порядка величин заключается в том, что Redis был бы связан с обслуживанием запроса в течение этого времени, если бы не клиентские буферы.
Клиентские буферы образуют пространство памяти, которое выделяется для обслуживания клиентских запросов, и каждое соединение с Redis выделяется со своим собственным буферным пространством. После обработки запроса Redis копирует данные ответа в буфер клиента и переходит к обработке последующих запросов, в то время как запрашивающий клиент считывает данные обратно по этому соединению в своем собственном сетевом темпе. Клиентские буферы Redis настраиваются в файле redis.conf с помощью обычной директивы client-output-buffer-limit (вы можете получить этот параметр во время выполнения с помощью config get client-output-buffer-limit). Файл redis.conf по умолчанию определяет его следующим образом:
1.
client-output-buffer-limit normal 0 0 0
Эти значения представляют мягкий предел буфера, жесткий предел и время ожидания в секундах соответственно (аналогично поведению буферов репликации ). Они служат защитой, при которой Redis прерывает соединение — не позволяя клиенту прочитать ответ — когда размер буфера достигает а) мягкого предела и остается там до истечения времени ожидания или б) жесткого предела. Установка этих пределов в 0 означает отключение этой защиты.
Однако, в отличие от буферов репликации, выделение памяти для клиентских буферов берется из пространства памяти данных Redis. Общий объем памяти, который может использовать Redis, задается директивой maxmemory, и после достижения Redis будет использовать настроенную политику удаления (определенную директивой maxmemory-policy). Это фактически означает, что медленно работающие клиенты и / или большое количество одновременных подключений могут привести к тому, что ваш экземпляр Redis преждевременно вытеснит ключи или откажет в обновлениях с сообщением о нехватке памяти (OOM), поскольку его использование памяти, главным образом, является суммой размера набора данных и клиентские буферы, достигли предела памяти.
Из-за относительности жизни, клиент не обязательно должен быть медленным, чтобы вызвать это поведение. Из-за огромной разницы в скорости между доступом к ОЗУ и чтением из сети на самом деле очень легко добиться исчерпания памяти Redis с помощью раздутых клиентских буферов, даже с самыми эффективными клиентами и сетевыми связями. Рассмотрим (злую) команду KEYS , например, после ее выполнения Redis скопирует все пространство имен ключей в буфер клиента. Если в вашей базе данных имеется значительное количество ключей, одного этого будет достаточно, чтобы вызвать выселение.
Предупреждение: используйте KEYS с особой осторожностью и никогда в производственной среде. Помимо возможности инициировать выселение, как описано выше, используя его, вы рискуете заблокировать Redis на значительный период времени.
Однако KEYS — не единственная команда, которая может вызвать этот сценарий. Аналогично, SMISBERS , HGETALL , LRANGE и ZRANGE (и связанные с ними команды) Redis могут иметь тот же эффект, если ваши значения (и диапазоны) достаточно велики или, поскольку каждое соединение требует отдельного буфера, если у вас есть несколько открытых соединений.
Поэтому настоятельно рекомендуется воздерживаться от использования этих команд безответственно. Вместо них предпочтение отдается семейству команд SCAN , которые были доступны начиная с v2.8. Эти команды не только позволяют Redis продолжать обработку запросов между последующими вызовами SCAN, но также снижают вероятность исчерпания клиентских буферов.
Клиентские буферы — часто пропускаемый аспект требований к памяти и управления Redis. Их установка по умолчанию на отключение довольно рискованна, поскольку может быстро привести к нехватке памяти. Путем соответствующей установки порогов буферов — принимая во внимание настройку «maxmemory», а также существующее и прогнозируемое использование памяти и шаблоны трафика приложения. Ответственное использование вышеупомянутых команд может предотвратить неприятные ситуации, которые оставят вас с пульсирующей головной болью. Оставайтесь с нами для нашей следующей части в Главных головных болях Redis для Devops!