Performance

Redis 佔用了所有的記憶體和崩潰

  • October 8, 2019

redis 伺服器 v2.8.4 在 Ubuntu 14.04 VPS 上執行,具有 8 GB RAM 和 16 GB 交換空間(在 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從 Etiher 重新啟動 OOM 崩潰或導致service redis-server force-reload記憶體使用量降至 <100MB。

**問題:**為什麼會redis-server佔用越來越多的記憶體,直到崩潰?我們怎樣才能防止這種情況發生?

maxmemory不是因為一旦redis達到限制,設置就不起作用了maxmemory,它會開始刪除數據?

在此處輸入圖像描述 在此處輸入圖像描述

重啟redis-server後

在此處輸入圖像描述 在此處輸入圖像描述

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


更新

htop報告記憶體使用量redis-server為 4.4G RAM 和 22.6G Swap 時,redis 中所有鍵佔用的空間量僅為rdbtools60.59636307 MB報告的。這也是它重新啟動後立即佔用的 RAM 量。redis-server

INFO ALL什麼時候redis-server佔用大量記憶體

mem_fragmentation_ratio:0.19

127.0.0.1:6379&gt; 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
  1. 使用maxmemory設置 Redis 數據庫也可以增長的限制。如果不這樣做,Redis 將增長,直到記憶體耗儘後作業系統將殺死它(根據您目前的經驗)。
  2. 的使用maxmemory應該與maxmemory-policy- 您可以根據案例的要求從不同的驅逐策略中進行選擇。例如,如果您使用allkeys-lrueviction 策略,Redis 確實會在到達後開始驅逐(最近最少使用的)數據maxmemory。或者,您可以使用volatile-lruvolatile-random策略指示 Redis 僅驅逐可過期的數據。最後,您可以將策略設置為,noeviction但這意味著一旦記憶體耗盡,Redis 將使用 OOM 消息拒絕進一步的寫入。

編輯:

首先禁用交換 - Redis 和交換不容易混合,這肯定會導致緩慢。

也可以free -m代替 top 查看 RAM 狀態的全貌(http://www.linuxatemyram.com/)。

這幾乎可以肯定是記憶體碎片,因為 redis 在生產中廣為人知並深受喜愛,而且您可能還沒有發現記憶體洩漏。

關於設置池大小的建議無助於碎片化。您必須專門降低 Redis 大小 - 低於您的實際記憶體大小 - 因為 Redis 無法解決碎片問題 - 但是,就簡短的回答而言,您必須這樣做,並開始計劃重新啟動您的伺服器頻繁。

我使用各種作業系統和記憶體數據庫的經驗法則是,您需要 2 倍實際記憶體,並且記憶體大小將在大約 2 週內穩定下來。

但是,這取決於您的實際分配模式以及您使用的記憶體分配器。

現在,我為伺服器找到的最好的記憶體分配器是 JEMalloc。我們現在在Aerospike使用它來減少(幾乎消除)長期記憶碎片。JEMalloc 具有允許您創建記憶體“競技場”(池)的功能,並在任何分配上選擇哪個池,從而為您提供類似大小的分配並管理類似的記憶體生命週期分配。在你討論的那種情況下,這對我們來說是一個巨大的勝利。

Zend PHP 引擎在這方面是複雜的,因為引擎內部的所有分配要麼在每個事務記憶體中,要麼在全域記憶體中。每個事務的記憶體在事務結束時一舉釋放,因此非常有效。

如果您在 Linux 中,核心記憶體分配器 (Clib) 經歷了許多曲折,您使用的版本將極大地決定碎片的數量,實際的應用程序模式也是如此。例如,當您稍微增長對象時,一些分配器會好得多,而有些則更糟。遺憾的是,即使與其他 Redis 使用者討論也意味著談論您正在使用的作業系統和作業系統版本。

您可以重新啟動伺服器(從持久性)並取回記憶體的事實可能意味著洩漏,但更有可能指向碎片。

  1. 不允許交換(對於redis,OOM比交換更好)
  2. 減少 redis 的記憶體大小
  3. 按計劃重啟

引用自:https://dba.stackexchange.com/questions/72661