(五)redis性能問題
A. redis客戶端
- redis客戶端通信
- redis新版本對于網(wǎng)絡請求進行多線程處理,收到請求后redis實際處理數(shù)據(jù)依然為單線程模式双谆。
- redis客戶端同服務端間的通信基于tcp協(xié)議返干。
- jedis客戶端
- 開發(fā)階段將jedis的jar包加入project中兴枯,或使用maven添加依賴。
- jedis直連模式
- 是默認方式矩欠,但每次使用都會新建tcp連接财剖。
- jedis直連簡單方便,但存在對象線程不安全的問題癌淮,適用于少量連接的情況躺坟。
- jedisPool模式
- 生產(chǎn)多采用該方式,預先生成幾個jedis對象于pool中该默,這些對象保持長連接狀態(tài)瞳氓。
- 具體使用時,用getJedisFromPool方法獲取對象栓袖,再完成后續(xù)實際操作匣摘。
- 向jedisPool借用jedis對象是本地操作,并無網(wǎng)絡開銷裹刮∫舭瘢控制pool的大小可以有效確定并發(fā)的壓力,遠小于新建tcp的方式捧弃。
B. redis內(nèi)存理解
- 概述:redis所有實時使用的數(shù)據(jù)都存儲于內(nèi)存中赠叼,持久化文件用于備份恢復。本小節(jié)九內(nèi)存消耗违霞、內(nèi)存管理 & 優(yōu)化進行闡述分析嘴办。
1. 內(nèi)存消耗
-
內(nèi)存使用統(tǒng)計
info memory
:查看內(nèi)存相關指標,重點需要關注的是used_memory_rss, used_memory & 它們的比值mem_fragmentation_ratio买鸽。-
閾值注意點
- mem_fragmentation_ratio > 1時涧郊,說明redis占用OS的內(nèi)存并非全是數(shù)據(jù)存儲消耗的,是內(nèi)存碎片消耗的眼五,兩者相差很大則說明碎片率很嚴重妆艘;
- mem_fragmentation_ratio < 1時,說明內(nèi)存不足時OS進行swap看幼,讓硬盤臨時替代成內(nèi)存給redis使用批旺,這導致redis性能急劇下降。
-
核心指標說明
屬性名 屬性說明 used_memory_human used_memory可讀顯示 used_memory_rss 操作系統(tǒng)下诵姜,redis進程占用的物理內(nèi)存總量 mem_fragmentation_ratio used_memory_rss / used_memory汽煮,大于1就有碎片;小于1則說明有swap給redis用
-
內(nèi)存消耗分類
- 自身內(nèi)存:redis空進程自身消耗內(nèi)存很少棚唆,通常used_memory_rss在3M左右暇赤,used_memory則約800kb。
- 對象內(nèi)存:最主要消耗內(nèi)存的部分瑟俭,存儲用戶所有數(shù)據(jù)翎卓。一個對象由key和value兩部分組成。
- 緩沖內(nèi)存:緩沖內(nèi)存包括客戶端緩沖摆寄、復制積壓緩沖區(qū) & AOF緩沖區(qū)失暴。在客戶端連接數(shù)過大時,可能會造成redis內(nèi)存飆升微饥。
- 內(nèi)存碎片:redis默認內(nèi)存分配器是jemalloc逗扒,一般采用固定范圍的內(nèi)存塊分配,將內(nèi)存分為小欠橘、大矩肩、巨大三個范圍。頻繁的更新操作(append肃续、setrange等)黍檩、大量過期key刪除易導致碎片出現(xiàn)叉袍。建議重啟節(jié)點完成碎片整理。
-
子進程內(nèi)存消耗
- 場景:在AOF或RDB時刽酱,fork的子進程理論上會需要和父進程一樣的內(nèi)存空間喳逛。基于linux的copy-on-write技術棵里,父子進程可共享物理內(nèi)存頁润文。但在接受寫請求時,父進程仍然需要對修改內(nèi)容所在的內(nèi)存頁進行復制以完成寫操作殿怜。
- THP:transparent huge pages機制在linux2.6.38后出現(xiàn)典蝌,默認開啟,導致復制內(nèi)存頁從4kb變成2mb头谜。若有大量寫請求骏掀,這會導致內(nèi)存消耗急劇上升。
2. 內(nèi)存管理
設置內(nèi)存上限目的:防止所用內(nèi)存超出服務器物理內(nèi)存乔夯,一般情況下設置合理的
maxmemory
砖织,保證機器預留20 - 30%閑置內(nèi)存。動態(tài)調(diào)整內(nèi)存上限:
config set maxmemory 10g
&config rewrite
末荐。注意侧纯,一旦使用內(nèi)存上限調(diào)整就會激活內(nèi)存回收。-
內(nèi)存回收策略
-
過期對象回收:精準維護每個key過期會消耗大量cpu資源甲脏,對單線程的redis來說成本過高眶熬,一般有兩種模式解決。
- 惰性刪除:客戶端讀取到expired的key時块请,會執(zhí)行刪除操作并返回空值娜氏。該方式雖然節(jié)約cpu,但存在內(nèi)存泄漏問題墩新。若expired的key一直未被讀取就不會被刪除贸弥,內(nèi)存無法釋放。
- 定時任務刪除:redis內(nèi)部維護一個定時任務海渊,默認每秒運行10次绵疲,通過配置
hz
完成。默認使用慢模式運行臣疑,每個數(shù)據(jù)庫空間隨機找20個key檢查盔憨,發(fā)現(xiàn)過期時刪除對應的key-value。若本次檢查中超過25%的key過期讯沈,則繼續(xù)檢查20個key郁岩,直到低于25%或者運行超時才結束回收的循環(huán)。
-
內(nèi)存溢出控制策略:基于
mexmemory-policy
進行策略的選取 & 確認,可使用config set maxmemory-policy xxx
進行動態(tài)配置问慎。策略名 策略具體內(nèi)容 noeviction 默認策略萍摊,不刪除任何數(shù)據(jù),拒絕所有寫入操作并向客戶端返回OOM錯誤信息蝴乔。 volatile-lru 根據(jù)LRU算法刪除expired的key记餐,直到空間足夠為止驮樊。若沒有可刪除對象薇正,則回退成noeviction策略。 allkeys-lru 根據(jù)LRU刪除key囚衔,不管有無設置超時屬性挖腰。 allkeys-random 隨機刪除所有key。 volatile-random 隨機刪除expired的key练湿。 volatile-ttl 根據(jù)key-value的ttl屬性猴仑,刪除最近將要過期的數(shù)據(jù),若沒有復合的對象回退noeviction策略肥哎。
-
4. 內(nèi)存優(yōu)化
- 概述:redis所有存儲數(shù)據(jù)都是用redisObject封裝辽俗,有下方幾個字段
字段 | 含義 |
---|---|
type | 當前對象數(shù)據(jù)類型,主要為string篡诽,hash崖飘,list,set & zset杈女。注意朱浴,key都是string類型。 |
encoding | redis內(nèi)部編碼類型达椰,代表其內(nèi)部采用的數(shù)據(jù)結構翰蠢。 |
lru | 記錄對象最后一次被訪問的時間。 |
refcount | 記錄當前對象被引用的次數(shù)啰劲,若refcount=0就可以被安全回收梁沧。 |
*ptr | 和對象的數(shù)據(jù)內(nèi)容相關,若為整數(shù)直接存儲數(shù)據(jù)蝇裤;若非整數(shù)則表示指向數(shù)據(jù)的指針廷支。 |
- 縮減對象:縮減key和value的長度是最直接的方法。
- 共享對象池:redis內(nèi)部維護0-9999的整數(shù)對象池猖辫,可通過
object refcount
查看引用次數(shù)驗證是否啟動整數(shù)對象池技術酥泞。- 效果:使用該技術后,數(shù)據(jù)內(nèi)存使用率可降低30%以上啃憎。
- 限制:使用maxmemory-policy中的lru策略時(無論allkeys或volatile)芝囤,redis禁止使用共享對象池。因為共享時,lru字段也需要共享悯姊,導致無法獲取每個對象最后的訪問時間羡藐。
- 其他:字符串的優(yōu)化(預分配機制、字符串重構)悯许,encoding類型優(yōu)化 & 控制key數(shù)量仆嗦。
C. redis緩存設計
- 概述
- 緩存收益
- 加速讀寫。
- 降低后端負載壓力先壕,例如減少數(shù)據(jù)庫訪問量和復雜計算瘩扼。
- 成本代價
- 數(shù)據(jù)不一致性:緩存層和存儲層數(shù)據(jù)在一定時間窗口內(nèi)有數(shù)據(jù)不一致問題,需要存儲層更新至緩存層垃僚。
- 代碼維護成本:新增對于緩存層的代碼 & 緩存與存儲邏輯的代碼集绰。
- 運維成本增加,維護集群狀態(tài)谆棺。
- 緩存收益
1. 緩存更新策略
- LRU栽燕、LFU或FIFO算法
- 使用場景:key數(shù)量過多,消耗內(nèi)存達到設置的maxmemory閾值時改淑,會對key-value的剔除碍岔。
- 問題:產(chǎn)生一致性問題較嚴重,刪除后導致緩存層數(shù)據(jù)缺失且運維人員無法及時得知刪除信息朵夏。
- 配置方法:設置maxmemory大小 & maxmemory-policy算法即可蔼啦。
- 超時剔除
- 使用場景:緩存數(shù)據(jù)配置了expire命令,保障key-value在一段時間后失效刪除侍郭。
- 問題:在一定窗口內(nèi)有一致性問題询吴。
- 主動更新
- 使用場景:對數(shù)據(jù)一致性要求較高時使用,若真實數(shù)據(jù)更新立即更新緩存層亮元。
- 問題:維護成本較高猛计,需開發(fā)正完成更新邏輯。
- 案例實踐建議
- 低一致性業(yè)務:使用最大內(nèi)存淘汰算法即可爆捞。
- 高一致性業(yè)務:超時剔除+主動更新奉瘤,結合使用。
2. redis雪崩
- 現(xiàn)象:redis的大量的key在某個時間段失效或redis服務不可用煮甥,導致需要直接訪問數(shù)據(jù)庫盗温,大量請求沖擊database。
- 解決方案
- 不要設置固定過期時間成肘,盡量在setex時采用隨機的ttl卖局。
- 保證緩存層服務高可用性,基于分布式集群架構双霍。
3. redis緩存穿透
- 現(xiàn)象:redis和database都不存在該key對應的數(shù)據(jù)砚偶,但用戶不斷發(fā)起對該類數(shù)據(jù)的請求導致database掛掉批销,比如持續(xù)大量請求uid的-1的對應數(shù)據(jù)。
- 解決方案
- 緩存空對象染坯,后續(xù)再訪問該key可基于緩存層返回null值均芽,存在問題是導致緩存了更多的無用key & 數(shù)據(jù)不一致問題。該策略適用于數(shù)據(jù)命中不高单鹿,數(shù)據(jù)頻繁變化實時性高的場景掀宋。
- 設置database的并發(fā)鎖,防止大量請求在database上進行仲锄。
- 設置攔截器劲妙,類似bitmaps或bloom filter,不存在的uid直接攔截在redis層昼窗,不可達database是趴。適用于數(shù)據(jù)命中不高,數(shù)據(jù)相對固定的場景澄惊。
4. redis擊穿
- 現(xiàn)象:redis中沒有該key但是database中有,一般出現(xiàn)場景為某個hot key過期富雅,大量用戶并發(fā)查詢該key導致直接沖擊database掸驱。
- 解決方案
- hot key重建
- 定義:緩存失效的瞬間,有大量線程來重建緩存没佑。
- 負面效應:重建時后段附在加大毕贼,所以需要減少重建緩存的次數(shù)。
- 設置互斥鎖
- 互斥鎖通過競爭對資源獨占使用蛤奢,執(zhí)行順序是亂序的鬼癣。該方法利用setex或setnx實現(xiàn),確保只有一個線程重建緩存啤贩,其他線程都在等待狀態(tài)待秃。
- 同步鎖更高級,能保證執(zhí)行順序痹屹。
- 設置hot key永不過期
- 直接不設置過期時間章郁,或者設置一個邏輯過期時間,超過該周期后單獨使用一個線程重建緩存志衍。
- 但容易出現(xiàn)數(shù)據(jù)一致性問題暖庄。
- hot key重建
D. pipeline & transaction
- pipeline
- 概述:管道技術是客戶端行為,對redis server透明楼肪,server不知道發(fā)過來的請求是普通的還是pipeline形式的培廓。
- 使用效果:類似批量的方式缺失降低了網(wǎng)絡開銷,利用多個命令一次網(wǎng)絡發(fā)送提升了效率春叫〖缒疲基于hgetall的操作并沒有對應的mhgetall可用俘侠,此時pipeline可派上用場。
- transaction
- 概述:事務是redis server行為蔬将,當客戶端使用了MULTI命令后把客戶端對象設置為特殊狀態(tài)爷速。客戶端發(fā)出的命令會被緩存到server霞怀,等到EXEC再執(zhí)行惫东。
- 使用效果:客戶端在exec前的命令,都會被server返回一個queued毙石,事務模式能提高網(wǎng)絡使用效率廉沮,但不支持回滾。
E. 異常排查 & 配置優(yōu)化
1. Jedis客戶端常見異常
-
無法從連接池獲取到連接:jedisPool的jedis個數(shù)有限(默認8個)徐矩,若他們都被使用時滞时,那么第9個來調(diào)用的就會報錯。
- 報錯信息:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get get a resource from the pool
- 高并發(fā)場景下滤灯,連接池的jedis個數(shù)可進行調(diào)整坪稽。若我們認為一個jedis每條命令處理時間5ms,1s單個jedis對象極限能處理200個命令鳞骤,8個jedis的qps極限約為200*8=1600窒百。若qps預計在1.6w的話,需將jedis數(shù)量調(diào)整至80豫尽。
- 若存在慢查詢篙梢,那么這個jedis也會被長時間占用不歸還,可能造成該異常美旧。
- 報錯信息:
-
讀寫超時
- 報錯信息:
redis.clients.jedis.exceptions.JedisConnectionException & java.net.SocketTimeoutException: read timed out
- 讀寫超時設置的太短渤滞。
- 讀寫操作耗時太久,需優(yōu)化具體邏輯榴嗅。
- 報錯信息:
-
連接超時
- 報錯信息:
redis.clients.jedis.exceptions.JedisConnectionException & java.net.SocketTimeoutException: connect timed out
- 連接超時設置太短妄呕,修改參數(shù)
jedis.getClients().setConnectionTimeout(A larger value)
。 - redis發(fā)生阻塞录肯,tcp-backlog滿了導致新連接失敗趴腋。
- 服務端與客戶端間的網(wǎng)絡存在問題。
- 報錯信息:
-
客戶端緩沖區(qū)異常
- 報錯信息:
redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream
- jedis輸出的緩沖區(qū)大小偏小论咏,若set bigkey优炬,可能就會報錯.
- jedis不正常并發(fā)讀寫,被多個線程操作厅贪。
- 報錯信息:
-
其他場景異常
lua腳本正在執(zhí)行:正在運行l(wèi)ua腳本時會報錯蠢护。
加載持久化文件:正在加載rdb文件時會報錯。
內(nèi)存使用情況超出maxmemory:若redis使用內(nèi)存過多养涮,超出預設的maxmemory會報錯OOM葵硕,需要擴容調(diào)整眉抬。
-
客戶端連接數(shù)過大:超出預設的maxclients時,會報錯懈凹,具體解決手段有兩個大方向
客戶端:若maxclients設置的閾值不小蜀变,則一般是客戶端使用不當導致的,可下線部分應用節(jié)點先降低總連接數(shù)介评。
服務端:基于服務端一般是高可用模式库北,可采用故障轉移機制,下線有問題的redis節(jié)點们陆,完成主從切換后再排查寒瓦。
-
實際案例
- redis內(nèi)存陡增:master內(nèi)存狂增幾乎打滿maxmemory,但slave內(nèi)存幾乎無變化坪仇,導致無法寫入新數(shù)據(jù)杂腰,報出OOM的錯誤。
- 確有大量key寫入:基于slave內(nèi)存無變化的現(xiàn)象椅文,可初步判定主從間復制出現(xiàn)問題喂很,比較兩側dbsize進行復核。
- 其他原因:造成master壓力大可能是jedis等客戶端緩沖區(qū)導致的雾袱,比如客戶端使用monitor命令恤筛,可使用info clients確認。
- 客戶端周期性超時:redis服務端無明顯異常芹橡,可發(fā)現(xiàn)部分慢查詢。
- 網(wǎng)絡原因?qū)е略摤F(xiàn)象出現(xiàn)望伦。
- redis服務端自身問題林说,需查log文件再確認。
- 查詢慢查詢時間點屯伞,查看客戶端日志中是否存在
redis.clients.jedis.exceptions.JedisConnectionException
&java.net.SocketTimeoutException: connect timed out
的錯誤信息腿箩。
- redis內(nèi)存陡增:master內(nèi)存狂增幾乎打滿maxmemory,但slave內(nèi)存幾乎無變化坪仇,導致無法寫入新數(shù)據(jù)杂腰,報出OOM的錯誤。
2. 運維配置優(yōu)化
a. Linux - 內(nèi)存分配控制overcommit
定義:Linux對于大部分申請內(nèi)存的請求回復為yes,便于運行更多的程序劣摇。大多數(shù)情況下珠移,申請完內(nèi)存后并不會馬上使用內(nèi)存,該技術即為overcommit末融。本處內(nèi)存代表钧惧,物理內(nèi)存+swap之和。
-
參數(shù)具體可選值
值 含義 0 表示內(nèi)核將檢查是否有足夠的可用內(nèi)存勾习,若有足夠內(nèi)存浓瞪,則申請通過;若沒有足夠的可用內(nèi)存巧婶,則申請失敗乾颁。 1 表示內(nèi)核允許超量使用內(nèi)存直到耗盡涂乌。 2 表示內(nèi)核絕不過量使用內(nèi)存(never overcommit),系統(tǒng)整個內(nèi)存地址空間不超過swap+50%RAM值英岭。 常見場景:redis啟動時湾盒,日志中出現(xiàn)
WARNING overcommit is set to 0!...
-
redis中的解決方案:上述日志提示修改
vm.overcommit_memory=1
,便于持久化操作的fork能在低內(nèi)存下執(zhí)行成功诅妹。- 獲取參數(shù):
cat /proc/sys/vm/overcommit_memory
- 設置參數(shù):
echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
罚勾,并進行sysctl vm.overcommit_memory=1
- 獲取參數(shù):
b. Linux - 內(nèi)存交換swappiness
定義:物理內(nèi)存不足時將一部分內(nèi)存頁進行swap操作——將硬盤暫時作內(nèi)存使用。若遇到高并發(fā)漾唉、高吞吐的應用荧库,此時磁盤IO會成為系統(tǒng)瓶頸。在Linux 下赵刑,并不是物理內(nèi)存使用完才會使用swap分衫,具體何時使用swap基于swappiness參數(shù)。
-
參數(shù)含義:swappiness取值范圍在 0 -100間般此,默認值為60蚪战,該值越大意味著操作系統(tǒng)使用swap的概率越高。
值 策略 0 Linux3.5及更新版本铐懊,寧愿OOM killer也不用swap邀桑。 1 Linux3.5及更新版本,寧愿用swap也不用OOM killer科乎。 60 默認值壁畸。 100 Linux會主動使用swap。 -
設置方法
- 配置swappiness:使用
echo {bestvalue} > /proc/sys/vm/swapiness
- 確保重啟依然生效:使用
echo vm.swappiness={bestvalue} >> /etc/sysctl.conf
- 配置swappiness:使用
-
常見場景
- redis在物理內(nèi)存充足時運行極快茅茂,物理內(nèi)存不足時該配置可避免redis死掉捏萍。
- 若redis時高可用的情況下,寧愿死掉也不要使用swap空闲,因為這會導致阻塞令杈。
- 除了直接free -h查看swap情況,亦可參考mem_fragmentation_ratio碴倾,若 < 1則存在redis使用swap的情況逗噩。
c. Linux - THP
- 定義:Linux kernel在2.6.38后增加了THP特性,默認開啟跌榔。全稱Transparent Huge Pages异雁,支持大內(nèi)存頁2MB分配,可加快fork子進程的速度矫户,但fork操作后每個內(nèi)存頁從4KB增加到2MB片迅,會大幅度增加重寫期間父進程的內(nèi)存消耗,每次寫命令引起的復制內(nèi)存頁單位放大了512倍皆辽。
- 參數(shù)設置
- 禁用THP特性:使用命令
echo never > /sys/kernel/mm/transparent_hugepage/enabled
- 確保重啟依然生效:編輯開機配置文件/etc/rc.local柑蛇,追加禁用THP特性命令——
echo never > /sys/kernel/mm/transparent_hugepage/enabled
- 禁用THP特性:使用命令
- 常見場景
- redis啟動時日志中出現(xiàn)
WARNING you have Transparent Huge Pages (THP) support enabled in your kernel...
芥挣,需手動禁用THP。 - 部分版本的Linux 未把THP放入/sys/kernel/mm/transparent_hugepage/enabled耻台,例如Red Hat 6以上的版本即將THP配置放入/sys/kernel/mm/redhat_transparent_hugepage/enabled空免,但redis將檢查THP的位置寫死導致不能成功檢測THP問題并將之暴露于日志中,但THP的問題依舊存在需要手動調(diào)整盆耽。
- redis啟動時日志中出現(xiàn)
d. Linux - OOM Killer
- 定義:在內(nèi)存不足時選擇性地殺掉用戶進程蹋砚,OOM Killer會為每個用戶進程設置一個權值,該值越高越容易被優(yōu)先干掉摄杂。
- 參數(shù)設置
- 參數(shù)位置:每個進程的權值位于/proc/{pid}/oom_score中坝咐,受到/proc/{pid}/oom_adj的控制。
- oom_adj
- 當oom_adj設置為最小值時析恢,該進程不會被干掉墨坚。不同Linux 版本的最小值不同,可參考Linux 源碼中的oom.h(-15到-17)映挂。
- 設置方法為
echo {value} > /proc/{pid}/oom_adj
- 適用場景:為保證redis在主機內(nèi)存使用率接近滿載時仍然能存活下來泽篮,可將redis進程對應的oom_adj設置成最小值。
e. Linux - 其他參數(shù)
-
NTP
- 定義:網(wǎng)絡時間協(xié)議柑船,全稱network time protocol帽撑,保證不同機器的時鐘一致性。
- 場景:redis集群有多節(jié)點組成鞍时,涉及多主機問題亏拉。時鐘不一致會導致redis集群內(nèi)問題排查難度提升,例如無法有效判別clutser故障轉移逆巍。
- 解決手段:建議每小時使用一次時鐘同步专筷,保障其集群內(nèi)時鐘一致性。具體為
0 * * * * /usr/sbin/ntpdate ntp.xx.com > /dev/null 2>&1
-
ulimit
-
定義:查看和設置系統(tǒng)當前用戶進程的資源數(shù)蒸苇,常用命令
ulimit -a
,其展示效果可見下方吮旅。category unit value core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 61370 open files (-n) 4096 POSIX message queues (bytes, -q) 819200 max user processes (-u) 61370 -
場景
redis允許同時多個客戶端通過網(wǎng)絡進行連接溪烤,可通過服務端配置
maxclients
參數(shù)來進行具體客戶端數(shù)的限制。redis除了供給客戶端連接數(shù)所需的10000FD句柄庇勃,還需要32個FD供redis自身內(nèi)部使用檬嘀。
-
Linux系統(tǒng)下德崭,所有網(wǎng)絡連接都是文件句柄绊序,若當前open files為4096谆奥,則啟動redis時會有下方日志
You requested maxclients of 10000 requiring at least 10032 max file descriptors...Current maximum open files is 4096...
解決手段:將open files的值設置為65535劝赔,通過命令
ulimit -Sn 65535
實現(xiàn)达布。
-
-
TCP backlog
- 定義
- backlog是一個連接隊列,在Linux內(nèi)核2.2之前创淡,backlog包括半連接狀態(tài)和全連接狀態(tài)兩種隊列大刑汛;在Linux內(nèi)核2.2之后衷掷,分離為兩個backlog來分別限制半連接(SYN_RCVD狀態(tài))隊列大小和全連接(ESTABLISHED狀態(tài))隊列大小辱姨。
- 半連接狀態(tài):服務器處于Listen狀態(tài)時收到客戶端SYN報文時放入半連接隊列中,即SYN queue(服務器端口狀態(tài)為:SYN_RCVD)戚嗅。
- 全連接狀態(tài):TCP的連接狀態(tài)從服務器(SYN+ACK)響應客戶端后雨涛,到客戶端的ACK報文到達服務器之前,則一直保留在半連接狀態(tài)中懦胞;當服務器接收到客戶端的ACK報文后替久,該條目將從半連接隊列搬到全連接隊列尾部,即 accept queue (服務器端口狀態(tài)為:ESTABLISHED)躏尉。
- 場景:redis默認tcp-backlog值為511蚯根,若Linux系統(tǒng)的值小于511則會在啟動日志中出現(xiàn)
WARNING: THE TCP backlog setting of 511 cannot be ...
- 解決手段
- 查看系統(tǒng)值:通過命令
cat /proc/sys/net/core/somaxconn
查看accept queue具體值,redis不涉及修改syn queue的問題醇份,若想查看可通過cat /proc/sys/net/ipv4/tcp_max_syn_backlog
進行查詢稼锅。 - 修改:使用
echo 511 > /proc/sys/net/core/somaxconn
進行變更。
- 查看系統(tǒng)值:通過命令
- 定義
f. 數(shù)據(jù)恢復手段
- AOF機制恢復
- 場景:若誤操作flushall或flushdb導致數(shù)據(jù)丟失僚纷,需借助持久化文件進行恢復矩距。若開啟了
appendonly yes
,則誤操作僅在AOF文件中追加了一條操作記錄怖竭。 - 解決手段
- 若AOF文件重寫了锥债,則之前的數(shù)據(jù)就無法順利找回,所以需要調(diào)整
auto-aof-rewrite-percentage
&auto-aof-rewrite-min-size
阻止AOF自動重寫痊臭,并拒絕手動bgrewriteaof哮肚。 - 確保上方參數(shù)設置后,將AOF文件中的flush操作去掉广匙,并確保AOF文件格式正常以保障數(shù)據(jù)的順利恢復允趟。
- 若AOF文件重寫了锥债,則之前的數(shù)據(jù)就無法順利找回,所以需要調(diào)整
- 場景:若誤操作flushall或flushdb導致數(shù)據(jù)丟失僚纷,需借助持久化文件進行恢復矩距。若開啟了
- RDB機制恢復
- 前置配置:若rdb持久化設置中有自動策略,例如
save 900 1
這類鸦致,則因為flush一般涉及key value都較多潮剪,會導致RDB恢復基本無望。除非并無開啟rdb自動策略分唾,否則面對flush誤操作抗碰,rdb不能有效恢復數(shù)據(jù)。 - 解決手段:若redis沒有進行rdb自動策略绽乔,僅有手動的bgsave所得的rdb文件弧蝇,那么即可使用rdb文件恢復數(shù)據(jù),但相對數(shù)據(jù)完整性不如aof機制。
- 前置配置:若rdb持久化設置中有自動策略,例如
F. redis阻塞問題
- 概述
- redis屬于典型的單線程架構看疗,讀寫操作皆于唯一的主線程中完成沙峻。
- redis處于高并發(fā)場景時,主線程若出現(xiàn)阻塞則問題嚴重鹃觉,阻塞時jedis會拋出JedisConnectionException異常专酗。
- 阻塞內(nèi)因:不合理使用api或數(shù)據(jù)結構,cpu飽和盗扇、持久化阻塞(basave的fork瞬間或save持久化)祷肯。
- 阻塞外因:cpu競爭、內(nèi)存交換(swap)疗隶、網(wǎng)絡問題佑笋。
1. 內(nèi)因詳解
a. api或數(shù)據(jù)結構使用不合理
場景案例:redis正常場景下執(zhí)行命令速度極快(微妙級),若執(zhí)行
hgetall
命令且該hash類型的key是big key斑鼻,則執(zhí)行速度就會很慢蒋纬,屬于是典型的不合理使用api & 數(shù)據(jù)結構。-
慢查詢
- 定義:默認配置
slowlog-log-slower-than 10000
坚弱,即10ms以上的操作被判定為慢查詢蜀备,slowlog-max-len 128
默認存儲慢查詢?nèi)罩鹃L度為128條。 - 獲取結果:
slowlog get 10
荒叶,即獲得最近的10條慢查詢命令碾阁。
- 定義:默認配置
-
解決方案
定制慢查詢閾值:線上一般可設置1ms為慢查詢閾值,即
slowlog-log-slower-than 1000
些楣,該速度下單機redis的qps將被限制為1000左右脂凶。拓展慢查詢?nèi)罩鹃L度:增加日志長度幫助排查故障的原因,將
slowlog-log-slower-than
可設置為1000愁茁。其他:使用快速命令
hgetall
改成hmget
蚕钦,并禁用keys、sort命令鹅很,并將big key拆分嘶居。
-
大鍵big key問題
- 定義
- big key指value所占空間很大的key,一般地促煮,string類型的key食听,若其value大于10KB即為big key。其他類型的big key污茵,是因為包含的元素過多。
- 一個string類型的key葬项,value最大為512MB泞当;一個list類型的key,其value最多可存儲(2的32次方-1)個元素民珍。
- 危害
- 內(nèi)存空間不均:若在redis集群模式下襟士,bigkey必須被分配至某個節(jié)點盗飒,導致內(nèi)存空間使用不均勻。
- 阻塞:因為操作big key容易耗時過高陋桂,導致阻塞時間偏長逆趣。
- 網(wǎng)絡擁塞:每次獲取big key產(chǎn)生的網(wǎng)絡流量較大,占用帶寬嗜历。
- 檢測big key
- 被動收集:big key在被訪問時宣渗,出現(xiàn)異常日志。通過這種情況探測出的big key梨州,即為被動收集的模式痕囱。
- 主動檢測:使用
redis-cli -h xxx.xxx.xxx.xxx -p 6379 --bigkeys
探測,其本質(zhì)是使用scan漸進式遍歷暴匠,rdr也是很好的redis分析工具鞍恢,在從節(jié)點上操作時更合適的手段。
- 刪除big key
- string類型:該類的big key一般可以直接
del key
即可每窖,不會阻塞帮掉。 - hash、list窒典、set & sorted set:直接刪除依然會導致阻塞蟆炊,若為hash類型的場景下,可結合hscan逐步獲取進行刪除崇败。
- Redis4.0后特性:使用lazy delete free模式盅称,刪除big key不會阻塞。
- string類型:該類的big key一般可以直接
- 定義
-
熱鍵hot key問題
- 常見場景:熱點突發(fā)新聞后室、熱銷大賣商品會給系統(tǒng)帶來巨大流量缩膝,在集群模式下存儲這些信息的redis節(jié)點會出現(xiàn)流量不均勻的情況,存儲熱點消息的節(jié)點出現(xiàn)QPS壓力偏大的問題岸霹。
- 判別方法
- 代理端:若客戶端對redis服務端的請求疾层,是基于Twemproxy/Codis這樣的分布式架構,則所有的請求都通過代理端再達到服務端贡避,可在代理處完成數(shù)據(jù)統(tǒng)計分析big key痛黎。
- 服務端:使用monitor在server處分析客戶端大量請求中的hot key,但是使用monitor會影響redis性能刮吧,且該方法是針對redis單節(jié)點進行的湖饱,若為集群模式還需要聚合統(tǒng)計。
- 解決方案
- 拆分復雜數(shù)據(jù)結構:若為二級結構(list杀捻、hash等)井厌,等可拆分成若干key-value,分散至redis集群的各個節(jié)點上。
- 遷移:將hot key所在的slot單獨放置到一個redis節(jié)點仅仆。
- 本地緩存:將hot key放在業(yè)務端的本地緩存中器赞,處理速度更快且降低redis壓力,但需要注意數(shù)據(jù)一致性問題墓拜。
b. cpu飽和
- 簡述:redis處理命令時為單線程港柜,僅有主線程處理業(yè)務,所以可用cpu數(shù)為1咳榜。若單核cpu的主機夏醉,則使用率接近100%,可使用top命令或
redis-cli -h xxx.xxx.xxx.xxx -p 6379 --stat
查看使用情況贿衍,stat中connections是歷史總連接數(shù)累計授舟,實時數(shù)據(jù)可看lsof -i:6379 | wc -l
。 - 解決方案
- 若看到qps已經(jīng)足夠高(一般可達6w)贸辈,那么此時垂直優(yōu)化較困難释树,建議通過集群化完成水平擴展。
- 若發(fā)現(xiàn)qps僅數(shù)千甚至更低擎淤,那么大概率使用了高時間復雜度的命令奢啥,需修改業(yè)務方法。
- 內(nèi)存優(yōu)化過度嘴拢,可用
info commandstats
檢查桩盲,比如hset耗時過長,為節(jié)約內(nèi)存空間放寬ziplist的使用條件席吴,可修改hash-max-ziplist-entries
&hash-max-ziplist-values
赌结。
c. 持久化導致堵塞
前置說明:不考慮使用
save
的場景,這種模式會導致長時間redis堵塞孝冒。fork阻塞:rdb和aof重寫恢復數(shù)據(jù)時柬姚,主線程會fork生成子進程,子進程再完成實際的重寫庄涡。若fork耗時過長量承,則可能導致阻塞出現(xiàn);
aof阻塞:開啟aof后穴店,文件刷盤的方式一般為1s一次撕捍,后臺線程對aof文件進行fsync操作,當磁盤壓力大時fsync會需要等待泣洞,其主要緣由是磁盤壓力偏大忧风。
2. 外因詳解
- cpu競爭
- 進程競爭:redis屬于cpu密集型應用,雖然一般情況下cpu不是性能瓶頸球凰,但是不建議和其他服務部署在一臺主機上阀蒂。
- 綁定cpu:redis為盡可能地充分利用多核cpu该窗,通常會一臺機器部署多個redis實例。此場景下蚤霞,不同redis進程綁定對應的cpu可降低上下文切換的開銷,但是某個實例進行rdb或者aof持久化時义钉,可能因為綁定cpu會導致壓力過大昧绣。
- 內(nèi)存交換swap
- 簡述:swap空間即內(nèi)存空間不足時,將磁盤充當內(nèi)存使用捶闸。
- 甄別手段
- 找到redis pid夜畴,通過
redis-cli -p 6379 info server | grep process_id
; - 接著根據(jù)id查詢swap信息删壮,使用
cat /proc/xxxx/smaps | grep swap
贪绘。正常情況下應該都是0kb或者少量4kb。
- 找到redis pid夜畴,通過
- 網(wǎng)絡問題
- 拒絕連接:網(wǎng)絡割接或帶寬耗盡時的網(wǎng)絡閃斷(
sar -n DEV
查看)央碟,redis超過默認1w的maxclients連接數(shù)税灌,或者是進程限制打開文件數(shù)(ulimit -n)、backlog隊列溢出亿虽。 - 網(wǎng)絡延遲:客戶端到redis服務器之間網(wǎng)絡延遲菱涤,可使用
redis-cli -h xxx.xxx.xxx.xxx -p 6379 --latency
核驗。 - 網(wǎng)卡軟中斷:高并發(fā)下單個網(wǎng)卡隊列只能使用一個cpu洛勉,新版redis已經(jīng)改進網(wǎng)絡方面效率問題粘秆。
- 拒絕連接:網(wǎng)絡割接或帶寬耗盡時的網(wǎng)絡閃斷(