介面效能提升方法
1.索引
1.1 沒加索引
sql語句中where條件的關鍵欄位,或者order by後面的排序欄位,忘了加索引,這個問題在專案中很常見。
專案剛開始的時候,由於表中的資料量小,加不加索引sql查詢效能差別不大。
目前在mysql中如果想要修改索引,只能先刪除索引,再重新新增新的。
1.2 索引沒生效
可以使用explain命令,檢視mysql的執行計劃,它會顯示索引的使用情況。
1.3 選錯索引
必要時可以使用force index來強制查詢sql走某個索引。
2. sql最佳化
3. 遠端呼叫
3.1 並行呼叫
3.2 資料異構
4. 重複呼叫
4.1 迴圈查資料庫
這裡有個需要注意的地方是:id集合的大小要做限制,最好一次不要請求太多的資料。要根據實際情況而定,建議控制每次請求的記錄條數在500以內。
4.2 死迴圈
還有一種隱藏的比較深的死迴圈,是由於程式碼寫的不太嚴謹導致的。如果用正常資料,可能測不出問題,但一旦出現異常資料,就會立即出現死迴圈。
4.3 無限遞迴
建議寫遞迴方法時,設定一個遞迴的深度,比如:分類最大等級有4級,則深度可以設定為4。然後在遞迴方法中做判斷,如果深度大於4時,則自動返回,這樣就能避免無限迴圈的情況。
5. 非同步處理
在這裡有個原則就是:核心邏輯可以同步執行,同步寫庫。非核心邏輯,可以非同步執行,非同步寫庫。
通常非同步主要有兩種:多執行緒 和 mq。
5.1 執行緒池
但使用執行緒池有個小問題就是:如果伺服器重啟了,或者是需要被執行的功能出現異常了,無法重試,會丟資料。
5.2 mq
因為傳送mq訊息速度是很快的,我們只需關注業務操作的程式碼即可。
6. 避免大事務
我們該如何最佳化大事務呢?
少用@Transactional註解
將查詢(select)方法放到事務外
事務中避免遠端呼叫
事務中避免一次性處理太多資料
有些功能可以非事務執行
有些功能可以非同步處理
7. 鎖粒度
為了解決併發場景下,多個執行緒同時修改資料,造成資料不一致的情況。通常情況下,我們會:加鎖。
7.1 synchronized
在java中提供了synchronized關鍵字給我們的程式碼加鎖。
通常有兩種寫法:在方法上加鎖 和 在程式碼塊上加鎖。
同時它也帶來了新的問題:synchronized只能保證一個節點加鎖是有效的,但如果有多個節點如何加鎖呢?
答:這就需要使用:分散式鎖了。目前主流的分散式鎖包括:redis分散式鎖、zookeeper分散式鎖 和 資料庫分散式鎖。
由於zookeeper分散式鎖的效能不太好,真實業務場景用的不多,這裡先不講。
7.2 redis分散式鎖
7.3 資料庫分散式鎖
mysql資料庫中主要有三種鎖:
表鎖:加鎖快,不會出現死鎖。但鎖定粒度大,發生鎖衝突的機率最高,併發度最低。
行鎖:加鎖慢,會出現死鎖。但鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
間隙鎖:開銷和加鎖時間界於表鎖和行鎖之間。它會出現死鎖,鎖定粒度界於表鎖和行鎖之間,併發度一般。
優先使用行鎖,其次使用間隙鎖,再其次使用表鎖。
8.分頁處理
8.1 同步呼叫
google的guava工具中的Lists.partition方法,用它來做分頁簡直太好用了,不然要寫一大堆分頁的程式碼。
8.2 非同步呼叫
使用CompletableFuture類,多個執行緒非同步呼叫遠端介面,最後彙總結果統一返回。
9.加快取
9.1 redis快取 redis和memcached
9.2 二級快取
使用二級快取,即基於記憶體的快取。
除了自己手寫的記憶體快取之後,目前使用比較多的記憶體快取框架有:guava、Ehcache、caffine等。
10. 分庫分表
當系統發展到一定的階段,使用者併發量大,會有大量的資料庫請求,需要佔用大量的資料庫連線,同時會帶來磁碟IO的效能瓶頸問題。
隨著使用者數量越來越多,產生的資料也越來越多,一張表有可能存不下。由於資料量太大,sql語句查詢資料時,即使走了索引也會非常耗時。
需要做分庫分表
如果有使用者請求過來的時候,先根據使用者id路由到其中一個使用者庫,然後再定位到某張表。
路由的演算法挺多的:
根據id取模,比如:id=7,有4張表,則7%4=3,模為3,路由到使用者表3。
給id指定一個區間範圍,比如:id的值是0-10萬,則資料存在使用者表0,id的值是10-20萬,則資料存在使用者表1。
一致性hash演算法
分庫分表主要有兩個方向:垂直(即業務方向)和水平(即資料方向)。
分庫:是為了解決資料庫連線資源不足問題,和磁碟IO的效能瓶頸問題。
分表:是為了解決單表資料量太大,sql語句查詢資料時,即使走了索引也非常耗時問題。此外還可以解決消耗cpu資源問題。
分庫分表:可以解決 資料庫連線資源不足、磁碟IO的效能瓶頸、檢索資料耗時 和 消耗cpu資源等問題。
如果在有些業務場景中,使用者併發量很大,但是需要儲存的資料量很少,這時可以只分庫,不分表。
如果在有些業務場景中,使用者併發量不大,但是需要儲存的數量很多,這時可以只分表,不分庫。
如果在有些業務場景中,使用者併發量大,並且需要儲存的數量也很多時,可以分庫分表。
11. 輔助功能
11.1 開啟慢查詢日誌
開啟慢查詢日誌需要重點關注三個引數:
slow_query_log 慢查詢開關
slow_query_log_file 慢查詢日誌存放的路徑
long_query_time 超過多少秒才會記錄日誌
set global slow_query_log='ON';
set global slow_query_log_file='/usr/local/mysql/data/slow.log';
set global long_query_time=2;
也可以直接修改配置檔案my.cnf
[mysqld]
slow_query_log = ON
slow_query_log_file = /usr/local/mysql/data/slow.log
long_query_time = 2
11.2 加監控
目前業界使用比較多的開源監控系統是:Prometheus。
可以訪問Prometheus的官網:https://prometheus.io/
11.3 鏈路跟蹤
用分散式鏈路跟蹤系統:skywalking。
在skywalking中可以透過traceId(全域性唯一的id),串聯一個介面請求的完整鏈路。可以看到整個介面的耗時,呼叫的遠端服務的耗時,訪問資料庫或者redis的耗時等等,功能非常強大。
可以訪問skywalking的官網:https://skywalking.apache.org/