欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

redis性能優(yōu)化之生產(chǎn)中實(shí)際遇到的問題及排查總結(jié)

 更新時(shí)間:2022年12月22日 08:47:46   作者:_crisis  
這篇文章主要介紹了redis性能優(yōu)化之生產(chǎn)中實(shí)際遇到的問題及排查總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

背景

redis-K,V數(shù)據(jù)庫(kù),因其高性能的操作性和支持豐富的數(shù)據(jù)結(jié)構(gòu),目前大量被用于銜接應(yīng)用層和關(guān)系數(shù)據(jù)庫(kù)中間的緩存層。

隨著使用的場(chǎng)景越來越多,和數(shù)據(jù)量快速的遞增,在生產(chǎn)環(huán)境中經(jīng)常會(huì)遇到相關(guān)的性能瓶頸問題。

這時(shí)候就需要借助一些外部的手段來分析瓶頸根源在哪,對(duì)癥下藥提升性能。

常見性能問題及問題分析過程

1、生產(chǎn)系統(tǒng)剛開始運(yùn)行階段,系統(tǒng)穩(wěn)定。但是運(yùn)行一段時(shí)間后,發(fā)現(xiàn)部分時(shí)間段系統(tǒng)接口響應(yīng)變慢。查看客戶端日志經(jīng)常會(huì)出現(xiàn)這樣的錯(cuò)誤:

redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out。

2、生產(chǎn)環(huán)境長(zhǎng)時(shí)間的運(yùn)行后,經(jīng)常會(huì)有接口返回?cái)?shù)據(jù)失敗的情況,或者是從監(jiān)控上發(fā)現(xiàn)數(shù)據(jù)庫(kù)壓力某一時(shí)間暴增。查看客戶端日志發(fā)現(xiàn)這樣的錯(cuò)誤:

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

3、突然間服務(wù)不能訪問,返回錯(cuò)誤:

redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.

當(dāng)然在實(shí)際生產(chǎn)情況中,還有各種各樣的異常情況,但是在客戶端普遍表現(xiàn)為上面幾種場(chǎng)景,下面我們來一步步分析上面的問題。

問題一

首先從客戶端反饋的日志,懷疑是服務(wù)器和客戶端間的網(wǎng)絡(luò)問題。為排除這個(gè)問題,我們編寫腳本,在客戶端定時(shí)ping服務(wù)端(redis服務(wù)),持續(xù)運(yùn)行一段后,發(fā)現(xiàn)未有丟包的情況,排除網(wǎng)絡(luò)問題。

查看redis服務(wù)端日志,未發(fā)現(xiàn)有異常情況。查看redis服務(wù)器資源監(jiān)控,發(fā)現(xiàn)每幾分鐘左右,IO會(huì)有一波峰值,但是CPU和帶寬壓力都在正常范圍。

這里介紹下我們的redis部署模式:一主一從通過redis自帶的sentinal做HA,主從均有開啟持久化。初步懷疑間隔性IO操作占用資源導(dǎo)致redis讀寫變慢(在此,拋出一個(gè)問題:在服務(wù)器資源CPU和帶寬均未達(dá)到瓶頸的情況下,持續(xù)的IO高峰操作是否會(huì)影響物理內(nèi)存的讀寫)。接下來采取的措施是:關(guān)閉主庫(kù)的持久化,用從庫(kù)來做持久化,但是這種模式下存在一個(gè)問題,如果主發(fā)生故障,sentinal做主從切換后問題同樣存在,大家有更好的建議可以指點(diǎn)下。

運(yùn)行一段時(shí)候,發(fā)現(xiàn)問題有所改善,但是依然還是會(huì)有time out的情況,只有繼續(xù)排查問題。由于redis操作采用單線程,考慮會(huì)不會(huì)有某些慢查詢導(dǎo)致time out。執(zhí)行slowlog查看慢查詢語(yǔ)句,發(fā)現(xiàn)有大量的keys命令操作,keys命令在大量并發(fā)情況下性能非常差,結(jié)合官方給出的warning

