千里之堤,潰于蟻穴。一個在完美的架構,因為一個慢Sql,會導致系統直接崩潰。總結了一些解決慢sql的方法,供參考。
一、慢sql優化
訂閱每日慢日志,優先解決調用次數多的慢sql,因慢sql優化的知識點非常多,只列舉幾個容易忽視的地方。
注意:
1、數據量不同,查詢條件不同,sql使用的索引可能是不一樣的,要構造多種查詢條件去測試。
2、避免所有字段都返回,盡量使用覆蓋索引,解決慢sql問題,終歸是與庫的磁盤IO、CPU做抗爭。
3、避免隱式轉換造成的索引無法使用問題。
4、控制好事務粒度,大事務不僅會嚴重影響數據庫的吞吐量,CPU(死鎖檢測),也會造成主從的延遲,危害極大。
5、合理的設置數據庫連接池的參數,設置sql語句的timeout,查詢量大的地方,需要有降級開關。
6、新增功能,每一條sql語句,都要進行explain
7、所謂的慢sql,有些sql并不慢,而是壞sql,調用量低,數據量少的情況,并不慢,慢日志無法捕獲。這個時候,需要對功能進行壓測,壓測需要注意兩個問題:
- a) 壓測腳本的選擇,如果使用固定的查詢條件,會造成MySQL命中緩存,或使用固定索引,壓測效果不明顯
- b) 壓測數據庫的操作,要逐漸放量,避免將庫CPU打滿,既要盯UMP的性能曲線,又要關注數據庫CPU的使用率。
二、讀寫分離
使用讀寫分離的方式,降低數據庫的壓力,讀寫分離能有效降低庫的壓力,但是其并不是銀彈,使用時需注意以下問題。
注意:
1、主從延遲問題。讀寫分離后,無可避免的會有延遲問題,所以需要甄別好,哪些業務是對延遲敏感的,這類業務,需要繼續查詢主庫。為盡量避免延遲問題,需注意以下幾點:
- a) 從庫的壓力,不能過大,如果資源允許,盡量主從的硬件資源相同。
- b) 避免使用大事務。
- c) 盡量避免大批量的刪除、更新操作,尤其是無法使用索引的情況。
2、業務隔離,不同業務使用不同從庫。識別出業務的黃金流程。重點業務與其他非重點業務使用不同的從庫進行隔離。
三、架構調整,服務化改造,應用拆分
對庫的操作,統一收口到應用的服務層,收口之后,sql語句集中,優化效果會事半功倍。
注意:
1、脫庫改造,增加緩存。
- a) 對于數據要求實時性不高的場景,并且為了快速的減少系統問題,可采取緩存read-through的方式,該方式系統改造量低,簡單。但是要注意,避免不存在的key緩存穿透(不存在key設置特殊值、bloomfilter)。緩存雪崩問題。
- b) 數據異構,將依賴的底層數據通過binlake或雙寫等等方式,異構到jimdb
- c) 數據異構,將列表類或多條件復雜查詢數據,異構到ES。查詢需注意深分頁及一次查詢的數據量過多問題。
2、復雜的統計類功能,使用離線計算的方式,避免實時通過庫函數進行計算統計
3、瀏覽記錄、日志類或其他不重要功能,可通過mq,同步寫轉異步寫
四、數據庫垂直拆分,業務隔離
底層資源進行拆分,按業務維度,不同業務拆分為不同應用 ,使用不同的資源。
五、數據庫水平拆分,分庫分表
注意:
1、庫水平拆分會出現很多問題,無法join,無法聚合查詢,可采用異構數據到ES等方式解決。
2、將無用的歷史數據進行歸檔。
六、不適合使用Mysql場景
Mysql數據庫不適用的場景:
1、復雜、多字段、模糊查詢
2、超大文本的存儲(text類型)。大文本查詢,會耗費mysql大量的內存空間,造成熱數據被置換出去,查詢效率降低
3、日志類大數量的存儲
4、超高并發的查詢
針對問題1,對于復雜、模糊查詢等,更適合使用ES搜索引擎去處理。
- a) 如果對數據的實時性要求不高,建議通過binlake或mq的方式,異步構建ES索引。
- b) 如果對數據實時性要求很高,可通過雙寫的方式處理,失敗可以采用異步補償的方式。另外ES本身段刷新有1秒的延遲,1s后數據才可搜索。如果不可接受并且數據修改頻率低,可通過setRefresh方法強制刷新,立刻即可搜索到。寫入量大的時候慎用。
針對問題2、3,建議使用nosql庫,hbase、es等存儲
針對問題4,簡單查詢,jimdb是非常好選擇。如果有業務需要復雜查詢,更建議使用ES多集群方式處理。