該用緩存還是得用緩存

后臺(tái)用了一年多,現(xiàn)在查詢報(bào)表變得很卡,大概要15~180秒,運(yùn)營(yíng)經(jīng)常反映報(bào)表加載不出來(lái),我去服務(wù)器一看日志,原來(lái)查詢花了200多秒,nginx直接超時(shí)了……

先優(yōu)化一下 SQL

我的想法是優(yōu)化報(bào)表的 SQL 語(yǔ)句,因?yàn)槲野l(fā)現(xiàn)查個(gè) sql 居然加起來(lái)要 10幾秒。

我們的 sql 分為2條,一條是先查總數(shù),這是為了下一步分頁(yè)用。另一條是查詳情。

查總數(shù)的 sql 我看了下,index 都有用到,但是在 explain 中多出了 using temporary; using file sort; 這2項(xiàng)。于是我把 group by date 去掉,這2項(xiàng)就沒(méi)了。

于是吭哧吭哧地把數(shù)據(jù)都加載出來(lái),然后在代碼里 group by,雖然比較費(fèi)內(nèi)存和 CPU,但總比讓數(shù)據(jù)庫(kù)做好啊對(duì)不對(duì)?

后來(lái)想著對(duì)第二條也這樣優(yōu)化,但是發(fā)現(xiàn)不行,因?yàn)榈诙l有個(gè)分頁(yè),不 group by 的話,就沒(méi)法分頁(yè)了……這個(gè)暫時(shí)沒(méi)想到替代方法??蓱z代碼已經(jīng)寫(xiě)了2小時(shí)了,只好先不用了。

代碼寫(xiě)完了,本地測(cè)試一下,發(fā)現(xiàn)查詢速度從 9s 降到 1s,果然有效!
于是趕緊弄上服務(wù)器,然后一試,變成 32s 了!而且 cpu 、內(nèi)存狂漲!
無(wú)語(yǔ)了,趕緊回滾了。

事后分析,大概是因?yàn)閿?shù)據(jù)量太大,服務(wù)器也處理不過(guò)來(lái)了……

試試緩存?

這事只好作罷,心里想,慢點(diǎn)就慢點(diǎn)吧,反正也是自己人用。
但是渠道那邊又來(lái)找了,說(shuō)是我們的 api 拉取超時(shí)了。這下就比較難辦了,渠道那邊超時(shí),可能會(huì)影響我們正常的業(yè)務(wù)。況且這種現(xiàn)象如果聽(tīng)之任之,最終可能引發(fā)雪崩效應(yīng),到時(shí)就麻煩了。

但是現(xiàn)在數(shù)據(jù)庫(kù)優(yōu)化很蛋疼,怎么辦呢?這時(shí)還是應(yīng)該從業(yè)務(wù)角度考慮,渠道要的數(shù)據(jù)并不是實(shí)時(shí)數(shù)據(jù),所以完全可以用緩存頂一下嘛。

django 的話,直接用 django-cacheops 就行了,挺好用的,直接在 queryset 后面加個(gè) .cache() 就可以啟用緩存了,當(dāng)然配置里面要設(shè)置一下,不然它默認(rèn)對(duì)所有查詢都緩存就不好了,畢竟運(yùn)營(yíng)要看到的是實(shí)時(shí)數(shù)據(jù)。

代碼改好了,部署上去,加載時(shí)間立即縮短了10倍!而且不是光 api 接口,連報(bào)表的查詢也大大縮短了!真是意外的驚喜啊。

所以從這件事可以總結(jié)出2個(gè)道理:

  1. sql 查詢變慢了,不一定是這條 sql 本身,可能是慢查詢太多,導(dǎo)致它被拖累了
  2. 緩存一定要用上,減少數(shù)據(jù)庫(kù)的壓力是非常有必要的。

redis 的問(wèn)題

不過(guò),剛高興沒(méi)多久呢,也就1、2分鐘吧,接口就報(bào) 500 錯(cuò)誤了,異常信息提示 Connection closed by server ,郁悶,趕緊回滾。然后就在本地測(cè),結(jié)果一點(diǎn)問(wèn)題沒(méi)有。我猜可能是配置不一樣,但具體是哪個(gè)參數(shù)我也不知道了。

然后就是上網(wǎng)查資料,發(fā)現(xiàn)一個(gè)參數(shù) timeout 貌似有用。分別在本地和服務(wù)器端看了下,原來(lái)本地 timeout = 0,服務(wù)器是 timeout = 60 。把它改過(guò)來(lái)之后,終于正常了。

不過(guò)呢,最近遇到的 redis 的問(wèn)題挺多的,比如服務(wù)器上經(jīng)常遇到 use of closed network connection ,這個(gè)就挺郁悶的,完全不知道怎么下手。

現(xiàn)在疏理一下,timeout 是 redis 用來(lái)控制客戶端連接的。如果 timeout > 0 的話,如果客戶端持續(xù) timeout 秒沒(méi)有活動(dòng),redis 就會(huì)關(guān)閉這個(gè)連接。

如果設(shè)置成 timeout = 0,就表示永遠(yuǎn)不關(guān)閉。

問(wèn)題在于,admin 服務(wù)器請(qǐng)求量小,確實(shí)可能 60s 里沒(méi)有活動(dòng),redis 可以關(guān)閉它,但是廣告服務(wù)器請(qǐng)求量很大,為什么還是會(huì)關(guān)閉呢?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容