2014年7月14日 星期一

MySQL Fabric - 為您的應用系統提供高可用、高擴充性的資料庫

MySQL Fabric
- 為您的應用系統提供高可用、高擴充性的資料庫

Oracle在今年5月初推出了一套為各方寄以厚望的在MySQL產品 – MySQL Fabric,單從字面上似乎不太能看出它是啥咪碗糕,但是由名稱上還是有跡可循的,”Fabric”"""織品",這意味著它是用來"""一片”MySQL資料庫。MySQL Fabric是一套資料庫伺服器場(Database Server Farm)的架構管理系統。

MySQL Fabric是什麼?
MySQL Fabric 能 『組織』多個MySQL資料庫,使應用系統能將大於幾TB的表分散到多個資料庫 – 做Data Shard(或資料分片);在同一分片之內又可以含多個資料庫,並且由Fabric自動挑一個適合的(有最新的交易的資料)當主資料庫,其他的資料庫自動配置成從資料庫 - 做資料庫主從複製;進而在主資料庫當機時由各從資料中挑一個適合的提升為主資料庫,那麼其他的從資料庫自動轉向這個新的主資料庫找新的交易資料來複製。注意,這裡所說的 『自動』是指由MySQL Fabric在背後為您完成,您不需要手動參與這些更改配置的動作。最重要的MySQL FabricGPL的開源軟體,也就是在符合GPL的規範下您可以自由的使用及修改這個軟體。
 
MySQL Fabric要決解的問題

為什麼要做Data Shard?當您的應用需要處理的表有大於1TB的資料時,Data Shard常常就是一個不得不為之惡。這麼大的表不論在查詢、更新的效率上,或是備份、更改結構所需要的時間上都會造成窒礙難行的問題。然而當您將這樣大的表分散到多個資料庫伺服器上,又會使每一台資料庫伺服器都可能是單點固障點,只要有一台當機就會使整個系統的查詢都會有問題,另一方面應用端的程式也會因為每個查詢都要依其查詢條件(where子句的內容)分別指向不同的資料庫而變得更為複雜。再者,當Data Shard的結構改變時(例如增加一個資料庫)會使應用端所有的程式都必需修改,而使維護變得即為複雜。
為了解決應用程式複雜度增加的問題,有人在應用端和資料庫之間加了一個代理器(proxy)或者稱為switch,應用端所有對資料庫的指令先送到switch,再由switch判斷要轉到那一個資料庫,右圖是這個方案的示意架構。這也許可以解決應用端程式複雜度的問題,但是當應用端的數量增加,資料庫分片增加或系統的壓力增加時,這個switch會成為容量及性能的瓶頸和單點固障(當它當機時所有的應用端都找不到資料庫),而且所有對資料庫的指令均要傳兩次(先到switch再到資料庫),每個查詢都會造成額外的負荷,而能降低應用系統的效能。
MySQL Fabric的架構
MySQL Fabric則採取不一樣的做法,其架構如下圖所示,主要的特點是把switch合併到各應用端的connector(或是driver)中,以解決單一switch的單點固障和性能瓶頸的問題。。MySQL Fabric主要由三個部份所構成:



1.MySQL Fabric管理節點:
是一個Python脚本,由它整個架構的核心,MySQL Fabric管理節點主要的功能是管理整個資料庫伺服器場(server farm),它開啟時會找/etc/mysql/fabric.cnf配置檔(或以—config參數指定配置檔),由它指定fabric背後當成存放Server Farm架構和配置之repositoryMySQL資料庫位置、所用的端口、和連線帳號等資訊,Fabric在初始化時(執行mysqlfabric manage setup命令),會在MySQL資料庫上開一個schema (通常是名稱為fabricdatabase),存放server farm配置相關的資料,例如那些伺服器組由那些MySQL 資料庫構成,各伺服器組中以那一個MySQL資料庫為主那些為從,各分庫的表要拆分到那些伺服器組中,各shard table要以那個欄位的內容做拆分,拆分的政策為何(RANGE,KEY)?如果是RANGE拆分,各組存放的是那些範圍(例如<1000 font="">的存第一個shard, >1000的存於第二個shard)MySQL Fabric節點在設定配置時會對server farm中各MySQL資料庫下達建立主從複製的指令(下圖紅色線條),在正常運時會定期pin各組的主資料庫,當它發現主資料庫沒有正運作,它會啟動固障移轉程序,在該server farm的從資料庫中找一個適合的提升為主,其他的從資料庫轉向新的主資料庫繼續複製交易資料。

