這篇文章主要介紹“如何解決寫(xiě)接口出現(xiàn)的問(wèn)題”,在日常操作中,相信很多人在如何解決寫(xiě)接口出現(xiàn)的問(wèn)題問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”如何解決寫(xiě)接口出現(xiàn)的問(wèn)題”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
成都創(chuàng)新互聯(lián)公司-成都網(wǎng)站建設(shè)公司,專注網(wǎng)站制作、網(wǎng)站建設(shè)、網(wǎng)站營(yíng)銷推廣,國(guó)際域名空間,網(wǎng)絡(luò)空間,網(wǎng)站托管有關(guān)企業(yè)網(wǎng)站制作方案、改版、費(fèi)用等問(wèn)題,請(qǐng)聯(lián)系成都創(chuàng)新互聯(lián)公司。
深夜,領(lǐng)導(dǎo):“你寫(xiě)的接口有問(wèn)題!趕緊起床瞧瞧”。Ding!催命軟件一響,你就知道,該 Work 了......
可思來(lái)想去,覺(jué)得不可能啊。我的代碼,就是一個(gè)簡(jiǎn)單的 redis 查詢啊,難不成是 Redis 掛了?
同事把證據(jù)全部發(fā)到了群里,是你的接口無(wú)疑。一個(gè)簡(jiǎn)單的 Get 查詢,平均耗時(shí)達(dá)到了 2 秒。jstack,promethus 的監(jiān)控,把問(wèn)題全部指向到了你的接口!
登錄 Redis 服務(wù)器,一切正常。該怎么辦?要這么不明不白不清不楚的背個(gè)章丘大鐵鍋么?
快是原罪
這種情況下,要相信自己的直覺(jué)。你的接口又快又好,很可能是木秀于林,鶴立雞群,當(dāng)了替罪鳥(niǎo)。
在 “某些” "高并發(fā)"環(huán)境下,由于資源未做隔離,在發(fā)生問(wèn)題的時(shí)候,一些日志和工具的表現(xiàn),會(huì)有非常強(qiáng)的迷惑性。
發(fā)生問(wèn)題的,都是速度最快、請(qǐng)求最多的接口,但理論上并不可能。
如上圖。這種情況很常見(jiàn)。大多數(shù)請(qǐng)求,通過(guò) Tomcat 線程池的調(diào)度,進(jìn)行真正的業(yè)務(wù)處理。
當(dāng)然線程池是不干這種臟活的,它把請(qǐng)求交給資源處理池去處理,比如:
一個(gè)數(shù)據(jù)庫(kù)連接池,執(zhí)行耗時(shí)的統(tǒng)計(jì)操作和迅速的查詢操作。
一個(gè) Redis 連接池,執(zhí)行阻塞性的慢查詢和簡(jiǎn)單的 GET SET。
一個(gè) Http 連接池(HTTPClient、OkHTTP 等),遠(yuǎn)程調(diào)用速度不等的資源。
...
我們平常的編碼中,通常都會(huì)共用這樣的資源池。因?yàn)樗鼘?xiě)起代碼來(lái)簡(jiǎn)單,不需要?jiǎng)幽X。
但如果你的服務(wù)本身,并沒(méi)有做好拆分以及隔離,問(wèn)題就是致命的。比如,你把報(bào)表接口和高并發(fā)的 C 端接口放在了一個(gè)實(shí)例上。
這時(shí)候,你就有可能被報(bào)表接口給坑了。
一個(gè)例子
我們以數(shù)據(jù)庫(kù)連接池為例,來(lái)說(shuō)明一下這個(gè)過(guò)程,先看一下以下基礎(chǔ)信息:
Tomcat 的連接池,配置大小為 200 個(gè)。
MySQL 的連接池,配置大小為 50 個(gè),算是比較大了。
接口 A 需要調(diào)用耗時(shí)的查詢,耗時(shí)為 5 秒。
接口 B 速度非常快,查詢數(shù)據(jù)庫(kù)響應(yīng)時(shí)間在 200ms 以下。
速度快的 B 接口,請(qǐng)求量是遠(yuǎn)遠(yuǎn)大于接口 A 的,平常情況下相安無(wú)事。
有一天,接口 A 忽然有了大量的查詢,由于它的耗時(shí)比較長(zhǎng),迅速把數(shù)據(jù)庫(kù)的 50 個(gè)連接池給占滿了(接口 B 由于響應(yīng)快,持有時(shí)間短,慢慢連接會(huì)被 A 吃掉)。
這時(shí)候,無(wú)論是接口 A,還是接口 B 的請(qǐng)求,都需要等待至少 5 秒鐘,才能獲取下一條數(shù)據(jù)庫(kù)連接,業(yè)務(wù)才能正常走下去。
不一小會(huì)兒,服務(wù)的狀態(tài)就變成這樣:
數(shù)據(jù)庫(kù)連接池 50 個(gè)連接,迅速占滿,而且?guī)缀跞宦樵冋紳M。
Tomcat 連接池的 200 個(gè)連接,迅速被占滿,其中大部分是速度快的接口 B,因?yàn)樗恼?qǐng)求量大速度快。
所有接口都 Block 在 Tomcat 的線程上。進(jìn)而造成:哪怕是查詢一個(gè)非數(shù)據(jù)庫(kù)的請(qǐng)求,也要等待 5 秒左右。
一般在遇到這種問(wèn)題的時(shí)候,我們都傾向于使用 jstack 打印信息堆棧,或者查看一些內(nèi)部的監(jiān)控曲線。
可惜的是,這些信息,大部分都是騙人的,你看到的慢查詢,并不是真正的慢查詢。
從上面的分析中,你應(yīng)該很容易看出問(wèn)題的癥結(jié)所在:未隔離的瓶頸資源引起上游資源的連鎖反應(yīng)。
但在平常的工作中,我不止一次看到有同學(xué)對(duì)此手忙腳亂。很多證據(jù)都指向了一些又快又好的接口,而這些根本和它們一點(diǎn)關(guān)系都沒(méi)有。他們樂(lè)呵呵的截圖,@相關(guān)人等,囂張至極。
在遇到這種情況的時(shí)候,你可以使用下面的腳本進(jìn)行初步分析:
$ cat 10271.tdump| grep "waiting to lock " | awk '{print $5}' | sort | uniq -c | sort -k1 -r 26 <0x0000000782e1b590> 18 <0x0000000787b00448> 16 <0x0000000787b38128> 10 <0x0000000787b14558>
上面的例子,我們找到給 0x0000000782e1b590 上鎖的執(zhí)行棧,可以發(fā)現(xiàn)全部是卡在 HttpClient 的讀操作上了。
在實(shí)際場(chǎng)景中,可以看下排行比較靠前的幾個(gè)鎖地址,找一下共性:
而這些顯示信息非常少的堆棧,才是問(wèn)題的根本原因。
如何解決
增加 Tomcat 連接池的大小,或者增加連接池的大小,并不能解決問(wèn)題,大概率還會(huì)復(fù)現(xiàn)。
最好的解決方式,當(dāng)然是把耗時(shí)的服務(wù)和正常的服務(wù)拆分開(kāi)來(lái),比如時(shí)下流行的微服務(wù)。你的服務(wù)查詢慢,自己訪問(wèn)超時(shí),和我的服務(wù),一丁點(diǎn)兒關(guān)系都沒(méi)有。
但是,你的服務(wù)即然能遇到這種問(wèn)題,就證明你的公司缺乏這種改造的條件。就只能在單體服務(wù)上來(lái)做文章。
這種做法,就是隔離:
如上圖,我們?cè)谕粋€(gè)工程里,創(chuàng)建了兩個(gè) MySQL 數(shù)據(jù)庫(kù)連接池,指向了相同的 MySQL 地址。
使用這種方式,連接池的操作,就能夠相對(duì)做到互不影響。但到現(xiàn)在為止,還沒(méi)完,因?yàn)槟愕?Tomcat 連接池依然是共享的。
慢查詢相關(guān)的,從連接池中獲取連接的策略,要改一下,不能一直等待,而應(yīng)該采用 FailFast 的方式(獲取連接短時(shí)間的超時(shí)也是可以的),否則癥狀還是一樣。
時(shí)下流行的熔斷概念,也在一定程度上實(shí)踐這種隔離性。
到此,關(guān)于“如何解決寫(xiě)接口出現(xiàn)的問(wèn)題”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!