MySQL 技術內幕——MySQL Cluster

高可用性(High Availability)指的是通過儘量縮短因日常維護操作(計劃)和突發的系統崩潰(非計劃)所導致的停機時間,以提高系統和應用的可用性。常見的高可用衡量指標有 5 個 9、4 個 9、3 個 9,例如 5 個 9 即 99.999%,意味着每年只能有 (365 * 24 * 60) * (1 - 0.99999) = 5.256 分鐘不可用。高可用的指標需要結合業務和成本來選擇。

如何實現高可用?

  • 避免導致系統不可用的因素(服務器磁盤空間耗盡、性能糟糕的SQL、表結構和索引沒有優化、主從數據不一致、人爲的操作失誤等等),減少系統不可用的時間;
    • 建立完善的監控及報警系統;
    • 定時的對備份數據進行恢復測試;
    • 正確配置數據庫環境;
    • 從服務器一定要配置成只讀的,這樣能減少很多因爲主從不一致而出現的故障;
    • 對不需要的數據進行歸檔和清理;
  • 增加系統的冗餘,保證發生系統不可用時可以儘快恢復;
    • 避免存儲單點故障(單純的主從複製架構並不能解決主庫的單點問題);
    • 主從切換及故障轉移;

如何解決 MySQL 庫的單點故障?

  • 主庫切換後,如何通知新的主服務器的IP地址?
  • 如何檢查 MySQL 主庫是否可用?
  • 如何處理從服務器和新主服務器之間的那種複製關係?

下面來看一下這些問題。

1.MMM架構

MMM(Multi-Master Replication Manager)是 MySQL 多組複製的簡稱,它是由 Perl 語言開發的用於管理 MySQL 主主同步架構的工具集。主要作用就是監控和管理 MySQL 的主主複製拓撲,並在當前的主服務器失效時,進行主和主備服務器之間的主從切換和故障轉移等工作。

MMM 提供了什麼功能?

  • 監控 MySQL 主從複製健康情況(MMM 架構同一時間只有一臺主服務器對外提供服務,另外的主備服務器只能用於查詢);
  • 在主庫出現宕機時進行故障轉移並自動配置其他從對新主的複製。
    • 如何找到從庫對應的新的主庫日誌點的日誌同步點?如果存在多個從庫出現數據不一致的情況如何處理?MMM 對這一塊的處理並不安全。MMM 只是簡單粗暴的找到新的主庫當前的日誌點,然後使從庫對這個日誌點進行同步。在一個繁忙的系統中使用 MMM 很有可能造成數據丟失的情況。
  • 提供了一個寫虛擬 IP 和多個讀虛擬 IP,寫虛擬 IP 只能在主數據庫之間進行切換,讀虛擬 IP 則可以在服務器所有主從節點進行切換。在主從服務器出現問題時可以自動遷移虛擬 IP。

MMM 架構圖:

MMM 架構圖

MMM 部署所需資源:

資源名稱 數量 說明
主DB服務器 2 用於主備模式的主主複製配置
從DB服務器 0-N 可以配置0臺或多臺服務器,但不建議太多
監控服務器 1 用於監控MySQL複製集羣
IP地址 2 * (N+1) N爲MySQL服務器的數量
監控用戶 1 用於監控數據庫狀態的MySQL用戶(replication client)
代理用戶 1 用於MMM代理的MySQL用戶(super, replication client, process)
複製用戶 1 用於配置MySQL複製的MySQL用戶(replication slave)

MMM 架構優點:

  • 使用Perl腳本語言開發及完全開源;
  • 提供了讀寫 VIP (虛擬IP),使服務器角色的變更對前端應用透明;
  • 提供了對從服務器的延遲監控;
  • 提供了主數據庫故障轉移後,從服務器對新主服務器的重新同步功能;
  • 很容易對發生故障的主數據庫重新上線;

MMM 架構缺點:

  • 發佈時間比較早,不支持 MySQL 新的複製功能;
  • 在進行主從切換時,容易造成數據丟失;
  • MMM監控服務存在單點故障;
  • 沒有讀負載均衡的功能。

2.MHA架構

MHA(Master High Availability)也是由 Perl 語言開發的,在 MySQL 高可用方面是一個相對成熟的解決方案。

MHA 完成主從切換超高效,基本上在 30 秒內完成主從切換,並且在切換過程中最大程度的保證數據一致性。達到真正意義上的高可用。

