Redis забирает всю память и сбои

12

Сервер Redis v2.8.4 работает на Ubuntu 14.04 VPS с 8 ГБ ОЗУ и 16 ГБ подкачки (на SSD). Однако htopпоказывает, что в redisодиночку занимает 22.4 Gпамять!

redis-serverв итоге разбился из-за запоминания. Memи Swpоба попадания на 100% затем redis-serverубиваются вместе с другими службами.

От dmesg:

[165578.047682] Out of memory: Kill process 10155 (redis-server) score 834 or sacrifice child
[165578.047896] Killed process 10155 (redis-server) total-vm:31038376kB, anon-rss:5636092kB, file-rss:0kB

Перезапуск redis-serverпосле сбоя OOM или из-за того, что service redis-server force-reloadиспользование памяти сократилось до <100 МБ.

Вопрос: почему redis-serverзанимает все больше и больше памяти, пока он не падает? Как мы можем предотвратить это?

Правда ли, что настройка maxmemoryне будет работать, потому что как только redis достигнет maxmemoryпредела, он начнет удалять данные?

введите описание изображения здесь введите описание изображения здесь

После перезапуска редис-сервера

введите описание изображения здесь введите описание изображения здесь

Редис версия: Redis server v=2.8.4 sha=00000000:0 malloc=jemalloc-3.4.1 bits=64 build=a44a05d76f06a5d9


Обновить

Когда htopсообщается, что использование памяти redis-serverсоставляет 4,4 ГБ ОЗУ и 22,6 Г Своп, объем пространства, занимаемого всеми ключами в Redis, составляет только 60.59636307 MB, как сообщает rdbtools . Это также объем оперативной памяти, занятой redis-serverсразу после перезагрузки.

INFO ALLкогда redis-serverзанимает тонны памяти

mem_fragmentation_ratio:0.19

127.0.0.1:6379> INFO all

# Server
redis_version:2.8.4
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:a44a05d76f06a5d9
redis_mode:standalone
os:Linux 3.13.0-24-generic x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.2
process_id:26858
run_id:4d4a507b325e567d5ada203a0c65891bcf4d02de
tcp_port:6379
uptime_in_seconds:100011
uptime_in_days:1
hz:10
lru_clock:165668
config_file:/etc/redis/redis.conf

# Clients
connected_clients:60
client_longest_output_list:768774
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:23973468008
used_memory_human:22.33G
used_memory_rss:4563857408
used_memory_peak:24083474760
used_memory_peak_human:22.43G
used_memory_lua:33792
mem_fragmentation_ratio:0.19
mem_allocator:jemalloc-3.4.1

# Persistence
loading:0
rdb_changes_since_last_save:127835154
rdb_bgsave_in_progress:0
rdb_last_save_time:1406716479
rdb_last_bgsave_status:err
rdb_last_bgsave_time_sec:1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok

# Stats
total_connections_received:110
total_commands_processed:386765263
instantaneous_ops_per_sec:3002
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:1385878
keyspace_misses:23655
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:82

# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:10547.48
used_cpu_user:8240.36
used_cpu_sys_children:201.83
used_cpu_user_children:914.86

# Commandstats
cmdstat_del:calls=136,usec=1407,usec_per_call=10.35
cmdstat_exists:calls=161428,usec=1391252,usec_per_call=8.62
cmdstat_zadd:calls=64149642,usec=936323882,usec_per_call=14.60
cmdstat_zrem:calls=137,usec=2131,usec_per_call=15.55
cmdstat_zremrangebyscore:calls=2293,usec=111905082,usec_per_call=48802.91
cmdstat_zrange:calls=7925,usec=285907448,usec_per_call=36076.65
cmdstat_zrangebyscore:calls=921434,usec=292731002,usec_per_call=317.69
cmdstat_zcount:calls=8,usec=172,usec_per_call=21.50
cmdstat_zrevrange:calls=191184,usec=965447,usec_per_call=5.05
cmdstat_zcard:calls=5180,usec=13502,usec_per_call=2.61
cmdstat_zscore:calls=29856,usec=576044,usec_per_call=19.29
cmdstat_hset:calls=64145124,usec=199407095,usec_per_call=3.11
cmdstat_hget:calls=248487,usec=501220,usec_per_call=2.02
cmdstat_hincrby:calls=128339355,usec=2071112929,usec_per_call=16.14
cmdstat_hgetall:calls=193747,usec=1608260,usec_per_call=8.30
cmdstat_select:calls=1,usec=5,usec_per_call=5.00
cmdstat_rename:calls=134,usec=1090,usec_per_call=8.13
cmdstat_keys:calls=4503,usec=4997628,usec_per_call=1109.84
cmdstat_bgsave:calls=2,usec=20012,usec_per_call=10006.00
cmdstat_type:calls=603,usec=2736,usec_per_call=4.54
cmdstat_multi:calls=64181979,usec=383633610,usec_per_call=5.98
cmdstat_exec:calls=64181979,usec=4403181204,usec_per_call=68.60
cmdstat_info:calls=126,usec=28675,usec_per_call=227.58

