日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
高并發(fā)服務(wù)遇redis瓶頸引發(fā)time-wait事故

摘要

超過(guò)10年行業(yè)經(jīng)驗(yàn),技術(shù)領(lǐng)先,服務(wù)至上的經(jīng)營(yíng)模式,全靠網(wǎng)絡(luò)和口碑獲得客戶,為自己降低成本,也就是為客戶降低成本。到目前業(yè)務(wù)范圍包括了:網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站制作,成都網(wǎng)站推廣,成都網(wǎng)站優(yōu)化,整體網(wǎng)絡(luò)托管,微信小程序定制開發(fā),微信開發(fā),重慶APP軟件開發(fā),同時(shí)也可以讓客戶的網(wǎng)站和網(wǎng)絡(luò)營(yíng)銷和我們一樣獲得訂單和生意!

元旦期間 訂單業(yè)務(wù)線 告知 推送系統(tǒng) 無(wú)法正常收發(fā)消息,作為推送系統(tǒng)維護(hù)者的我正外面瀟灑,無(wú)法第一時(shí)間回去,直接讓 ops 幫忙重啟服務(wù),一切好了起來(lái),重啟果然是個(gè)大殺器。由于推送系統(tǒng)本身是分布式部署,消息有做各種的可靠性策略,所以重啟是不會(huì)丟失消息事件的。

事后通過(guò)日志分析有大量的 redis 的報(bào)錯(cuò),十分鐘內(nèi)有 16w 次的錯(cuò)誤。日志的錯(cuò)誤是 connect: cannot assign requested address 。該錯(cuò)誤不是推送服務(wù)內(nèi)部及 redis 庫(kù)返回的 error,而是系統(tǒng)回饋的 errno 錯(cuò)誤。

這個(gè)錯(cuò)誤是由于無(wú)法申請(qǐng)可用地址引起的,也就是無(wú)法申請(qǐng)到可用的 socket。

話說(shuō),元旦當(dāng)天在線數(shù)和訂單量確實(shí)大了不少,往常推送系統(tǒng)的長(zhǎng)連接客戶端在 35w,這次峰值飆到 50w 左右, 集群共 6 個(gè)節(jié)點(diǎn),其中有 4 個(gè)節(jié)點(diǎn)每個(gè)都抗了 9w+ 的長(zhǎng)連接。另外,推送的消息量也隨之翻倍。

分析

下面是 kibana 日志的統(tǒng)計(jì),出錯(cuò)的時(shí)間區(qū)間里有近 16w 次的 redis 報(bào)錯(cuò)。

下面是出問(wèn)題節(jié)點(diǎn)的 TCP 連接狀況,可以看到 established 在 6w,而 time-wait 連接干到 2w 多個(gè)。

為什么會(huì)產(chǎn)生這么多 time-wait?誰(shuí)主動(dòng)關(guān)閉就就有 time-wait,但推送系統(tǒng)除了協(xié)議解析失敗之外,其余情況都不會(huì)主動(dòng) close 客戶端,哪怕是鑒權(quán)失敗和弱網(wǎng)絡(luò)客戶端寫緩沖爆滿,事后通過(guò)日志也確定了不是推送系統(tǒng)自身產(chǎn)生的 tw。

另外,linux 主機(jī)被 ops 交付時(shí)應(yīng)該有做內(nèi)核調(diào)優(yōu)初始化的,在開啟 tw_reuse 參數(shù)后,time-wait 是可以復(fù)用的。難道是沒開啟 reuse?

查看 sysctl.conf 的內(nèi)核參數(shù)得知,果然 tcp_tw_reuse 參數(shù)沒有打開,不能快速地復(fù)用還處在 time-wait 狀態(tài)的地址,只能等待 time-wait 的超時(shí)關(guān)閉,rfc 協(xié)議里規(guī)定等待 2 分鐘左右,開啟 tw_reuse可在 1s 后復(fù)用該地址。另外 ip_local_port_range 端口范圍也不大,縮短了可用的連接范圍。

 
 
 
 
  1. sysctl  -a|egrep "tw_reuse|timestamp|local_port" 
  2.  
  3. net.ipv4.ip_local_port_range = 35768    60999 
  4. net.ipv4.tcp_timestamps = 1 
  5. net.ipv4.tcp_tw_reuse = 0 

