Redis ใช้หน่วยความจำและล่มทั้งหมด


12

เซิร์ฟเวอร์ redis v2.8.4 กำลังทำงานบน Ubuntu 14.04 VPS พร้อม RAM 8 GB และพื้นที่สลับ 16 GB (บน SSD) อย่างไรก็ตามhtopแสดงให้เห็นว่าredisเพียงลำพังกำลัง22.4 Gหน่วยความจำ!

redis-serverในที่สุดก็ล้มเหลวเนื่องจากออกจาก memeory 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จากความผิดพลาดของ OI หรือservice redis-server force-reloadทำให้การใช้หน่วยความจำลดลงเหลือ <100MB

คำถาม:ทำไมredis-serverครอบครองหน่วยความจำมากขึ้นเรื่อย ๆ จนกว่ามันจะล่ม? เราจะป้องกันสิ่งนี้ได้อย่างไร

เป็นความจริงหรือไม่ว่าการตั้งค่าmaxmemoryจะไม่ทำงานเพราะเมื่อ Redis ถึงmaxmemoryขีด จำกัด มันจะเริ่มลบข้อมูลหรือไม่

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

หลังจากรีสตาร์ทเซิร์ฟเวอร์ Redis

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

รุ่น 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 เป็นเพียง60.59636307 MBรายงานโดยrdbtools นี่เป็นปริมาณ 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

คำตอบ:


8
  1. ใช้maxmemoryเพื่อตั้งค่าขีด จำกัด ว่าฐานข้อมูล Redis ของคุณจะสามารถเติบโตได้เช่นกัน ความล้มเหลวในการทำเช่นนั้น Redis จะเติบโตขึ้นจนกว่า OS จะฆ่ามันเมื่อหน่วยความจำหมด (ต่อประสบการณ์ปัจจุบันของคุณ)
  2. การใช้งานmaxmemoryควรจะควบคู่ไปกับmaxmemory-policy- คุณสามารถเลือกนโยบายการขับไล่ที่แตกต่างกันขึ้นอยู่กับความต้องการของกรณีการใช้งานของคุณ ตัวอย่างเช่นหากคุณใช้allkeys-lruนโยบายการขับไล่ข้อมูล Redis จะเริ่มต้นการขับไล่ข้อมูล (ที่ใช้น้อยที่สุด) เมื่อmaxmemoryมาถึง หรือคุณสามารถสั่งให้ Redis ขับไล่เฉพาะข้อมูลที่หมดอายุด้วยนโยบายvolatile-lruหรือ volatile-randomท้ายสุดคุณสามารถตั้งค่านโยบายเป็นnoevictionแต่นั่นก็หมายความว่าเมื่อหน่วยความจำหมดเรดิสจะปฏิเสธการเขียนเพิ่มเติมด้วยข้อความ OOM

แก้ไข:

การปิดการใช้งาน swap ครั้งแรก - Redis และ swap ไม่ได้ผสมกันอย่างง่ายดายและนี่อาจทำให้เกิดความเชื่องช้า