# Keyspace
db0:keys=2109,expires=0,avg_ttl=0
Nyxynyx
источник

Ответы:

8
  1. Используйте, maxmemoryчтобы установить предел того, насколько может расти ваша база данных Redis. Если этого не сделать, Redis будет расти до тех пор, пока операционная система не уничтожит его после исчерпания памяти (согласно вашему текущему опыту).
  2. Использование maxmemoryдолжно быть связано с maxmemory-policy- вы можете выбирать из различных политик выселения в зависимости от требований вашего варианта использования. Например, если вы используете allkeys-lruполитику выселения, Redis действительно начнет выселять (наименее недавно использованные) данные, как maxmemoryтолько будет достигнут. В качестве альтернативы вы можете указать Redis исключать только данные с истекшим сроком действия с помощью политик volatile-lruили volatile-random. Наконец, вы можете установить политику, noevictionно это будет означать, что, как только память будет исчерпана, Redis будет запрещать дальнейшие записи с сообщением OOM.

Редактировать:

Сначала отключите swap - Redis и swap не смешиваются легко, и это, безусловно, может привести к замедлению.

Также сделайте free -mвместо top полную картину состояния вашей оперативной памяти ( http://www.linuxatemyram.com/ ).

Итамар Хабер
источник
Спасибо, я запутался в том, почему использование памяти продолжает расти, но выполнение bgsaveи перезапуск redis-serverприводит к снижению использования памяти до более приемлемого значения 70 МБ. Может ли это быть утечка памяти?
Nyxynyx
Возможно, но вряд ли (или другие люди сообщили бы об этом) ... Скорее всего, проблема фрагментации. В следующий раз, когда это произойдет, опубликуйте вывод вашего Redis ' INFO ALL. Если моя догадка верна, mem_fragmentation_ratioволя заоблачная.
Итамар Хабер
redis-serverзабирает всю память и вылетает каждый день. Теперь он собирается использовать всю память, поэтому я записал вывод INFO ALLи добавил в OP. mem_fragmentation_ratio:0.19
Nyxynyx
Если наборы данных Redis не превышают 250 МБ и maxmemoryустановлены на 1 ГБ, означает ли это, что когда использование памяти Redis достигает 1 ГБ, выселение все равно удалит данные? Поскольку Redis mem_fragmentation_ratioесть 0.19, означает ли это, что в swap слишком много фрагментации, или слишком много, или в обоих? Есть ли способ уменьшить фрагментацию?
Nyxynyx
Когда redis-сервер собирается аварийно завершить работу из-за OOM, rdbtools показывает, что ключи в redis занимают только 60 МБ. Это выглядит как очень серьезная фрагментация? Учитывая, что он занимает 4,4 ГБ оперативной памяти и 22,4 ГБ подкачки.
Nyxynyx
5

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

Рекомендации по настройке размера пула не помогут при фрагментации. Вам нужно будет конкретно уменьшить размер Redis - меньше, чем ваш фактический объем памяти - потому что Redis не может учитывать фрагментацию - но, с точки зрения краткого ответа, вам придется это сделать и начать планировать перезапуск вашего сервера часто.

Мое эмпирическое правило, работающее с различными операционными системами и базами данных в памяти, заключается в том, что вам нужно в 2 раза больше фактической памяти, а объем памяти стабилизируется примерно через 2 недели.

Однако это зависит от ваших фактических моделей распределения и используемого вами распределителя памяти.

Сейчас лучшим распределителем памяти, который я нашел для серверов, является JEMalloc. Мы используем его в Aerospike сейчас, чтобы уменьшить (почти удалить) долговременную фрагментацию памяти. JEMalloc имеет функцию, которая позволяет вам создавать «арену» (пул) памяти и при любом распределении выбирать, какой пул, тем самым предоставляя вам ресурсы одинакового размера и управлять аналогичными распределениями времени жизни памяти. Это была большая победа для нас в тех случаях, которые вы обсуждаете.

В этом отношении движок Zend PHP сложен, потому что все выделения внутри него находятся либо в памяти для каждой транзакции, либо в глобальной памяти. Для каждой транзакции память освобождается одним махом в конце транзакции и, таким образом, может быть очень эффективной.

Если вы работаете в Linux, распределитель памяти ядра (Clib) сделал несколько изгибов и поворотов, и от того, какая версия вы используете, будет резко зависеть степень фрагментации, как и от фактического шаблона приложения. Например, некоторые распределители намного лучше, когда вы немного растете объекты, а некоторые намного хуже. К сожалению, даже обсуждение с другими пользователями Redis означает разговор о том, какую ОС и какую версию ОС вы используете.

Тот факт, что вы можете перезапустить сервер (из постоянства) и вернуть память, может означать утечку, но, скорее всего, указывает на фрагментацию.

  1. Запретить своп (лучше для OOM, чем для свопа, для redis)
  2. Уменьшить объем памяти redis
  3. Перезапуск по расписанию
Брайан Булковски
источник
Как бы вы уменьшили объем памяти, регулируя maxmemory?
Nyxynyx