作為內(nèi)存數(shù)據(jù)庫,內(nèi)存空間的大小對于Redis來說是至關重要的。內(nèi)存越多意味著存儲的數(shù)據(jù)也會越多,內(nèi)存利用率的高低直接關系到Redis運行效率的高低
在實際研發(fā)過程中發(fā)現(xiàn),明明物理內(nèi)存很大,但是實際的內(nèi)存使用卻不是很理想(刪除了Redis數(shù)據(jù)后,采用top命令還是可以看到Redis占用的內(nèi)存很多)
那么這些刪除的數(shù)據(jù)為什么沒有按照預期釋放Redis的內(nèi)存呢?這是因為,當數(shù)據(jù)刪除后,Redis釋放的內(nèi)存空間會由內(nèi)存分配器管理,并不會立即返回給操作系統(tǒng)。所以,操作系統(tǒng)仍然會記錄著給Redis分配了大量內(nèi)存。具體分析請繼續(xù)往下看。
內(nèi)存碎片的定義:
根據(jù)操作系統(tǒng)的架構和Redisjemalloc分配策略,應用程序申請內(nèi)存大小必須是一塊連續(xù)的內(nèi)存地址空間的 N 個字節(jié)(N 表示需要向物理內(nèi)存申請大于等于實際需要存儲數(shù)據(jù)的內(nèi)存空間的大小)
雖然操作系統(tǒng)的剩余內(nèi)存空間足夠,但是應用程序申請的是一塊連續(xù)的地址空間的 N 個字節(jié),而實際已申請的剩余的內(nèi)存空間中沒有大小為 N 字節(jié)的連續(xù)空間,導致這塊剩余空間不可用,那么這些剩余空間對于內(nèi)存整體來說就是內(nèi)存碎片
內(nèi)存碎片的理解
假設操作系統(tǒng)為你分配了 32 字節(jié)的連續(xù)內(nèi)存空間,而你實際業(yè)務存儲數(shù)據(jù)的時候只需要 24 字節(jié)內(nèi)存空間
在下一次存儲數(shù)據(jù)時,實際數(shù)據(jù)需要 10 字節(jié)的內(nèi)存,剛剛申請剩下的 8 字節(jié)內(nèi)存無法保存 10 字節(jié)的數(shù)據(jù),應用程序不得不重新向操作系統(tǒng)再次申請 16 字節(jié)的連續(xù)空間來存儲 10 字節(jié)的數(shù)據(jù)
那么多余的 8 字節(jié)內(nèi)存空間以及第二次申請所剩的 6 字節(jié)的內(nèi)存空間,如果后續(xù)沒有辦法被分配存儲其它數(shù)據(jù),那么這些剩余的內(nèi)存空間就是內(nèi)存碎片
內(nèi)存碎片的類比
應用程序 A 需要保存 6 字節(jié)的數(shù)據(jù),jemalloc按分配策略向物理內(nèi)存申請 8 字節(jié)的連續(xù)空間,如果應用程序 A 不再保存新數(shù)據(jù),那么這多出來的 2 字節(jié)空間就是內(nèi)存碎片

應用程序 A 需要再保存 6 字節(jié)的數(shù)據(jù),由于上面申請的內(nèi)存只有 2 字節(jié)的連續(xù)空間,不夠保存 6 字節(jié)的數(shù)據(jù),所以jemalloc按分配策略向物理內(nèi)存又申請了 8 字節(jié)的連續(xù)空間