นอกจากนี้ให้ทำfree -mแทนด้านบนเพื่อรับภาพเต็มสถานะ RAM ของคุณ ( http://www.linuxatemyram.com/ )


ขอบคุณฉันสับสนว่าทำไมการใช้งานหน่วยความจำยังคงเพิ่มขึ้น แต่การทำbgsaveและเริ่มต้นใหม่redis-serverทำให้การใช้หน่วยความจำลดลงเป็นค่าที่สมเหตุสมผลมากขึ้น 70 MB นี่อาจเป็นความจำรั่วหรือไม่?
Nyxynyx

เป็นไปได้ แต่ไม่น่าเป็นไปได้ (หรือคนอื่นจะรายงานว่า) ... มีโอกาสมากขึ้นปัญหาการกระจายตัว ครั้งต่อไปที่เกิดขึ้นโพสต์ผลลัพธ์ของ Redis ของINFO ALLคุณ หากการเดาของฉันถูกต้องความmem_fragmentation_ratioมุ่งมั่นจะสูงขึ้นไป
Itamar Haber

redis-serverhogs หน่วยความจำทั้งหมดและล้มเหลวทุกวัน กำลังจะใช้หน่วยความจำหมดแล้วดังนั้นฉันจึงบันทึกเอาท์พุทINFO ALLและเพิ่มลงใน OP mem_fragmentation_ratio:0.19
Nyxynyx

หากชุดข้อมูล redis ไม่เกิน 250MB และmaxmemoryตั้งค่าเป็น 1 GB หมายความว่าเมื่อการใช้ mem ของ redis มีค่าถึง 1GB การไล่จะยังลบข้อมูลอยู่หรือไม่ เนื่องจาก redis mem_fragmentation_ratioคือ0.19หมายความว่ามีการกระจายตัวมากเกินไปหรือมากเกินไปถูกเก็บใน swap หรือทั้งสองอย่าง? มีวิธีใดในการลดการกระจายตัว?
Nyxynyx

เมื่อเซิร์ฟเวอร์ Redis กำลังจะล่มเนื่องจาก OOM rdbtools แสดงว่าคีย์ใน redis ใช้เวลาเพียง 60MB เท่านั้น ดูเหมือนว่าการกระจายตัวที่รุนแรงอย่างยิ่ง? พิจารณาว่ากิน RAM 4.4GB ขึ้นไปและ Swap 22.4G
Nyxynyx

5

นี่คือการกระจายตัวของหน่วยความจำเกือบแน่นอนเนื่องจาก Redis เป็นที่รู้จักกันดีและเป็นที่รักในการผลิตและคุณอาจไม่พบหน่วยความจำรั่ว

คำแนะนำเกี่ยวกับการตั้งค่าขนาดของพูลจะไม่ช่วยในการแยกส่วน คุณจะต้องลดขนาด Redis โดยเฉพาะ - ต่ำกว่าขนาดหน่วยความจำจริงของคุณ - เนื่องจาก Redis ไม่สามารถอธิบายการแยกส่วนได้ - แต่ในแง่ของคำตอบสั้น ๆ คุณจะต้องทำเช่นนั้นและเริ่มวางแผนในการเริ่มต้นใหม่ เซิร์ฟเวอร์บ่อยครั้ง

กฎง่ายๆที่ฉันใช้กับระบบปฏิบัติการที่หลากหลายและฐานข้อมูลในหน่วยความจำคือคุณต้องการหน่วยความจำจริงของคุณถึง 2 เท่าและขนาดหน่วยความจำจะมีเสถียรภาพในอีกประมาณ 2 สัปดาห์

อย่างไรก็ตามขึ้นอยู่กับรูปแบบการจัดสรรที่แท้จริงของคุณและตัวจัดสรรหน่วยความจำที่คุณกำลังใช้

ตอนนี้ตัวจัดสรรหน่วยความจำที่ดีที่สุดที่ฉันพบสำหรับเซิร์ฟเวอร์คือ JEMalloc เราใช้งานที่Aerospikeเพื่อลดการกระจายตัวของหน่วยความจำระยะยาว JEMalloc มีคุณสมบัติที่ช่วยให้คุณสร้างหน่วยความจำ "เวที" (พูล) และการจัดสรรใด ๆ ให้เลือกพูลใดซึ่งจะให้การจัดสรรขนาดเท่ากันและจัดการการจัดสรรอายุการใช้งานของหน่วยความจำที่คล้ายกัน มันเป็นชัยชนะครั้งใหญ่สำหรับเราในกรณีที่คุณกำลังพูดคุย

เอ็นจิ้น Zend PHP นั้นมีความซับซ้อนในเรื่องนี้เนื่องจากการจัดสรรทั้งหมดภายในเอ็นจิ้นนั้นอาจอยู่ในหน่วยความจำต่อธุรกรรมหรือหน่วยความจำระดับโลก หน่วยความจำสำหรับการทำธุรกรรมแต่ละรายการนั้นจะถูกปล่อยให้เป็นอิสระในช่วงท้ายของการทำธุรกรรมดังนั้นจึงมีประสิทธิภาพมาก

หากคุณอยู่ใน Linux ตัวจัดสรรหน่วยความจำเคอร์เนล (Clib) ได้ทำการบิดและหมุนเป็นจำนวนมากและเวอร์ชันที่คุณใช้อยู่จะเป็นตัวกำหนดจำนวนของการแตกแฟรกเมนต์เช่นเดียวกับรูปแบบแอปพลิเคชันจริง ตัวอย่างเช่นตัวจัดสรรบางตัวจะดีกว่ามากเมื่อคุณกำลังเติบโตวัตถุเล็กน้อยบางตัวแย่กว่ามาก อย่างน่าเศร้าแม้แต่การพูดคุยกับผู้ใช้ Redis คนอื่น ๆ หมายถึงการพูดถึงระบบปฏิบัติการที่คุณใช้อยู่

ความจริงที่ว่าคุณสามารถรีสตาร์ทเซิร์ฟเวอร์ (จากการคงอยู่) และรับหน่วยความจำของคุณกลับมาอาจหมายถึงการรั่วไหล แต่มีโอกาสมากที่จะกระจายตัว

  1. ไม่อนุญาตการสลับ (ดีกว่าเป็น OOM ดีกว่าเปลี่ยนเป็น redis)
  2. ลดขนาดหน่วยความจำของ Redis
  3. รีสตาร์ทตามกำหนดเวลา

คุณจะลดขนาดหน่วยความจำโดยการปรับได้maxmemoryอย่างไร?
Nyxynyx
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.