2.資料庫伺服器場(database server farm)
是整個架構中的工作引擎,在傳統的資料庫應用中這是單一MySQL資料庫,MySQL Fabric則是以多個資料庫支持大資料量表(TB級以上的表)和高可用資料庫的需求。這些資料庫分成幾個高可用組(HA Group或稱為server group),每個組包含一個以上的資料庫伺服器,上圖中最下面幾個灰色和淺藍色的圓角方塊代表高可用組,如果高可用組中有多個資料庫,MySQL Fabric(mysqlfabric group promote 指令)自其中挑一個提升為主資料庫,其他資料庫則成為從資料庫,從資料庫複製主資料庫的變化 - 完成設定同一高可用組內的主從複製。自此以後Fabric會定期監看這個主資料庫,當主資料庫當機時,Fabric會自該高可用組內的從資料庫中挑一個提升為主資料庫,其他的資料庫會轉向這個新的主資料庫繼續複製。另一方面MySQL Fabric也會指示應用端的connector對這些主從資料庫做讀寫分離,當應用程式對資料庫做讀寫兼具的交易性操作,connector會將交易性指令送到主資料庫,如果某一段應用程式只會對資料庫下讀的指令,且連線的read_only參數調為”ON”,則所有的查詢均輪流送到這幾個從資料庫。藉由讀寫分離,應用系統的資料處理能量得以增加。此外,如前一段所描述的MySQL Fabric還能處理需要拆分到多個資料庫服務器的表(sharding tables),每一個高可用組(上圖灰色圓角方塊)都可能存放shard table的部份資料,應用端的connector會將對shard table的指令依MySQL Fabric管理節點的設定送到不同的高可用組,如此可使資料庫的容量隨著高可用組的數量呈同比例的增長。同時,對非拆分的表所下的指令和所有的DDL會由Connector送到全域性高可用組(Global Group,上圖淺藍色的圓角方塊),全域性組的主資料庫又被MySQL Fabric設為其他高可用組的主資料庫,所有存拆分表的高可用組的主資料庫會複製global group的變異,這麼一來其他高可組都有一份非拆分表的資料,而使SQL中拆分表對非拆分表的JOIN操作(由於所需的資料都在同一資料庫中)變得更簡單。例如在一個訂單系統中有ORDERORDER_LINEPRODUCT三個表,ORDERORDER_LINE依客戶代號(customer_id)KEY shardPRODUCT表不拆分,則每個高可用組的資料庫有一部份ORDERORDER_LINE表的資料,在做過正規化的ORDER_LINE表只有參照PRODUCT的外鍵加在product_id欄位上不會有product_name欄位,如果要查各ORDER_LINE買的是什麼產品和產品名稱,必需在SQL指令中JOIN PRODUCT表,由於PRODUCT表的操作都先打到Global Group,再複製到各高可用組(Global Group的從資料庫),如此使得ORDER_LINE JOIN PRODUCT的指令可找到所有需要的PRODUCT之資料。

3.Connector
應用系統在運作時,每個SQL指令會經由connector送到資料庫。MySQL Fabric所搭配的connector和一般使用單機的MySQL資料庫一樣,只是在較新版的connectorfabric aware connector多了一些能處理資料庫伺服器場(database server farm)的功能,使它們能在建立資料庫連線時,XML-RPC協定查一下MySQL Fabric的管理節點中server farm的配置,然後透過該連線所下的查詢可依Fabric的指示送到適當的資料庫,如此一來就常見的database shard方案中可能造成效能瓶頸和單點固障的proxy(或圖一中的switch)收到Connector裡面,從而解決這些問題(由各應用端的database driver決定要將指令送到那一個資料庫)。目前MySQL Fabric支援的技術有JavaPythonPHP,即Connector/JConnector/PythonConnecotr/PHP都是Fabric-aware。以Java為例,JDBC driver 必需是Connector/J 5.1.30以後的版本(可自網址dev.mysql.com/download下載)FabircJava程式和一般對單機MySQL的查詢的Java程式差不多,只是在建database connection objectdatabase conneciton URL不是指向資料庫,改為指向MySQL Fabric管理節點(伺服器的IP和端口-通常是32274)。當查詢的表是全域性表(不做table shard)DDL(例如建表或改表結構)時,建立connection object的要加上 “fabricServerGroup=參數 ,之後透過這個connection object所下的SQL 指令會送到Global Group的主資料庫,再由資料庫複製到其他的高可用組(shard)中。如果SQL指令所要操作的表是分區表(shard table),則建立connection object時要在參數加上 “fabricShardTable=,之後透過這個connection object所下的SQL 指令會依MySQL Fabirc所設定的分表(shard)原則送到各分區(shard)的高可用組。這樣一來應用程式對這些shard tableSQL指令時不需在SQL中判斷要送到那個資料庫,完全由Connector在建立資料庫連線(connection)時向MySQL Fabric 所查到的server farm的配置資訊(那個資料庫屬於那個shard group、各shard table的拆分原則為何...)所決定,而且這個配置在建主連線後就緩存(cache)Connector所在的應用端(Java memory heapPythonPHPcache),如此在每次下SQL指令時不需要重復查MySQL Fabric管理節點,而依存於應用端的分表配置直接送到正確的資料庫而使應用程式的效能不會因為要做表拆分(table shard)而有任何降低。

結論
MySQL Fabric推出正式發行版才兩個多月,已經引起許多重量級MySQL用戶的注意和試用,而Oracle也不吝於加大對它投資,以加速使其功能更趨完善,在現在已推出了一個更新版,在最新版的MySQL Fabric 加上了對SSL連線的支持,近期內對Fabric改良的重點將著重於使Fabric對應用程式更透明化(例如單一個SQLshard table的查詢條件可以跨shard)、支援更多的高可用方案(例如高可用組之內的MySQL可以DRBD做高可用或用MySQL Cluster)、提供更友善易用的使用介面等。在此建議關心MySQL發展的朋友可以留意這個產品的發展,進一步試用它,將您的意見和心得(或發現的bug)反應給Oracle,如果您滿意它所提供的功能和穏定度,可以將它放入您的投產系統正式營運,Fabric的開發團會很歡迎大家對這個MySQL家族的新成員所做的任何貢獻。本篇文章的目的在于介紹MySQL Fabric要解決的問題和Fabric的架構,至於詳細的設定和操作步驟 ,容我在下一個文章中以一個範例和各位分享,敬請祈待。