根據(jù)上一步對jemalloc內(nèi)存分配策略的特性以及實際案例的理解,導致內(nèi)存碎片形成有內(nèi)因和外因兩個層面的原因。簡單來說,內(nèi)因就是操作系統(tǒng)的內(nèi)存分配機制,外因就是Redis的存儲特性。
內(nèi)因:內(nèi)存分配器的分配策略
內(nèi)存分配器的分配策略就決定了操作系統(tǒng)無法做到“按需分配”
內(nèi)存分配策略一般都是按固定大小來分配內(nèi)存,而不是完全按照應用程序申請的內(nèi)存大小來給程序分配內(nèi)存
Redis的分配器包括:libc、jemalloc、tcmalloc多種內(nèi)存分配器來分配內(nèi)存,默認使用的是jemalloc內(nèi)存分配器
以jemalloc分配策略為例(其它的內(nèi)存分配策略也存在類似問題):jemalloc的分配策略之一是按照一系列固定大小劃分內(nèi)存空間,例如:8字節(jié)、16 字節(jié)、32 字節(jié)、64 字節(jié)、…2KB、4KB、8KB等。當程序申請的內(nèi)存最接近某個固定值時,jemalloc會給它分配相應的大小的空間。這樣的分配方式本身是為了減少分配次數(shù)(如:應用程序需要申請 24 字節(jié)的內(nèi)存,那么jemalloc會取最近的 32 字節(jié)的連續(xù)內(nèi)存空間分配給應用程序)。
但是,如果Redis每次向分配器申請的內(nèi)存空間大小不一樣,這種分配方式就會有形成碎片的風險,而這正好來源于Redis的外因了
外因:Redis 鍵值對大小不一致和更新操作
Redis通常作為公用的緩存系統(tǒng)或者鍵值數(shù)據(jù)庫對外提供服務,不同的業(yè)務應用的數(shù)據(jù)都可以保存在Redis中,這就會帶來不同大小的鍵值對。這樣一來,Redis申請內(nèi)存空間分配時,本身就會有大小不一的空間需求
上面也說到,內(nèi)存分配器只能按照固定大小分配內(nèi)存,所以,分配的內(nèi)存空間一般都會比申請的空間大一些,不會完全一致,這本身就會造成一定的碎片,降低內(nèi)存空間存儲效率,這就是第一個外因
應用程序?qū)︽I值對的修改和刪除,也會導致空間的擴容和釋放,一方面,如果修改后的鍵值對變大或者變小了,就需要占用額外的空間或者釋放不用的空間。另一方面,刪除的鍵值對就不再需要內(nèi)存空間了,此時,就會把空間釋放出來,形成空間剩余或者空閑

