如果將應用的所有資料簡單地放在一臺 MySQL 伺服器例項上,就不用談什麼擴充套件性了。但是業務能穩定持續的增長,那麼應用肯定會碰到效能瓶頸。
對於很多型別的應用而言,購買更高效能的機器能解決一大部分效能問題,這也是我們常說的 “垂直擴充套件” 或者 “向上擴充套件”。
另一個與之相反的方法是將任務分配的多臺機器上,這通常被稱為 “水平擴充套件” 或者 “向外擴充套件”。
接下來,我們將討論如何聯合使用向上擴充套件和向外擴充套件,以及如何使用叢集方案來進行擴充套件。
最後,大部分應用還會有一些很少或者從不需要的資料,這些資料可以被清理或歸檔,我們可以稱這種方案為 “向內擴充套件”。
1 向上擴充套件
向上擴充套件(也叫垂直擴充套件)意味著購買更多效能強悍的機器。這種策略有較多優點:
- 更容易維護和開發,顯著節約開銷;
- 單臺伺服器備份和恢復較為簡單,無需關心一致性;
因此,從複雜性的成本來說,大多時候,向上擴充套件比向外擴充套件更簡單。
另外,不要覺得向上擴充套件很快就走到“盡頭”,要相信科技的進步速度。現在,擁有 0.5TB 記憶體、32 核(或者更多)CPU 以及更強悍 I/O 效能的商用伺服器很容易獲得。優秀的應用和資料庫設計,再加上很好的效能優化技能,已經可以滿足絕大多數商業應用。
不過遺憾的,雖然高效能伺服器比較容易獲得,但是 MySQL 並不能擴充套件到對應的規模。為了更好地在大型伺服器上執行 MySQL,一定要儘量選擇最新的版本。即使如此,當前合理的 “收益遞減點” 的機器配置大約是:
- 256G RAM
- 32 核 CPU
- PCIe flash 驅動器
如果繼續提升硬體配置,MySQL 效能雖然還能有所提升,但價效比就會降低。
因此,我們建議,如果系統確實有可能碰到可規劃性的天花板,並且會導致嚴重的業務問題,那就不要無限制的做向上擴充套件的規劃。對於龐大的應用,可以短期內購買更優的伺服器,但最終還是需要向外擴充套件的。
2 向外擴充套件
向外擴充套件(也叫橫向擴充套件或水平擴充套件)策略通常分為三個部分:複製、拆分和資料分片。
最常見的向外擴充套件就是讀寫分離。通過複製將資料分發到多個伺服器上,然後將備庫用於讀查詢。這種技術對於以讀為主的應用很有效。
另一個比較常見的向外擴充套件方法是將工作負載分佈到多個 “節點”。接下來我們要了解的主要是這種擴充套件方法。
在此之前,我們先明確下節點的概念。在 MySQL 架構中,一個節點就是一個功能部件。一般的,我們會將一臺伺服器作為一個幾點。但如果我們考慮到節點的高可用性,那麼一個節點通常可能是下面的幾種:
- 一個主 - 主 複製雙機結構,擁有一個主動伺服器和被動伺服器。
- 一個主庫和多個備庫。
- 一個主動伺服器,並使用分散式複製塊裝置(DRBD)作為備用伺服器。
- 一個基於儲存區域網路(SAN)的 “叢集”。
2.1 按功能拆分
按功能拆分,或者說按職責拆分,意味著不同的節點執行不同的任務。
例如,如果有一個網站,各個部分無需共享資料,那麼可以按照網站的功能區域進行劃分。像我們常見的入口網站,一般都是把不同欄目放在一起,但實際上可以將網站新聞、論壇、尋求支援等功能放到專用的 MySQL 伺服器。如圖 2-1
2.2 資料分片
在目前用於擴充套件大型 MySQL 應用的方案中,資料分片是最通用且最成功的方法。它把資料分割成一小片,或者說一塊,然後儲存到不同的節點中。
在使用分片前,要牢記一個通用原則:如非必要,儘量不分片。
除此之前,對於分片,我們只會對需要的資料做分片。這裡 “需要的資料” 通常是那些增長非常龐大的資料。而像對於使用者資訊這些全域性資料,一般是儲存在單個節點上,通常儲存在類似 redis 這樣的快取中。
對於分片,我們通常要考慮下列問題:
- 選擇合適的分割槽鍵(partition key)。
- 是否需要多個分割槽鍵?
- 跨分片查詢如何處理?
- 如何分片資料、分片和節點?
- 如何在節點上部署分片?
- 如何生成全域性唯一 ID?
2.3 通過多例項擴充套件
上面提到過,MySQL 不能完全發揮現代硬體的效能。當擴充套件到超過 24 個 CPU 核心時,MySQL 的效能開始趨於平緩,不再上升。當記憶體超過 128G 時也同樣如此。對於此種情況,我們可以通過多例項策略充分發揮硬體的效能。
多例項策略的基本思路是:
- 資料分片足夠小,可以使得在每臺機器上都能放置多個分片;
- 每臺伺服器執行多個例項;
- 給每個例項劃分伺服器的硬體資源;
可以看出,這是一種向上擴充套件和向外擴充套件的組合方案。這種方案還可以通過將每個 MySQL 例項繫結到特定的 CPU 核心上來優化效能。這種優化,主要有兩個好處:
- 由於 MySQL 內部的可擴充套件性限制,當核心數較少時,能夠在每個核心上獲得更好的效能;
- 當例項在多個核心上執行執行緒時,由於需要在多核心上同步共享資料,因而會有額外的開銷。
而我們把例項和 CPU 核心繫結後,可以減少 CPU 核心直接的切換和互動。要注意的,將程式繫結到具有相同物理套接字的核心上可以獲得最優的效果。
3 向內擴充套件
對於不斷增長的資料和負載,最簡單的方法是對不再需要的資料進行歸檔和清理。這種操作可能會帶來顯著的效果。這種做法並不能代替其他策略,但可以作為爭取時間的短期策略,也可以作為處理大資料量的長期計劃之一。
在設計歸檔和清理策略時需要考慮如下幾點:
- 對應用的影響。設計良好的歸檔系統能夠在不影響事務處理的情況下,從一個高負債的 OLTP 伺服器上移除資料。
- 要歸檔的行。考慮清楚哪些資料可以清理或歸檔。
- 維護資料一致性。資料間存在聯絡時,歸檔任務系統要能夠保證資料的邏輯一致性。
- 避免資料丟失。歸檔時要保證歸檔資料已經成功儲存,再講源資料刪除。
- 解除歸檔。考慮清楚歸檔系統中的解除歸檔策略。可以通過設定一些檢查點讓系統檢查是否有需要歸檔的資料。
如果不能及時的把老資料歸檔和清理時,我們也可以通過以下隔離冷熱資料的方式來提高效能:
- 將表劃分為幾個部分。分割大表中的冷熱資料,保證載入到記憶體中的資料中,熱資料的比例;
- MySQL 分割槽。使用MySQL 自帶的分割槽的功能,可以幫助我們把最近的資料留在記憶體中;
- 基於時間的資料分割槽。如果應用不斷有新資料儘量,一般新資料總是比舊資料更加活躍。因此,我們可以將新資料完整的保留在記憶體中,同時使用複製來保證主庫失效時有一份可以的備份,而舊資料就而言放到別的地方。
總結
- 向上氪金,向外氪腦。三思而後行。
- 能不分片,就儘量不分片。