🎯 問題:如何在頻繁查詢的情境下,解決資料庫系統的效能問題?
業界作法百百種,常見的思路是運用「讀寫分離」的技巧,設計一個主從式架構,將傳統資料庫細分為主 (Master) 、從 (Slave) 資料庫。
Master節點專注於於「資料的新增、修改、刪除」,資料正確性以 Master節點為準。Slave節點專注於「同步資料」、及「資料查詢」。
⭐ 讀寫分離好處:分散讀取及寫入的負擔
因為這個架構讓不同單元負責不同的工作,改善系統效能。若是流量真的太高,需要進一步強化讀取效能,只需要增加 Slave 節點數量,讓更多節點一起分擔查詢需求。
⭐ 讀寫分離注意項目:資料一致性
由於資料更新做在Master,以Master節點的資料為主,Slave負責同步,這時候要思考的問題是「用戶對於資料即時性的容忍程度為何」?
理想上能越頻繁同步資料越好,最好是Master節點的資料更新,馬上就會連動到Slave節點,但是過於頻繁的更新,也會造成Master節點的負擔,反而造成資料庫效能變差。原則上如果是對資料即時性要求極高的情境(如金融交易),不適合主從式讀寫分離架構。
因此有的系統會以不同情境設計同步頻率,例如不常更新的資料表,Slave節點就不會頻繁更新; 針對經常變動的資料表,Slave節點的更新頻率則可以縮短。
有的系統則是利用資料庫系統原生的同步功能,如 PostgreSQL 使用 Streaming Replication+WAL的技術,實現 Master 節點資料改變,Slave 節點異步更新的效果。註:PostgreSQL也支援同步更新的功能,但一般狀況下不會推薦同步更新,因為同步更新會影響 Master 寫入效能。(參考:PostgreSQL正體中文使用手冊。)
⭐ 讀寫分離注意項目:應用層路由
若使用傳統單一資料庫入口,應用系統只要連結單一入口,而讀寫分離架構需要連接不同入口,讓系統在新增、修改、刪除情境能對到 Master 節點,讀取情境對到 Slave 節點。
如果要在應用端做得更好,則需要往下繼續考慮問題:
1.Slave 節點的負載均衡問題:當有多的Slave節點時,如何透過隨機分配來降低Slave負載。
2.當Slave節點不可用時,系統是否有Failover機制,將查詢切回Master節點。
⭐ 額外選項:Redis可作為暫存資料庫
Redis是一個高性能的記憶體內 Key-Value 儲存系統,具備「極高速度」,「過期機制」(超過時間自動回收資料)、「高併發」等好用功能,時常作為Cache資料的選項。
若是要提升系統查詢的效能,可以將時常查詢的資料存於Redis,避免重複查詢資料庫,而且除了Key-Value結構、字串,也支援複雜的Hash結構(如Json格式資料)。
要注意的是,由於Redis是記憶體型儲存,若資料量過大,可能會讓記憶體使用量飆高。另外,也要小心資料一致性的問題,若資料庫更新資料,而Redis未更新,用戶可能會查到舊資料。
⭐ 結論
主從式架構的好處是能夠分散資料庫讀寫的負載。雖然現代已有許多參考的作法,但實際操作還是要確保Slave節點的資料正確性,並且也要考慮若是Slave節點失效,後續的Failover機制。
如何增強資料庫查詢的效能,一直是工程師努力的課題。我在職涯的前兩份工作都有接手主從式架構的資料庫系統設計,此後,我都對這類系統抱持著敬畏的態度,了解到系統的背後,若不是有無數個勤勤懇懇的工程師,就是有強大的東方神秘力量支持著。
