Redis zajmuje całą pamięć i ulega awarii

12

Serwer Redis v2.8.4 działa na Ubuntu 14.04 VPS z 8 GB pamięci RAM i 16 GB przestrzeni wymiany (na dyskach SSD). htopPokazuje jednak , że redissam zajmuje 22.4 Gpamięć!

redis-serverostatecznie rozbił się z powodu braku pamięci. Memi Swpoba trafiają w 100%, następnie redis-serverzostają zabite wraz z innymi usługami.

Od 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

Ponowne uruchomienie redis-serverod czasu awarii OOM lub service redis-server force-reloadpowoduje zmniejszenie zużycia pamięci do <100 MB.

Pytanie: Dlaczego redis-serverzajmuje coraz więcej pamięci, dopóki się nie zawiesi? Jak możemy temu zapobiec?

Czy to prawda, że ​​ustawienie maxmemorynie zadziała, ponieważ gdy redis osiągnie maxmemorylimit, rozpocznie usuwanie danych?

wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

Po zrestartowaniu serwera redis

wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

Wersja Redis: Redis server v=2.8.4 sha=00000000:0 malloc=jemalloc-3.4.1 bits=64 build=a44a05d76f06a5d9


Aktualizacja

Gdy htopzgłasza, że ​​użycie pamięci redis-serverwynosi 4.4G RAM i 22.6G Swap, ilość miejsca zajmowana przez wszystkie klawisze w redis jest tylko 60.59636307 MB, jak podają rdbtools . Jest to również ilość pamięci RAM zajętej redis-serverzaraz po ponownym uruchomieniu.

INFO ALLkiedy redis-serverzajmuje mnóstwo pamięci

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
źródło

Odpowiedzi:

8
  1. Użyj przycisku, maxmemoryaby ustawić limit wzrostu bazy danych Redis. W przeciwnym razie Redis będzie rosnąć, dopóki system operacyjny nie zabije go po wyczerpaniu pamięci (zgodnie z obecnym doświadczeniem).
  2. Wykorzystanie maxmemorypowinno być połączone z maxmemory-policy- możesz wybierać z różnych zasad eksmisji w zależności od wymagań twojego przypadku użycia. Na przykład, jeśli użyjesz zasady allkeys-lrueksmisji, Redis rzeczywiście zacznie eksmitować (ostatnio używane) dane po maxmemoryosiągnięciu. Możesz też poinstruować Redis, aby eksmitowała tylko dane, których ważność wygasła, zgodnie z zasadami volatile-lrulub volatile-random. Na koniec możesz ustawić tę zasadę na, noevictionale oznaczałoby to, że po wyczerpaniu pamięci Redis odmówi dalszego zapisu z komunikatem OOM.

Edytować:

Najpierw wyłącz swap - Redis i swap nie mieszają się łatwo, co z pewnością może powodować spowolnienie.