所以,由于沒有可用地址才爆出了 connect: cannot assign requested address 錯(cuò)誤。

內(nèi)在問(wèn)題

追究問(wèn)題

上面是表象問(wèn)題,來(lái)查查為什么會(huì)有這么多的 time-wait ?再說(shuō)一遍,通常哪一端主動(dòng) close fd,哪一端就會(huì)產(chǎn)生 time-wait。事后通過(guò) netstat 得知 time-wait 連接基本是來(lái)自 redis 主機(jī)。

下面是推送代碼中的連接池配置,空閑連接池只有 50,最大可以 new 的連接可以到 500 個(gè)。這代表當(dāng)有大量請(qǐng)求時(shí),企圖先從 size 為 50 的連接池里獲取連接,如果拿不到連接則 new 一個(gè)新連接,連接用完了后需要?dú)w還連接池,如果這時(shí)候連接池已經(jīng)滿了,那么該連接會(huì)主動(dòng)進(jìn)行 close 關(guān)閉。

 
 
 
 
  1. MaxIdle   = 50 
  2. MaxActive = 500 
  3. Wait      = false 

除此之外,還發(fā)現(xiàn)一個(gè)問(wèn)題。有幾處 redis 的處理邏輯是異步的,比如每次收到心跳包都會(huì) go 一個(gè)協(xié)程去更新 redis, 這也加劇了連接池的搶奪,改為同步代碼。這樣在一個(gè)連接上下文中同時(shí)只對(duì)一個(gè) redis 連接操作。

解決方法

調(diào)大 golang redis client 的 maxIdle 連接池大小,避免了高下無(wú)空閑連接而新建連接和池子爆滿又不能歸還連接的尷尬場(chǎng)面。當(dāng) pool wait 為 true 時(shí),意味著如果空閑池中沒有可用的連接,且當(dāng)前已建立連接的連接數(shù)大于 MaxActive 最大空閑數(shù),則一直阻塞等待其他人歸還連接。反之直接返回 “connection pool exhausted” 錯(cuò)誤。

 
 
 
 
  1. MaxIdle   = 300 
  2. MaxActive = 400 
  3. Wait      = true 

redis 的 qps 性能瓶頸

redis 的性能一直是大家所稱贊的,在不使用 redis 6.0 multi io thread 下,QPS 一般可以在 13w 左右,如果使用多指令和 pipeline 的話,可以干到 40w 的 OPS 命令數(shù),當(dāng)然 qps 還是在 12w-13w 左右。

Redis QPS 高低跟 redis 版本和 cpu hz、cache 存在正比關(guān)系

根據(jù)我的經(jīng)驗(yàn),在內(nèi)網(wǎng)環(huán)境下且已實(shí)例化連接對(duì)象,單條 redis 指令請(qǐng)求耗時(shí)通常在 0.2ms 左右,200us 已經(jīng)夠快了,但為什么還會(huì)有大量因 redis client 連接池?zé)o空閑連接而建立新連接的情況?

通過(guò) grafana 監(jiān)控分析 redis 集群,發(fā)現(xiàn)有幾個(gè)節(jié)點(diǎn) QPS 已經(jīng)到了 Redis 單實(shí)例性能瓶頸,QPS 干到了近 15w 左右。難怪不能快速處理來(lái)自業(yè)務(wù)的 redis 請(qǐng)求。這個(gè)瓶頸必然會(huì)影響請(qǐng)求的時(shí)延。請(qǐng)求的時(shí)延都高了,連接池不能及時(shí)返回連接池,所以就造成了文章開頭說(shuō)的問(wèn)題。總之,業(yè)務(wù)流量的暴增引起了一系列問(wèn)題。