MHA 提供了什麼功能?

  • 監控主數據庫服務器是否可用;
  • 當主DB不可用時,MHA可以從多個從服務器中選舉出一個新的主數據庫服務器;
  • 提供了主從切換和故障轉移功能;

MHA 是如何進行主從切換的?

  1. 嘗試從出現故障的主數據庫中保存二進制日誌(與MMM最大的不同,這一步不是總能成功的,當主數據庫硬件本身無法訪問時,則不能成功保存二進制日誌);
  2. 從多個可用的從服務器中識別出含有最新更新的那個從服務器,並把這個從服務器作爲新的備選主服務器;
  3. 在備選主服務器和其他從服務器之間同步差異二進制數據;
  4. 新的備選主服務器會存放從原主服務器上保存下來的二進制日誌(前提是保存下來了,這一步如果出現錯誤,例如重複的主鍵等,會使MHA停止進行故障轉移);
  5. 提升備選主服務器作爲新的主服務器;
  6. 遷移集羣中其他的從服務器作爲新的主服務器的從服務器。

MHA 架構圖:

MHA 架構圖

MHA 支持 GTID 的複製,而 MMM 不支持,GTID 也是安全性比較高的一種複製模式,配合 MHA 使用也是更加的合理。

MHA 配置步驟:

  1. 配置集羣內所有主機的 SSH 免認證登陸(比如故障轉移過程中保存原主服務器二進制日誌,配置虛擬IP地址等);
  2. 所有 DB 服務器安裝 MHA-node軟件包,監控服務器安裝 MHA-manager 軟件包;
  3. 建立主從複製集羣(MHA支持基於日誌點的複製和基於GTID的複製,這裏推薦使用基於GTID的複製);
  4. 配置 MHA 管理節點;
  5. 使用 masterha_check_ssh 和 masterha_check_repl 對配置進行檢驗;
  6. 啓動並測試 MHA 服務。

MHA 架構優點:

  • 使用Perl腳本語言開發及完全開源;
  • 可以支持基於 GTID 的複製模式;
  • MHA 在進行故障轉移時更不易產生數據丟失;
  • 同一個監控節點可以監控多個集羣;

MHA 架構缺點:

  • MHA 的配置中沒有主從 VIP 的配置,需要編寫腳本或利用第三方工具來實現 VIP 的配置;
  • MHA 啓動後只會對主數據庫進行監控,無法發現複製鏈路中的問題(例如主從延遲增大,複製鏈路中斷等);
  • 需要基於 SSH 免認證配置,存在一定的安全隱患;
  • 沒有讀負載均衡的功能。

3.讀寫分離和負載均衡

爲什麼要讀寫分離?

寫負載是不能夠分擔的,而且只能在主庫上進行寫操作。讀操作主從上都可以。爲了分擔主庫的讀負載,就需要進行讀寫分離,寫操作只能在主庫上進行,而讀操作儘量的在從庫上完成。

讀寫分離
而完成讀寫分離後,對於讀操作,如何分配多個服務器的讀操作,這就需要我們進行讀的負載均衡了。

目前實現讀寫分離有兩種方式:

  • 由程序實現讀寫分離;
  • 由中間件實現讀寫分離,例如 mysql-proxy(高併發下存在一定的問題)、maxScale(相對來說性能損耗小);
- 優點 缺點
由程序實現讀寫分離 1、由開發人員控制什麼樣的查詢在從庫中執行,比較靈活;
2、由程序直接連接數據,性能損耗比較少;
3、架構簡單;
1、增加了開發的工作量,使程序代碼更加複雜;
2、人爲控制,容易出現錯誤;
由中間件實現讀寫分離 1、由中間件根據查詢語法分析,自動完成讀寫分離;
2、對程序透明,對於已有程序不用做任何調整;
1、由於增加了中間層,所以對查詢性能有損耗(經測試,QPS可能降低50%-70%);
2、對於延遲敏感的業務,無法自動在主庫執行,不靈活;

4.分表分庫

隨着業務的不斷增長,數據庫中的數據也會越來越多,數據庫的壓力會越來越大,我們會發現,在業務繁忙的時候,數據庫的性能會直線下降,這時爲了保證良好的性能,需要想辦法分擔數據庫的壓力。分擔數據庫的讀負載可以使用主從複製的方式,增加只讀從數據庫,通過讀寫分離的方式把數據庫的讀負載分擔到不同的從數據庫中,這時在一段時間內已經可以解決問題了。隨着業務的發展,會發現,單一的主數據庫已經無法承擔寫負載了,那麼這時就需要對單一的主數據庫進行拆分了,通常來說,對主數據庫的拆分有下面幾種方式:

  • 把一個實例中的多個數據庫拆分到不同的實例;
  • 把一個庫中的表分離到不同的數據庫中;

