有一個項目,代稱
cc
,用了我們公司的産品,單表資料量在200萬左右。在做業務操作的時候,點選一下按鈕,需要等待2~3分鐘。及其難以忍受,特此讓我們修改。
PS:涉及的一些
指令,簡化了很多,不能暴露線上資訊。
sql
第一反應
當收到這個問題的時候,第一反應就是确定下到底是背景資料查詢慢,還是前端資料渲染慢,亦或者是網慢,那麼如何排查呢?
詢問客戶使用了産品的哪個功能,然後自己模拟一下,并使用F12,追蹤下總的時間,是否如客戶所說的時長;
定位問題
結果,果然,點選一下然後就開始了漫長的等待,竟然真的需要2~3分鐘,完成一個業務流竟然需要10分鐘(該業務流需要多次點選菜單處理資料)。
驗證客戶所說為真。
和網速沒關系;
那麼接下來驗證下是前端還是背景慢;
看下
mysql
資料庫的慢
sql
記錄,是否存在長時間的
sql
語句。
如果
mysql
沒有配置慢
sql
記錄,那麼首先我們要進行如下配置:
vim /etc/my.cnf
# 在 [mysqld] 子產品中
slow-query-log=On
slow_query_log_file="/data/mysql/localhost-slow.log"
配置完畢之後,需要重新開機下
mysql
服務。
systemctl restart mysqld.service
而後再次模拟
cc
客戶回報慢的地方,運作完畢之後,看下存儲慢
sql
檔案的地方,裡面是否有資料;
vim /data/mysql/localhost-slow.log
果然有,而且時間和前端展示的總時間差不太多,說明響應慢的問題,一大半的原因是因為資料庫慢所導緻的。其他的就是前端資料渲染慢+服務中轉+網速問題了。
解決思路
資料庫
sql
慢的思路:
首先我們需要找到所有的慢
sql
,找到之後,第一反應應該是查有沒有配置索引,有沒有添加索引,使用
explain + sql
的方式來檢視,例如:
explain select (*) from ceshi_1;
在展示的資訊中,各個參數含義如下:
- id:選擇辨別符
- select_type:表示查詢的類型
- table:輸出結果集的表
- partitions:比對的分區
- type:表示表的連接配接類型
- possible_keys:表示查詢時,可能使用的索引
- key:表示實際使用的索引
- key_len:索引字段的長度
- ref:列與索引的比較
- rows:掃描出的行數(估算的行數)
- filtered:按表條件過濾的行百分比
- Extra:執行情況的描述和說明
根據
possible_keys
和
key
即可看到是否配置和使用了索引,如果沒有就添加,如果有就檢查其他問題。
前端慢的思路:
需要看下前端資源是否進行了壓縮傳輸,以及網速問題;
大機率情況下,網速一般是不需要解決的,除非說這個項目是剛上線就特别慢,這種情況才需要解決網速問題,是以我們隻需要看下前端資源是否進行了壓縮傳輸即可。
前端一般使用的是
nginx
;我們看下是否進行了如下配置:
gzip on;
gzip_buffers 32 4k;
gzip_comp_level 2;
gzip_min_length 300k;
gzip_types text/plain application/x-javascript application/javascript application/xml text/css text/javascript image/jpeg image/gif image/png;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
以上内容,應該配置在
nginx
中的
conf/nginx.conf
檔案中的
http/server
中的
listen
參數下;
然後重新加載下
nginx
的配置檔案,讓其生效,使用如下指令:
./sbin/nginx -s reload
最常見的解決方式就是按照上面的來,一般都能解決。
但是
但是
但是
但是
但是
我這裡不好使,為什麼呢?往下看。
實際解決方案
上面不是說了嘛,總的來說,慢的有兩個地方,一個是
sql
查詢慢,還有一個就是前端加載慢(有部分影響)。前端就按照上面的解決沒問題,但是
sql
就不太行。
為啥呢,因為程式裡面實作某一功能的
sql
,咋說的,寫的有點兒爛,怎麼個爛法呢,跨表查詢+嵌套查詢+
group by
+
limit
+
like
+時間範圍查詢。就導緻了雖然這個
sql
中涉及的每個表的使用字段都配置了索引,但是并沒有命中,相當于無效了,而且,還不好弄。
當然了,最好的方式是讓程式修改裡面定義的
sql
檔案嘛,但是嘛。。。懂的都懂。
最後,通過在
mysql
中添加緩存,這個緩存的作用是什麼呢,就是說,當你執行了一條
sql
,比如是:
select a,b,b from test_1 where time = '2022-07-27';
你第一次執行這個指令的時候,
mysql
的緩存會把這個
sql
和結果存放到緩存中。
隻要你涉及到這個查詢的資料沒有變化,那麼你後面再次查詢的時候,就不執行查詢了,而是直接把緩存中的這個結果傳回,這樣子就大大減少了查詢時間。
怎麼配置呢,還是需要修改
mysql
的配置檔案:
query_cache_size=2048M # 緩存大小
query_cache_type=1 # 開啟緩存
然後重新開機下資料庫;
systemctl restart mysqld.service
當然了,也可以使用
global set
的方式臨時進行修改。
這樣子添加完之後,隻有第一次通路慢,後面就非常快了。
通過上面的操作之後,點選菜單的時間從2~3分鐘,優化到了14秒左右,客戶還是不是很滿意,因為他們需要操作的業務量還是挺大的。
那麼有沒有别的辦法呢,再次研究程式裡面定義的
sql
,看看是否能通過添加聯合索引,或者其他索引的方式來優化,你别說,還真的讓我發現了一個索引,添加完畢之後,時間再次砍半,由14秒,再次縮短到了7秒左右,這個時候客戶終于臨時接受了,并發函讓我們繼續整改。
我們也承諾會進行排期優化
sql
,并及時上線。
事情也就到此為止告一段落了。
總結
遇到這種資料庫慢的情況,無非就是先定位問題,然後再根據情況來優化,大機率是
sql
本身的問題,上線之初可能沒有進行稽核,隻是為了上線而上線了,測試資料也就幾百幾千條,完全沒有壓力測試吧。
這個處理方式,僅供參考,不可能所有的都可以按照這個方式來處理,你如果有更好的方式,歡迎通過公衆号“運維家”,來我的WX來和我交流。
至此,本文結束。
更多内容請轉至VX公衆号 “運維家” ,擷取最新文章。
------ “運維家” ------
------ “運維家” ------
------ “運維家” ------
臨武縣運維工程師教育訓練,溫州運維工程師,通達oa實施運維工程師,呼叫中心運維工程師面試