正式環(huán)境中,盡量避免使用keys,接下來找出使用keys的代碼做優(yōu)化,至此,time out問題解決。

問題二

從錯(cuò)誤日志看,是提示無法獲取連接。有兩種情況:

1、客戶端的連接池滿了,無法創(chuàng)建新的連接

檢查客戶端連接最大限制maxActive是否足夠

2、redis服務(wù)端連接溢出,無法分配新的連接

檢查服務(wù)端tcp連接:netstat -nat|grep -i "6379"|wc -l

檢查服務(wù)端連接是否達(dá)到最大值:查看服務(wù)端支持的最大連接:CONFIG GET maxclients,查看當(dāng)前服務(wù)端建立的   連接:connected_clients

通過上述檢查后,發(fā)現(xiàn)redis服務(wù)端connected_clients連接數(shù)持續(xù)過高,經(jīng)常在最大值徘徊。但是結(jié)合客戶端配置的最大連接配置maxActive,計(jì)算出所有客戶端連接占滿的情況下最大的連接數(shù)也達(dá)不到connected_clients的連接數(shù)。

執(zhí)行client list命令,發(fā)現(xiàn)大量的client的idle時(shí)間特別長(zhǎng):

正常的client連接,在持續(xù)使用的情況下,是不可能空閑這么長(zhǎng)時(shí)間,連接長(zhǎng)時(shí)間空閑,客戶端也會(huì)關(guān)閉連接。

查看redis服務(wù)端下面兩項(xiàng)配置:

  • timeout:client連接空閑多久會(huì)被關(guān)閉(這個(gè)配置容易被誤導(dǎo)為:連接超時(shí)和操作執(zhí)行超時(shí))
  • tcp-keepalive:redis服務(wù)端主動(dòng)向空閑的客戶端發(fā)起ack請(qǐng)求,以判斷連接是否有效

檢查上述配置發(fā)現(xiàn) timeout和tcp-keepalive均未啟用(均為0),這種情況下,redis服務(wù)端沒有有效的機(jī)制來確保服務(wù)端已經(jīng)建立的連接是否已經(jīng)失效。當(dāng)服務(wù)器和客戶端網(wǎng)絡(luò)出現(xiàn)閃斷,導(dǎo)致tcp連接中斷,這種情況下的client將會(huì)一直被redis服務(wù)端所持有,就會(huì)出現(xiàn)上面我們看到的idle時(shí)間特長(zhǎng)的client連接。

接下來設(shè)置timeout和tcp-keepalive來清理失效的連接。

上面問題中提到的數(shù)據(jù)庫(kù)某一時(shí)間壓力暴增,是由于在緩存模式下,redis請(qǐng)求失敗,請(qǐng)求的壓力瞬間集中到數(shù)據(jù)庫(kù)。

問題三

從錯(cuò)誤提示,可以看出是向磁盤保存數(shù)據(jù)失敗。引起這個(gè)問題的原因一般是內(nèi)存不足,但是生產(chǎn)環(huán)境我們一般都會(huì)為系統(tǒng)分配足夠的內(nèi)存運(yùn)行,而且查看內(nèi)存情況也顯示還有可用內(nèi)存。

查看redis日志,發(fā)現(xiàn)有這個(gè)錯(cuò)誤:Can’t save in background: fork: Cannot allocate memory

redis在保存內(nèi)存的數(shù)據(jù)到磁盤時(shí),為了防止主進(jìn)程假死,會(huì)Fork一個(gè)子進(jìn)程來完成這個(gè)保存操作。但是這個(gè)Fork的子進(jìn)程會(huì)需要分配和主進(jìn)程相同的內(nèi)存,這時(shí)候就相當(dāng)于需要的內(nèi)存double了,如果這時(shí)候可用內(nèi)存不足以分配需要的內(nèi)存,將會(huì)導(dǎo)致Fock子進(jìn)程失敗而無法保存數(shù)據(jù)到磁盤。