1. 數據庫分片

爲了解決上面的問題,我們需要對一個庫中的相關表進行水平拆分到不同實例的數據庫中,即需要進行分片處理,我們通常所說的分庫分表,大多數情況下指的就是這種方式。

數據庫分片後,數據通常是存放在不同的物理節點上,數據庫的分片並不像我們前面所說的第二種分庫分表的方式容易實現,要對原來一個獨立的數據庫進行分片,我們需要考慮很多問題,通常來說,不是萬不得已,不建議對數據庫進行分片。分片後數據庫會變得難以維護。

例如對訂單表進行分片,會將訂單表分成多個相同表結構的訂單表,多個訂單表可能會分佈在不同的物理節點中:

訂單表
訂單表1
訂單表2
訂單表3

數據庫分片前的準備:

在進行數據庫分片前,最重要的一項工作就是如何選擇分區鍵。分區鍵決定了我們如何對數據庫進行分片,以及分片後如何查詢數據。分區鍵選擇的是否合適直接決定了分區後數據庫的性能,對於分區鍵的選擇,我們應該做到以下幾點:

  • 分區鍵要能儘量避免跨分片查詢的發生;
  • 分區鍵要能儘量使各個分片中的數據平均。

如何存儲無需分片的表?

  • 方案一:每個分片中存儲一份相同(冗餘)的數據。這種方式可以更好的提高查詢效率。如果使用這種方式,對於維護每個分片中相同表的一致性就顯得非常重要了,一般可以採用多寫的方式維護數據;
  • 方案二:使用額外的節點統一存儲。好處是不存在數據冗餘問題。如果分片的表與統一存儲的表需要關聯查詢時,就只能由程序分別查詢後進行合併操作了,查詢效率比方案一要差一些。

如何在節點上部署分片?

  • 方案一:每個分片使用單一數據庫,並且數據庫名也相同;
  • 方案二:將多個分片表存儲在一個數據庫中, 由於數據的表不能重名,所以需要在表名上加入分片號後綴;
  • 方案三:在一個節點中部署多個數據庫,每個數據庫包含一個分片。

如何分配分片中的數據?

  • 方案一:按分區鍵的 Hash 值取模來分配分片數據。優點是可以相對平均的,在各個分片中分配數據,缺點是很難人爲的控制什麼樣的數據分配到哪個分片中;
  • 方案二:按分區鍵的範圍來分配分片數據。常用於分區鍵是日期類型或數值類型的情況,優點是可以很清楚的知道某條數據分配到了哪個分片中,缺點是很容易產生數據分配不平均和數據訪問量不平均的情況;
  • 方案三:利用分區鍵和分片的映射表來分配分片數據,這張映射表需要使用緩存的方式進行緩存,否則這張映射表就可能會成爲系統的瓶頸。

如何生成全局唯一ID?

  • 方案一:使用 auto_increment_increment 和 auto_increment_offset 參數;
  • 方案二:使用全局節點來生成ID;
  • 方案三:使用 Redis 等緩存服務器中創建全局 ID。

分片工具?oneProxyp。

5.數據庫監控

對於任何系統來說,監控都是重要的組成部分。數據庫是一切系統的核心組件,數據庫的穩定性從一定程度上決定了系統的穩定性,所以,對於數據庫的監控,就顯得尤爲重要了。常見的開源監控軟件有 Nagios、Zabbix。這些監控軟件,或是提供了數據庫監控插件,或是允許用戶以插件的形式開發自己對數據庫的監控腳本,並且支持的腳本語言也是多種多樣的,用戶完全可以按照自己的習慣,來選擇自己的監控軟件,以及編寫適合自己的監控腳本。

本篇主要關注 MySQL 數據庫我們都要監控些什麼?和怎麼對這些要監控的資源進行監控?

瞭解了這些之後,不管使用任何監控軟件,都可以自己完成對 MySQL 腳本的開發與部署。

