Redisサーバーv2.8.4は、8 GBのUbuntu 14.04 VPSで実行されていますRAMおよびSSDで16 GBのスワップスペース。ただし、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
OOMクラッシュまたはredis-server
からservice redis-server force-reload
を再起動すると、メモリ使用量が100MB未満に低下します。
質問:redis-server
がクラッシュするまで、ますます多くのメモリを使用するのはなぜですか?どうすればこれを防ぐことができますか?
Redisがmaxmemory
の制限に達するとデータの削除を開始するため、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スワップ)であると報告する場合、redisのすべてのキーが占めるスペースの量は rdbtools によって報告される60.59636307 MB
。これは、再起動直後にredis-server
が使用するRAMの量でもあります。
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はOSが強制終了するまで増大します。maxmemory
の使用はmaxmemory-policy
と組み合わせる必要があります-ユースケースの要件に応じて、さまざまなエビクションポリシーから選択できます。たとえば、allkeys-lru
排除ポリシーを使用している場合、maxmemory
に達すると、Redisは実際に(最も最近使用されていない)データの排除を開始します。または、volatile-lru
またはvolatile-random
ポリシーを使用して、有効期限が切れたデータのみを削除するようにRedisに指示できます。最後に、ポリシーをnoeviction
に設定できますが、メモリが使い果たされると、RedisはOOMメッセージでそれ以上の書き込みを拒否します。編集:
最初にスワップを無効にします-Redisとswapは簡単に混ざりません。これは確かに速度低下を引き起こす可能性があります。
RAMの状態の全体像を表示するには、topの代わりにfree -m
も実行してください( http://www.linuxatemyram.com/ )。
これはほぼ間違いなくメモリの断片化です。redisはよく知られており、本番環境で愛されており、メモリリークはおそらく発見されていません。
プールのサイズの設定に関する推奨事項は、断片化に役立ちません。 Redisは断片化を考慮できないため、Redisサイズを実際のメモリサイズよりも具体的に小さくする必要があります。ただし、簡単に言えば、それを行い、再起動の計画を立てる必要があります。頻繁にサーバー。
さまざまなオペレーティングシステムとインメモリデータベースを扱う経験則では、実際のメモリの2倍が必要で、メモリサイズは約2週間で安定します。
ただし、それは実際の割り当てパターンと、使用しているメモリアロケータによって異なります。
現在、サーバー用に見つけた最高のメモリアロケータはJEMallocです。 Aerospike で使用して、長期的なメモリの断片化を軽減(ほぼ削除)します。 JEMallocには、メモリ「アリーナ」(プール)を作成し、任意の割り当てでどのプールを選択するかを選択できる機能があり、これにより、同じサイズの割り当てが可能になり、同様のメモリ寿命の割り当てを管理できます。あなたが議論しているようなケースでは、それは私たちにとって大きな勝利でした。
Zend PHPエンジンはこの点で洗練されています。これは、エンジン内のすべての割り当てがトランザクションごとのメモリまたはグローバルメモリ内にあるためです。トランザクションごとのメモリは、トランザクションの終了。したがって、非常に効率的です。
Linuxを使用している場合、カーネルメモリアロケータ(Clib)には多くの工夫が施されており、実際のアプリケーションパターンと同様に、どのバージョンを使用しているかによって断片化の量が劇的に決まります。たとえば、オブジェクトをわずかに増やしている場合、一部のアロケータははるかに優れていますが、一部のアロケータははるかに悪いです。残念ながら、他のRedisユーザーと話し合うことは、使用しているOSとOSバージョンについて話すことを意味します。
サーバーを(永続化から)再起動してメモリを取り戻すことができるという事実は、リークを意味する可能性がありますが、フラグメンテーションを指している可能性が高くなります。