Zrób również free -mzamiast góry, aby uzyskać pełny obraz stanu pamięci RAM ( http://www.linuxatemyram.com/ ).

Itamar Haber
źródło
Dziękuję, jestem zdezorientowany, dlaczego zużycie pamięci stale rośnie, ale wykonanie bgsavei ponowne uruchomienie redis-serverpowoduje, że zużycie pamięci spada do bardziej rozsądnej wartości 70 MB. Czy to może być wyciek pamięci?
Nyxynyx
Możliwe, ale mało prawdopodobne (lub inne osoby by to zgłosiły) ... Bardziej prawdopodobne jest, że problem fragmentacji. Następnym razem, kiedy to się stanie, opublikuj wyniki swojego Redisa INFO ALL. Jeśli moje przypuszczenie jest słuszne, mem_fragmentation_ratiowola niebios.
Itamar Haber
redis-serverpochłania całą pamięć i codziennie ulega awarii. Zaraz zużyje całą pamięć, więc przechwyciłem dane wyjściowe INFO ALLi dodałem do OP. mem_fragmentation_ratio:0.19
Nyxynyx
Jeśli zestawy danych redis nie przekraczają 250 MB i maxmemorysą ustawione na 1 GB, czy to oznacza, że ​​gdy użycie pamięci redis osiągnie 1 GB, eksmisja nadal usunie dane? Skoro Redis mem_fragmentation_ratiojest 0.19, to czy oznacza to, że jest tam zbyt duża fragmentacja, czy zbyt dużo jest przechowywanych w swapie, czy w obu przypadkach? Jakiś sposób na zmniejszenie fragmentacji?
Nyxynyx
Kiedy serwer redis ma się zawiesić z powodu OOM, rdbtools pokazuje, że klucze w redis zajmują tylko 60 MB. To wygląda na bardzo poważną fragmentację? Biorąc pod uwagę, że zajmuje on 4,4 GB pamięci RAM i 22,4 GB wymiany.
Nyxynyx
5

Jest to prawie na pewno fragmentacja pamięci, ponieważ redis jest dobrze znany i lubiany w produkcji i prawdopodobnie nie znaleziono wycieku pamięci.

Zalecenia dotyczące ustawiania wielkości puli nie pomogą w fragmentacji. Będziesz musiał specjalnie zmniejszyć rozmiar Redis - mniejszy niż faktyczny rozmiar pamięci - ponieważ Redis nie może uwzględnić fragmentacji - ale, biorąc pod uwagę krótką odpowiedź, musisz to zrobić i zacząć planować ponowne uruchomienie serwery często.

Moją ogólną zasadą przy pracy z różnymi systemami operacyjnymi i bazami danych w pamięci jest to, że potrzebujesz 2x rzeczywistej pamięci, a rozmiar pamięci ustabilizuje się za około 2 tygodnie.

Zależy to jednak od faktycznych wzorców alokacji i używanego alokatora pamięci.

W tej chwili najlepszym przydziałem pamięci dla serwerów jest JEMalloc. Używamy go teraz w Aerospike, aby zmniejszyć (prawie usunąć) fragmentację pamięci długoterminowej. JEMalloc ma funkcję, która pozwala na tworzenie „areny” pamięci (puli) i przy dowolnej alokacji, wybierz pulę, zapewniając w ten sposób przydziały o podobnej wielkości i zarządzając podobnymi alokacjami czasu życia pamięci. To była dla nas duża wygrana w omawianych przypadkach.

Silnik Zend PHP jest pod tym względem wyrafinowany, ponieważ wszystkie alokacje wewnątrz silnika są albo w pamięci na transakcję, albo w pamięci globalnej. Pamięć na jedną transakcję jest zwalniana za jednym zamachem pod koniec transakcji, a zatem może być bardzo wydajna.

Jeśli korzystasz z Linuksa, narzędzie do alokacji pamięci jądra (Clib) wykonało wiele zwrotów akcji, a wersja, na której jesteś, będzie drastycznie określać stopień fragmentacji, podobnie jak rzeczywisty wzorzec aplikacji. Na przykład niektóre alokatory są znacznie lepsze, gdy nieznacznie rosną obiekty, inne są znacznie gorsze. Niestety, nawet rozmowa z innymi użytkownikami Redis oznacza rozmowę o tym, jakiego systemu operacyjnego i jakiej wersji systemu operacyjnego używasz.

Fakt, że możesz zrestartować serwer (z trwałości) i odzyskać pamięć, może oznaczać wyciek, ale bardziej prawdopodobne wskazuje na fragmentację.

  1. Nie zezwalaj na zamianę (lepiej OOM niż zamiana, dla redis)
  2. Zmniejsz rozmiar pamięci redis
  3. Uruchom ponownie zgodnie z harmonogramem
Brian Bulkowski
źródło
Jak zmniejszysz rozmiar pamięci, dostosowując maxmemory?
Nyxynyx