修改linux內(nèi)核參數(shù):vm.overcommit_memory=1。至此,問題解決。

overcommit_memory有三種取值:0, 1, 2

  • 0::檢查是否有足夠的可用內(nèi)存供進(jìn)程使用;有則允許申請(qǐng),否則,內(nèi)存申請(qǐng)失敗,并把錯(cuò)誤返回給應(yīng)用進(jìn)程;
  • 1:表示內(nèi)核允許分配所有的物理內(nèi)存,而不管當(dāng)前的內(nèi)存狀態(tài)如何;
  • 2:表示內(nèi)核允許分配超過所有物理內(nèi)存和交換空間總和的內(nèi)存。

優(yōu)化措施總結(jié)

1、結(jié)合實(shí)際使用場(chǎng)景,考慮是否需要用到redis的持久化,如果單純用來做應(yīng)用層的緩存(在緩存未命中的情況下訪問數(shù)據(jù)庫(kù)),可以關(guān)閉持久化。

2、緩存模式下,盡量為每塊緩存設(shè)置時(shí)效性,避免冷數(shù)據(jù)長(zhǎng)時(shí)間占用資源。

3、生產(chǎn)環(huán)境中盡量避免使用keys操作,由于redis是單線程模式,大量的keys操作會(huì)阻塞其他的命令執(zhí)行。

4、設(shè)置合理的內(nèi)存回收策略,保證內(nèi)存可用性的同時(shí)能適當(dāng)?shù)奶峁┚彺娴拿新省?/p>

5、提前計(jì)算出系統(tǒng)可能會(huì)用的內(nèi)存大小,合理的分配內(nèi)存。需要注意在開啟持久化模式下,需要預(yù)留更多的內(nèi)存提供給Fock的子進(jìn)程做數(shù)據(jù)磁盤flush操作。

深入探討研究

如果redis服務(wù)端未設(shè)置timeout,客戶端會(huì)如何處理長(zhǎng)時(shí)間未使用的連接?

這個(gè)問題可以從分析redis的sdk源碼查找答案,不過這個(gè)過程會(huì)比較枯燥。

接下來我們直接通過抓取客戶端和服務(wù)端的tcp數(shù)據(jù)包來獲取答案:

這里我用wireshark來抓取中間的tcp數(shù)據(jù)包,下面是抓取了一個(gè)完整的redis連接(從發(fā)起到結(jié)束)的tcp數(shù)據(jù)包

從上面可以看到,從tcp3次握手建立連接,到最后客戶端發(fā)送reset包給服務(wù)端終止了這個(gè)連接。

追蹤整個(gè)tcp的數(shù)據(jù)流:

*2$4AUTH$8password+OK*1$4PING+PONG*1$4PING+PONG*1$4QUIT+OK

從tcp數(shù)據(jù)流可以看出,整個(gè)tcp連接中間經(jīng)歷的操作:

1、客戶端發(fā)送密碼建立連接,服務(wù)端響應(yīng)OK

2、客戶端發(fā)送PING命令校驗(yàn)連接,服務(wù)端響應(yīng)PONG表示成功

3、客戶端再次發(fā)送PING命令校驗(yàn)連接,服務(wù)端響應(yīng)PONG表示成功

4、客戶端發(fā)送QUIT命令退出連接,服務(wù)端響應(yīng)OK表示退出成功

當(dāng)服務(wù)端響應(yīng)QUIT命令OK后,客戶端發(fā)送RESET的tcp包終止整個(gè)tcp連接。中間客戶端發(fā)起了兩次PING命令校驗(yàn)連接和一次QUIT命令來退出連接,每次間隔30s,加起來整個(gè)連接存活了90s。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論