發(fā)現(xiàn)問(wèn)題,那么就要解決問(wèn)題,redis 的 qps 優(yōu)化方案有兩步:

  • 擴(kuò)容 redis 節(jié)點(diǎn),遷移 slot 使其分擔(dān)流量
  • 盡量把程序中 redis 的請(qǐng)求改成批量模式

增加節(jié)點(diǎn)容易,批量也容易。起初在優(yōu)化推送系統(tǒng)時(shí),已經(jīng)把同一個(gè)邏輯中的 redis 操作改為批量模式了。但問(wèn)題來(lái)了,很多的 redis 操作在不同的邏輯塊里面,沒法合成一個(gè) pipeline。

然后做了進(jìn)一步的優(yōu)化,把不同邏輯中的 redis 請(qǐng)求合并到一個(gè) pipeline 里,優(yōu)點(diǎn)在于提高了 redis 的吞吐,減少了 socket 系統(tǒng)調(diào)用、網(wǎng)絡(luò)中斷開銷,缺點(diǎn)是增加了邏輯復(fù)雜度,使用 channal 管道做隊(duì)列及通知增加了 runtime 調(diào)度開銷,pipeline worker 觸發(fā)條件是滿足 3 個(gè) command 或 5ms 超時(shí),定時(shí)器采用分段的時(shí)間輪。

對(duì)比優(yōu)化修改前,cpu開銷減少了 3% 左右,壓測(cè)下redis qps平均降了 3w 左右差值,最多可以降到 7w 左右,當(dāng)然概率上消息的時(shí)延會(huì)高了幾個(gè)ms。

實(shí)現(xiàn)的邏輯參考下圖,調(diào)用方把redis command和接收結(jié)果的chan推送到任務(wù)隊(duì)列中,然后由一個(gè)worker去消費(fèi),worker組裝多個(gè)redis cmd為pipeline,向redis發(fā)起請(qǐng)求并拿回結(jié)果,拆解結(jié)果集后,給每個(gè)命令對(duì)應(yīng)的結(jié)果chan推送結(jié)果。調(diào)用方在推送任務(wù)到隊(duì)列后,就一直監(jiān)聽傳輸結(jié)果的chan。

這個(gè)方案來(lái)自我在上家公司做推送系統(tǒng)的經(jīng)驗(yàn),有興趣的朋友可以看看 PPT,內(nèi)涵不少golang高并發(fā)經(jīng)驗(yàn)。

總結(jié)

推送系統(tǒng)設(shè)計(jì)之初是預(yù)計(jì) 20w 的長(zhǎng)連接數(shù),穩(wěn)定后再無(wú)優(yōu)化調(diào)整,也一直穩(wěn)定跑在線上。后面隨著業(yè)務(wù)的暴漲,長(zhǎng)連接數(shù)也一直跟著暴漲,現(xiàn)在日常穩(wěn)定在 35w,出問(wèn)題時(shí)暴到 50w,我們沒有因?yàn)闃I(yè)務(wù)暴增進(jìn)行整條鏈路壓測(cè)及優(yōu)化。

話說(shuō),如果對(duì)推送系統(tǒng)平時(shí)多上點(diǎn)心也不至于出這個(gè)問(wèn)題。我曾經(jīng)開發(fā)過(guò)相對(duì)高規(guī)格的推送系統(tǒng),而現(xiàn)在公司的推送系統(tǒng)我是后接手的,由于它的架子一般,但業(yè)務(wù)性又太強(qiáng),看著腦仁疼,所以就沒有推倒來(lái)重構(gòu)。一直是在這個(gè)架子上添添補(bǔ)補(bǔ),做了一些常規(guī)的性能優(yōu)化。嗯,看來(lái)不能掉以輕心,免得績(jī)效離我遠(yuǎn)去。


分享題目:高并發(fā)服務(wù)遇redis瓶頸引發(fā)time-wait事故
URL標(biāo)題:http://www.5511xx.com/article/cddjjhh.html