應用 A、B、C、D 分別保存了 3、1、2、2 字節(jié)的數(shù)據(jù),并占據(jù)了相應的內(nèi)存空間。
應用 D 刪除了 2 字節(jié),這塊連續(xù)空間剩余 2 字節(jié)內(nèi)存碎片
應用 A 修改為 4 字節(jié),由于空間不連續(xù),操作系統(tǒng)將應用 B 的數(shù)據(jù)拷貝到了別的空間,最后剩余 1 字節(jié)內(nèi)存碎片
Redis 查看內(nèi)存使用細節(jié) ——info memory
[root@localhost ~]# /opt/redis-6.0.9/src/redis-cli -h 192.169.5.107 -p 7003
192.169.5.107:7003>auth ******
OK
192.169.5.107:7003>info memory
# Memory
used_memory:254075496
used_memory_human:242.31M
used_memory_rss:381378560
used_memory_rss_human:363.71M
used_memory_peak:2939252680
used_memory_peak_human:2.74G
used_memory_peak_perc:8.64%
used_memory_overhead:34808840
used_memory_startup:1475344
used_memory_dataset:219266656
used_memory_dataset_perc:86.80%
allocator_allocated:254256784
allocator_active:325685248
allocator_resident:384983040
total_system_memory:16647553024
total_system_memory_human:15.50G
used_memory_lua:109568
used_memory_lua_human:107.00K
used_memory_scripts:1440
used_memory_scripts_human:1.41K
number_of_cached_scripts:4
maxmemory:10737418240
maxmemory_human:10.00G
maxmemory_policy:noeviction
allocator_frag_ratio:1.28
allocator_frag_bytes:71428464
allocator_rss_ratio:1.18
allocator_rss_bytes:59297792
rss_overhead_ratio:0.99
rss_overhead_bytes:-3604480
mem_fragmentation_ratio:1.50
mem_fragmentation_bytes:127344080
mem_not_counted_for_evict:2122
mem_replication_backlog:1048576
mem_clients_slaves:0
mem_clients_normal:266552
mem_aof_buffer:2560
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0Redis 重要內(nèi)存參數(shù)解讀
Redis已使用的內(nèi)存大小,單位ByteRedis已使用的內(nèi)存大小,單位MbRedis的物理內(nèi)存空間,單位ByteRedis的物理內(nèi)存空間,單位MbRedis當前的碎片率(減去 1 表示內(nèi)存碎片比例)Redis當前的碎片大小,單位ByteRedis 重要內(nèi)存參數(shù)關系
內(nèi)存碎片率的計算公式
內(nèi)存碎片率 = 已分配的內(nèi)存 / 實際使用的內(nèi)存
mem_fragmentation_ratio = used_memory_rss / used_memory1< mem_fragmentation_ratio<= 1.5經(jīng)驗值一般保持在1~1.5之間是最合理的,這是因為,剛才我們介紹的那些因素是難以避免的,畢竟,內(nèi)因的內(nèi)存分配器是一定要使用的,分配器策略是通用的不會輕易修改。而外因是由Redis存儲策略決定,也無法限制,所有存在內(nèi)存碎片也是正常的情況(內(nèi)存碎片率值越大代表內(nèi)存碎片率越嚴重)
# 按照當前的信息,內(nèi)存碎片率是 1.5 - 1 = 0.5(50%)
used_memory:254075496 ->242.31M
used_memory_rss:381378560 ->363.71M
mem_fragmentation_ratio:1.50
mem_fragmentation_bytes:127344080 ->121.44Mmem_fragmentation_ratio >1.5這表明內(nèi)存碎片率已經(jīng)超過了 50% 。一般情況下,這個時候就應該采取一些措施來降低內(nèi)存碎片率了
Redis內(nèi)存碎片雖然不會影響 Redis 性能,但是會增加內(nèi)存消耗,導致不必要的內(nèi)存浪費,導致Redis的內(nèi)存實際利用率變低
快速查看內(nèi)存碎片率
redis-cli -c -h 192.169.5.107 -p 7001 -a '******' info memory | grep mem_fragmentation_ratio解決方案一:推倒重來
該方案是最簡單的方式,直接推倒重來。也就是把Redis直接重啟就完事兒了,內(nèi)存一斷電全世界就清凈。但是這種最暴力省事的方式卻有很多隱患
生產(chǎn)環(huán)境這么搞,如果你沒有進行過持久化,數(shù)據(jù)就會丟失。如果有持久化的話,我們還需要通過AOF或者RDB文件進行數(shù)據(jù)恢復,那么恢復時長就得取決于你持久化文件的大小,在這個階段Redis是無法對外提供服務的
解決方案二:空間置換(搬家讓位、合并空間)
為避免內(nèi)存碎片率過大的問題,Redis 4.0-RC3版本開始支持自動整理Redis內(nèi)存碎片
查看Redis是否已經(jīng)開啟自動碎片整理機制
[root@localhost ~]# redis-cli -c -h 192.169.5.107 -p 7001 -a '******'
192.169.5.107:7001>config get activedefrag
1) "activedefrag"
2) "no"
192.169.5.107:7001>解析Redis內(nèi)存碎片自動整理機制
開啟內(nèi)存碎片清理
# 開啟或關閉自動內(nèi)存碎片整理機制
config set activedefrag yes以下條件滿足任意一個就會觸發(fā)內(nèi)存碎片清理
# 內(nèi)存碎片占用空間達到 500mb 的時候開始清理
config set active-defrag-ignore-bytes 500mb
# 內(nèi)存碎片率大于 1.5(50%)的時候開始清理
config set active-defrag-threshold-lower 50
# 內(nèi)存碎片率大于 2(100%) 的時候盡大清理
config set active-defrag-threshold-upper 100Redis自動內(nèi)存碎片整理機制可能會對Redis的性能產(chǎn)生影響,在處理的過程中,操作系統(tǒng)需要把多份數(shù)據(jù)拷貝到新位置,把原有空間釋放出來,這會帶來時間開銷。因為Redis是單線程,在數(shù)據(jù)拷貝時,Redis只能等著,這就導致Redis無法及時處理請求,性能就會降低。而且,有的時候,數(shù)據(jù)拷貝還需要注意順序,這種對順序性的要求,會進一步增加Redis的等待時間,導致性能降低。為了避免對正常請求的影響,同時又能保證性能。自動內(nèi)存碎片清理功能在執(zhí)行時,還會監(jiān)控清理操作占用的CPU時間,而且還設置了兩個參數(shù),分別用于控制清理操作占用的CPU時間比例的上、下限,既保證清理工作能正常進行,又避免了降低 Redis 性能。
# 內(nèi)存碎片清理所占用 CPU 時間的比例不低于 20%,保證清理能正常開展
config set active-defrag-cycle-min 20
# 內(nèi)存碎片清理所占用 CPU 時間的比例不高于 50%,一旦超過則停止清理,從而避免在清理時,大量的內(nèi)存拷貝阻塞 Redis,導致其它請求延遲
config set active-defrag-cycle-max 50P.S
如果采用的是高可用的Redis集群架構的話,也可以將碎片率過高的主節(jié)點切換為從節(jié)點,以便進行安全重啟
內(nèi)存碎片自動清理涉及內(nèi)存拷貝,這對Redis而言,是個潛在的風險。如果在實踐過程中遇到Redis性能變慢,記得通過日志看下是否正在進行碎片清理。如果Redis的確正在清理碎片,那么,建議你調(diào)小active-defrag-cycle-max的值,以減輕對正常請求處理的影響。
Redis在進行內(nèi)存碎片整理時,由于是主線程操作的,所以這塊也是一個影響Redis性能的風險點
開啟Redis內(nèi)存碎片自動整理機制
# 1、登錄 Redis 集群
redis-cli -c -h 192.169.5.107 -p 7001 -a '******'
# 2、查看內(nèi)存碎片自動整理機制是否開啟(默認關閉)
192.169.5.107:7001>config get activedefrag
1) "activedefrag"
2) "no"
# 3、開啟 Redis 自動內(nèi)存碎片整理機制
192.169.5.107:7001>config set activedefrag yes
OK
# 4、設置內(nèi)存碎片清理所占用 CPU 時間的比例不高于 75%
192.169.5.107:7001>config set active-defrag-cycle-max 75
OK
# 5、設置內(nèi)存碎片清理所占用 CPU 時間的比例不低于 25%
192.169.5.107:7001>config set active-defrag-cycle-min 25
OK
# 6、設置啟動活動碎片整理的最小碎片百分比,內(nèi)存碎片率大于 0.05 的時候開始清理
192.169.5.107:7001>config set active-defrag-threshold-lower 5
OK
# 7、設置內(nèi)存碎片超過 100%,盡大清理
192.169.5.107:7001>config set active-defrag-threshold-upper 100
OK
# 8、設置內(nèi)存碎片的字節(jié)數(shù)達到256M時開始清
192.169.5.107:7001>config set active-defrag-ignore-bytes 268435456
OK
# 9、寫入配置
192.169.5.107:7001>config rewrite
OK手動清理內(nèi)存碎片
memory purge內(nèi)存分配情況內(nèi)部統(tǒng)計報表
memory malloc-stats你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
分享題目:Redis性能優(yōu)化——內(nèi)存碎片-創(chuàng)新互聯(lián)
文章地址:http://chinadenli.net/article32/cejesc.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、微信公眾號、網(wǎng)站導航、Google、響應式網(wǎng)站、網(wǎng)站內(nèi)鏈
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容