Redis 佔用了所有的記憶體和崩潰
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> 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
- 使用
maxmemory
設置 Redis 數據庫也可以增長的限制。如果不這樣做,Redis 將增長,直到記憶體耗儘後作業系統將殺死它(根據您目前的經驗)。- 的使用
maxmemory
應該與maxmemory-policy
- 您可以根據案例的要求從不同的驅逐策略中進行選擇。例如,如果您使用allkeys-lru
eviction 策略,Redis 確實會在到達後開始驅逐(最近最少使用的)數據maxmemory
。或者,您可以使用volatile-lru
或volatile-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 使用者討論也意味著談論您正在使用的作業系統和作業系統版本。
您可以重新啟動伺服器(從持久性)並取回記憶體的事實可能意味著洩漏,但更有可能指向碎片。
- 不允許交換(對於redis,OOM比交換更好)
- 減少 redis 的記憶體大小
- 按計劃重啟