對於 MySQL 來說,最基本的監控應該包含以下內容:

  • 對數據庫服務可用性進行監控(通過網絡連接到數據庫並且確定數據庫是可以對外提供服務的);
  • 對數據庫性能進行監控(QPS、TPS、併發線程數量的監控);
  • 對主從複製進行監控(主從複製鏈路狀態的監控、主從複製延遲的監控、定期的確認主從複製的數據是否一致);
  • 對服務器資源的監控(磁盤空間的監控(無論是數據目錄還是日誌目錄的空間被佔滿,都會導致 MySQL 不可用)、CPU 的使用情況、內存的使用情況、Swap 分區的使用情況以及網絡 IO 的情況等);

1.數據可用性監控

首先我們先來看下如何確認數據庫是否可以通過網絡進行連接。使用 MySQL 的本地的 SQL 文件連接數據庫服務器,並不意味着可以通過網絡 TCP/IP 協議能連接到 MySQL。確認數據庫是否可以通過網絡進行連接,通常使用以下幾種方式中的一種:

  • 方案一:利用 mysqladmin -umonitor_user -p -h ping 命令在遠程服務器上執行,來確認被監控的服務器是否可以連接;
  • 方案二:利用 telnet ip db_port 命令手動確認被監控的服務器是否可以連接;
  • 方案三:使用程序通過網絡建立數據庫連接來確認被監控的服務器是否可以連接,這是最好的方式。

可以連接到數據庫並不代表數據庫就是可用的,所以還需要確認數據庫是否可以讀寫。

如何確認數據庫是否可讀寫?

  • 定期檢查主數據庫的 read_only 參數是否爲 off;
  • 建立監控表並對錶中數據進行更改;
  • 如果只是監控數據庫是否可讀只需要執行簡單的查詢 select @@version;

可以連接到MySQL 的線程數是有限制的,如何監控數據庫的連接數?

show variables like 'max_connections';   //獲取MySQL能接受最大連接數的數量
show global status like 'Threads_connected';   //獲取系統變量Threads_connected的值,記錄了當前數據庫的連接數量

例如報警就可以當 Threads_connected / max_connections > 0.8 時,就需要報警。

2.數據性能監控

性能監控不同於可用性監控,性能監控更關注的是數據庫性能的變化趨勢,所以在進行性能監控的腳本開發時,就需要注意記錄好性能監控過程中所採集到的數據庫的狀態信息,以便分析數據庫性能變化趨勢時使用。

對於性能監控來說,可能關注最多的就是 QPS 和 TPS。

QPS = (Queries2 - Queries1) / (Uptime_since_flush_status2 - Uptime_since_flush_status1)

TPS = ((Com_insert2 + Com_update2 + Com_delete2) - (Com_insert1+ Com_update1 + Com_delete1)) /
(Uptime_since_flush_status2 - Uptime_since_flush_status1)

這幾個參數獲取方式:

show global status like 'Queries'
show global status like 'Uptime_since_flush_status'
show global status like 'Com_insert'
show global status like 'Com_update'
show global status like 'Com_delete'

如何監控數據庫的併發請求數量?

通常情況下,數據庫系統的性能會隨着併發處理請求數量的增加而下降。所以併發請求數量通常還需要和 CPU 的使用率等指標結合起來分析。

數據庫當前併發請求數量可以通過 show global status like ‘Threads_running’ 獲取。併發處理的數量通常會遠小於同一時間連接到數據庫的線程的數量。

通常情況下併發請求數量是很穩定的,如果我們發現某一時刻併發量突然間增大,那麼就需要檢查是否出現了數據庫的異常,比如數據庫出現大量阻塞的情況下,就很有可能出現這種現象。

如何監控 InnoDB 的阻塞?

查詢阻塞時間超過 20 秒的 SQL:

SELECT b.trx_mysql_thread_id AS '被阻塞線程'
		,b.trx_query AS '被阻塞SQL'
		,c.trx_mysql_thread_id AS '阻塞線程'
		,c.trx_query AS '阻塞SQL'
		,(UNIX_TIMESTAMP()-UNIX_TIMESTAMP(c.trx_started)) AS '阻塞時間'
FROM information_schema.innodb_lock_waits a
JOIN information_schema.innodb_trx b ON a.requesting_trx_id=b.trx_id
JOIN information_schema.innodb_trx c ON a.blocking_trx_id=c.trx_id
WHERE (UNIX_TIMESTAMP()-UNIX_TIMESTAMP(c.trx_started))>20
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章