后臺用了一年多厚者,現(xiàn)在查詢報表變得很卡中贝,大概要15~180秒梢莽,運營經(jīng)常反映報表加載不出來萧豆,我去服務器一看日志奸披,原來查詢花了200多秒昏名,nginx直接超時了……
先優(yōu)化一下 SQL
我的想法是優(yōu)化報表的 SQL 語句,因為我發(fā)現(xiàn)查個 sql 居然加起來要 10幾秒阵面。
我們的 sql 分為2條轻局,一條是先查總數(shù),這是為了下一步分頁用样刷。另一條是查詳情仑扑。
查總數(shù)的 sql 我看了下,index 都有用到置鼻,但是在 explain 中多出了 using temporary; using file sort; 這2項镇饮。于是我把 group by date 去掉,這2項就沒了箕母。
于是吭哧吭哧地把數(shù)據(jù)都加載出來储藐,然后在代碼里 group by,雖然比較費內(nèi)存和 CPU嘶是,但總比讓數(shù)據(jù)庫做好啊對不對钙勃?
后來想著對第二條也這樣優(yōu)化,但是發(fā)現(xiàn)不行聂喇,因為第二條有個分頁辖源,不 group by 的話,就沒法分頁了……這個暫時沒想到替代方法希太】巳模可憐代碼已經(jīng)寫了2小時了,只好先不用了誊辉。
代碼寫完了矾湃,本地測試一下,發(fā)現(xiàn)查詢速度從 9s 降到 1s芥映,果然有效洲尊!
于是趕緊弄上服務器远豺,然后一試,變成 32s 了坞嘀!而且 cpu 躯护、內(nèi)存狂漲!
無語了丽涩,趕緊回滾了棺滞。
事后分析,大概是因為數(shù)據(jù)量太大矢渊,服務器也處理不過來了……
試試緩存继准?
這事只好作罷,心里想矮男,慢點就慢點吧移必,反正也是自己人用。
但是渠道那邊又來找了毡鉴,說是我們的 api 拉取超時了崔泵。這下就比較難辦了,渠道那邊超時猪瞬,可能會影響我們正常的業(yè)務憎瘸。況且這種現(xiàn)象如果聽之任之,最終可能引發(fā)雪崩效應陈瘦,到時就麻煩了幌甘。
但是現(xiàn)在數(shù)據(jù)庫優(yōu)化很蛋疼,怎么辦呢痊项?這時還是應該從業(yè)務角度考慮锅风,渠道要的數(shù)據(jù)并不是實時數(shù)據(jù),所以完全可以用緩存頂一下嘛线婚。
django 的話遏弱,直接用 django-cacheops 就行了,挺好用的塞弊,直接在 queryset 后面加個 .cache() 就可以啟用緩存了漱逸,當然配置里面要設置一下,不然它默認對所有查詢都緩存就不好了游沿,畢竟運營要看到的是實時數(shù)據(jù)饰抒。
代碼改好了,部署上去诀黍,加載時間立即縮短了10倍袋坑!而且不是光 api 接口,連報表的查詢也大大縮短了眯勾!真是意外的驚喜啊枣宫。
所以從這件事可以總結(jié)出2個道理:
- sql 查詢變慢了婆誓,不一定是這條 sql 本身,可能是慢查詢太多也颤,導致它被拖累了
- 緩存一定要用上洋幻,減少數(shù)據(jù)庫的壓力是非常有必要的。
redis 的問題
不過翅娶,剛高興沒多久呢文留,也就1、2分鐘吧竭沫,接口就報 500 錯誤了燥翅,異常信息提示 Connection closed by server
,郁悶蜕提,趕緊回滾森书。然后就在本地測,結(jié)果一點問題沒有贯溅。我猜可能是配置不一樣拄氯,但具體是哪個參數(shù)我也不知道了。
然后就是上網(wǎng)查資料它浅,發(fā)現(xiàn)一個參數(shù) timeout 貌似有用。分別在本地和服務器端看了下镣煮,原來本地 timeout = 0姐霍,服務器是 timeout = 60 。把它改過來之后典唇,終于正常了镊折。
不過呢,最近遇到的 redis 的問題挺多的介衔,比如服務器上經(jīng)常遇到 use of closed network connection
恨胚,這個就挺郁悶的,完全不知道怎么下手炎咖。
現(xiàn)在疏理一下赃泡,timeout 是 redis 用來控制客戶端連接的。如果 timeout > 0 的話乘盼,如果客戶端持續(xù) timeout 秒沒有活動升熊,redis 就會關(guān)閉這個連接。
如果設置成 timeout = 0绸栅,就表示永遠不關(guān)閉级野。
問題在于,admin 服務器請求量小粹胯,確實可能 60s 里沒有活動蓖柔,redis 可以關(guān)閉它辰企,但是廣告服務器請求量很大,為什么還是會關(guān)閉呢况鸣?