Fabric是Oracle公司開發的既有分片又有讀寫分離的MySQL集羣管理工具,雖然我的以爲目前版本還有不少缺陷,但應該會逐步完善,未來會是一個不錯的工具。java
第一步:下載並安裝 Fabricpython
Fabric能夠從MySQL官網下載,她屬於MySQL Utilites裏,官方下載地址是http://dev.mysql.com/downloads/utilities/
mysql
我下載的是源碼版的,mysql-utilities-1.5.6.zip,由於是Python所寫,因此安裝跟C語言的不一樣:linux
$ unzip mysql-utilities-1.5.6.zip $ cd mysql-utilities-1.5.6/ $ python setup.py build $ sudo python setup.py install
安裝好後,原先的python腳本去掉了py後綴,默認放在/usr/local/bin/目錄下,可直接執行。sql
第一步:部署 MySQL5.6 多實例數據庫
運行Fabric前,咱們要先準備若干各數據庫,根據咱們的須要配置不一樣數量的數據庫,咱們先部署基本的讀寫分離的主從方式,Fabric的須要的利用MySQL的GTID特性進行主從複製,所以須要MySQL5.6以上版本,另外因爲MariaDB的GTID特性跟MySQL不一樣,Fabric不支持MariaDB,使用MariaDB的話有報錯。因此只能用MySQL5.6以上版本。bash
咱們至少須要部署3個MySQL實例才能看到Fabric的功效,服務器
做用 |
地址 |
端口 |
數據文件路徑 | 配置文件路徑 |
|
Fabric元數據庫 |
localhost |
10000 | /dev/shm/data/fa00 | fabric/fa00.cnf |
|
業務數據庫 1 | localhost | 10011 | /dev/shm/data/fa11 | fabric/fa11.cnf | |
localhost | 10012 | /dev/shm/data/fa12 | fabric/fa12.cnf |
TIP:因爲我在一臺電腦上啓動了不少數據庫,所以將數據文件都放在了內存硬盤中,個人機器默認有的是/dev/shm,其餘的機器根據會有所不一樣,如/run/shm等,這個路徑選擇可有可無,只要事先建立父目錄。由於使用內存硬盤,MySQL自身的內存需求下降,我下降了MySQL須要的內存使用量,這個也根據本身的狀況選擇。注:生產環境不可這樣配置。app
主從數據庫部署能夠參考文章:http://bangbangba.blog.51cto.com/3180873/1701857dom
和 http://bangbangba.blog.51cto.com/3180873/1702294
下面咱們仍是先修改配置文件,須要修改的內容以下:(以fa00.cnf舉例)
# 請自行調整前面6行的數字,每一個數據庫都不能相同,這裏是改了最後兩個00對應的數字。 [client] port = 10000 socket = /tmp/fa00.sock [mysqld] port = 10000 socket = /tmp/fa00.sock datadir = /dev/shm/data/fa00 server-id = 10000 user = lyw # 主從複製相關 log-bin=mysql-bin gtid-mode = on log-slave-updates = true enforce-gtid-consistency= true # 文件、內存大小,節約內存。 innodb_buffer_pool_size = 32M innodb_log_file_size = 5M
修改好3個文件配置文件 fa00.cnf,fa11.cnf,fa12.cnf 後,咱們初始化數據,而且啓動,此次咱們採用批量操做的方式,減小工做量。在mysql目錄下建立以下腳本init_start.sh和初始化數據庫文件fabric.sql,並執行init_start.sh,便可建立全部數據庫,並啓動。
fabric.sql 內容爲:
use mysql; delete from user where user=''; flush privileges; grant all on *.* to 'fabric'@'%' identified by '123456'; create database lyw; reset master;
init_start.sh 內容爲:
#! /bin/bash mkdir -p /dev/shm/data for cnf in `ls fabric/*.cnf` do scripts/mysql_install_db --defaults-file=$cnf bin/mysqld --defaults-file=$cnf & done # 等待一下,讓mysqld啓動完成, sleep 3 for cnf in `ls fabric/*.cnf` do bin/mysql --defaults-file=$cnf -uroot < fabric.sql done
準備好腳本後,執行init_start.sh即完成全部數據庫的初始化和啓動工做,能夠啓動mysql客戶端檢查下數據庫是否都初始化好。Fabric不須要主動執行change master to這行sql語句來開啓主從,而是交由Fabric自身去執行。到此數據庫以準備好,接下來開始真正的Fabric配置。
第三步:Fabric 讀寫分離主從配置
fabric的默認配置文件路徑爲/usr/local/etc/mysql/fabric.cfg,其餘安裝方法會是/etc/mysql/fabric.cfg(其餘系統根據本身狀況配置)所以爲了方便後面的操做,咱們仍是使用這個配置文件,固然也能夠用--config 參數指定配置文件。
fabric.cfg內容以下:
[DEFAULT] prefix = /usr/local sysconfdir = /usr/local/etc logdir = /var/log # storage 配置的是fabric元數據存儲的數據庫 [storage] address = localhost:10000 user = fabric password = 123456 database = fabric auth_plugin = mysql_native_password connection_timeout = 6 connection_attempts = 6 connection_delay = 1 [servers] user = fabric password = 123456 backup_user = fabric_backup backup_password = secret restore_user = fabric_restore restore_password = secret unreachable_timeout = 5 # fabric對外的協議,這裏是xmlrpc協議 [protocol.xmlrpc] address = localhost:32274 threads = 5 user = admin password = 123456 disable_authentication = yes realm = MySQL Fabric ssl_ca = ssl_cert = ssl_key = # fabric對外的協議,這裏是mysql協議,能用mysql鏈接,可是不能跟普通數據庫同樣操做 [protocol.mysql] address = localhost:32275 user = admin password = 123456 disable_authentication = yes ssl_ca = ssl_cert = ssl_key = [executor] executors = 5 [logging] level = INFO url = file:///var/log/fabric.log [sharding] mysqldump_program = /usr/bin/mysqldump mysqlclient_program = /usr/bin/mysql [statistics] prune_time = 3600 [failure_tracking] notifications = 300 notification_clients = 50 notification_interval = 60 failover_interval = 0 detections = 3 detection_interval = 6 detection_timeout = 1 prune_time = 3600 [connector] ttl = 1
配置好後,須要初始化fabric的元數據
$ mysqlfabric manage setup 。。。。。。 Finishing initial setup ======================= Password for admin user is not yet set. Password for admin/xmlrpc: 這裏須要設置admin的密碼 Repeat Password: 重複輸入密碼 Password set. Password set.
這時fa00這個數據庫已經有了fabric的元數據,咱們能夠用mysql客戶端查看。
而後啓動
$ mysqlfabric manage start
自此雖然啓動了fabric,可是尚未和前面配置的後兩個業務數據庫產生聯繫,接下來咱們須要用命令行創建聯繫。我先看一下mysqlfabric的分組相關幫助,
$ mysqlfabric help group Commands available in group 'group' are: group activate group_id [--synchronous] group description group_id [--description=NONE] [--synchronous] group deactivate group_id [--synchronous] group create group_id [--description=NONE] [--synchronous] group remove group_id server_id [--synchronous] group add group_id address [--timeout=NONE] [--update_only] [--synchronous] group health group_id group lookup_servers group_id [--server_id=NONE] [--status=NONE] [--mode=NONE] group destroy group_id [--synchronous] group demote group_id [--update_only] [--synchronous] group promote group_id [--slave_id=NONE] [--update_only] [--synchronous] group lookup_groups [--group_id=NONE]
咱們首先須要建立一個組group-1:
$ mysqlfabric group create group-1
而後將兩個業務數據庫10011和10012放入這個組中:
$ mysqlfabric group add group-1 127.0.0.1:10011 $ mysqlfabric group add group-1 127.0.0.1:10012
而後能夠查看這時group-1這個組的狀態
$ mysqlfabric group lookup_servers group-1 Fabric UUID: 5ca1ab1e-a007-feed-f00d-cab3fe13249e Time-To-Live: 1 server_uuid address status mode weight ------------------------------------ --------------- --------- --------- ------ d4919ca2-754a-11e5-8a5e-34238703623c 127.0.0.1:10011 SECONDARY READ_ONLY 1.0 d6597f06-754a-11e5-8a5e-34238703623c 127.0.0.1:10012 SECONDARY READ_ONLY 1.0
從status 和 mode 這兩個字段能夠看出,這個時候剛加入的兩個服務器尚未正式生效,都是做爲從庫只讀的身份,兩個庫尚未創建實質的聯繫,咱們須要將其中一個數據庫提高爲可寫的主:
$ mysqlfabric group promote group-1 $ mysqlfabric group lookup_servers group-1 Fabric UUID: 5ca1ab1e-a007-feed-f00d-cab3fe13249e Time-To-Live: 1 server_uuid address status mode weight ------------------------------------ --------------- --------- ---------- ------ d4919ca2-754a-11e5-8a5e-34238703623c 127.0.0.1:10011 SECONDARY READ_ONLY 1.0 d6597f06-754a-11e5-8a5e-34238703623c 127.0.0.1:10012 PRIMARY READ_WRITE 1.0
用promote命令提高後,其中一臺會被提高爲主數據庫,其餘的都爲從。主從也能夠經過mysql客戶端查看,在從庫執行下面的命令顯示以下,主庫執行則沒有信息
mysql> show slave status \G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 127.0.0.1 Master_User: fabric Master_Port: 10012 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 151 Relay_Log_File: lyw-hp-relay-bin.000002 Relay_Log_Pos: 361 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes 。。。。。。
至此主從方式以基本可用,咱們火燒眉毛地想要嘗試下客戶端如何使用了。官方提供python和java兩種客戶的,所以若是用Fabric,業務語言最好是這兩種。
Fabric是python所寫,咱們這裏就用python客戶端作例子,直接打開python交互界面
$ python Python 2.7.9 (default, Apr 2 2015, 15:33:21) [GCC 4.9.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import mysql.connector >>> from mysql.connector import fabric >>> conn = mysql.connector.connect(fabric={"host":"localhost", "port":32274, "username":"lyw", "password":"123456"}, user="fabric", password="123456", autocommit=True) >>> conn.set_property(group='group-1', scope=fabric.SCOPE_GLOBAL, mode=fabric.MODE_READWRITE) >>> cur = conn.cursor() >>> cur.execute('create database lyw') >>> cur.execute('use lyw;') >>> cur.execute('create table t1 (id int, v varchar(32))') >>> cur.execute('insert into t1 values(1, "aaa"), (2,"bbb")') >>> cur.execute('select * from t1') >>> cur.fetchall() [(1, u'aaa'), (2, u'bbb')] #下面切換到從庫下只讀數據,這時下面的sql語句是切換到了從庫執行,須要從新'use lyw' >>> conn.set_property(group='group-1', scope=fabric.SCOPE_GLOBAL, mode=fabric.MODE_READONLY) >>> cur.execute('use lyw') >>> cur.execute('select * from t1') >>> cur.fetchall() [(1, u'aaa'), (2, u'bbb')]
這個python例子能夠很好的看出主從方式下fabric的基本使用,
注意:請勿在從庫執行寫操做,不然數據會不符合預期,不會同步到主。
此時若是主數據庫掛了,那麼寫操做將不可用,fabric還不會自動切換,要想進行自動切換,須要執行如下命令:
$ mysqlfabric group activate group-1 主庫掛掉幾秒鐘後 $ mysqlfabric group lookup_servers group-1 Fabric UUID: 5ca1ab1e-a007-feed-f00d-cab3fe13249e Time-To-Live: 1 server_uuid address status mode weight ------------------------------------ --------------- ------- ---------- ------ a30d844d-7550-11e5-8a84-34238703623c 127.0.0.1:10011 PRIMARY READ_WRITE 1.0 a4d66a55-7550-11e5-8a84-34238703623c 127.0.0.1:10012 FAULTY READ_WRITE 1.0
而後咱們幹掉主庫,過幾秒種查看狀態,能夠發現從庫以切換爲主庫。原先的主庫變爲FAULTY
可是當掛掉的源主庫從新啓動時,不會自動加入到集羣裏面,須要先remove,再add回來才行。
$ mysqlfabric group remove group-1 127.0.0.1:10012 $ mysqlfabric group add group-1 127.0.0.1:10012 $ mysqlfabric group lookup_servers group-1 Fabric UUID: 5ca1ab1e-a007-feed-f00d-cab3fe13249e Time-To-Live: 1 server_uuid address status mode weight ------------------------------------ --------------- --------- ---------- ------ a30d844d-7550-11e5-8a84-34238703623c 127.0.0.1:10011 PRIMARY READ_WRITE 1.0 a4d66a55-7550-11e5-8a84-34238703623c 127.0.0.1:10012 SECONDARY READ_ONLY 1.0
狀態變爲只讀從庫,再去查數據,能夠發現宕機期間的數據被恢復(須要必定時間)
第四步:分片+主從 部署
咱們前面準備了不少腳本,部署已很方便,這裏我先拆除前面的數據,從新部署,讀者能夠根據本身喜愛操做。
咱們此次要部署以下列表的數據庫
做用 |
地址 |
端口 |
文件路徑 |
配置路徑 |
Fabric元數據 |
localhost |
10000 |
/dev/shm/data/fa00 | fabric/fa00.cnf |
業務數據庫 全局 |
localhost | 10091 | /dev/shm/data/fa91 | fabric/fa91.cnf |
localhost | 10092 | /dev/shm/data/fa92 | fabric/fa92.cnf | |
業務數據庫 1 | localhost | 10011 | /dev/shm/data/fa11 | fabric/fa11.cnf |
localhost | 10012 | /dev/shm/data/fa12 | fabric/fa12.cnf | |
業務數據庫 2 | localhost | 10021 | /dev/shm/data/fa21 | fabric/fa21.cnf |
localhost | 10022 | /dev/shm/data/fa22 | fabric/fa22.cnf | |
業務數據庫 3 | localhost | 10031 | /dev/shm/data/fa31 | fabric/fa31.cnf |
localhost | 10032 | /dev/shm/data/fa32 | fabric/fa32.cnf |
咱們複製以前的配置文件,修改其中的主要數據,準備好這9個配置文件fa00.cnf ~ fa32.cnf
而後咱們咱們初始化環境
$ sh init_start.sh $ mysqlfabric manage setup $ mysqlfabric manage start
只要3行就初始化完,輕鬆吧。
而後咱們要建立4個fabric組,group-g,group-1,group-2,group-3
$ mysqlfabric group create group-g $ mysqlfabric group create group-1 $ mysqlfabric group create group-2 $ mysqlfabric group create group-3
將數據庫放入這4個組中,
$ mysqlfabric group add group-g 127.0.0.1:10091 $ mysqlfabric group add group-g 127.0.0.1:10092 $ mysqlfabric group add group-1 127.0.0.1:10011 $ mysqlfabric group add group-1 127.0.0.1:10012 $ mysqlfabric group add group-2 127.0.0.1:10021 $ mysqlfabric group add group-2 127.0.0.1:10022 $ mysqlfabric group add group-3 127.0.0.1:10031 $ mysqlfabric group add group-3 127.0.0.1:10032
而且都選出主來
$ mysqlfabric group promote group-g $ mysqlfabric group promote group-1 $ mysqlfabric group promote group-2 $ mysqlfabric group promote group-3
如今爲止只是純粹的建立了4個獨立的組,咱們用的命令都是group相關的,接下來就是分片的重頭戲了,須要用sharding相關命令,咱們仍是先來看下sharding的簡單幫助
$ mysqlfabric help sharding Commands available in group 'sharding' are: sharding list_definitions sharding remove_definition shard_mapping_id [--synchronous] sharding move_shard shard_id group_id [--update_only] [--synchronous] sharding disable_shard shard_id [--synchronous] sharding remove_table table_name [--synchronous] sharding split_shard shard_id group_id [--split_value=NONE] [--update_only] [--synchronous] sharding create_definition type_name group_id [--synchronous] sharding add_shard shard_mapping_id groupid_lb_list [--state=DISABLED] [--synchronous] sharding add_table shard_mapping_id table_name column_name [--synchronous] sharding lookup_table table_name sharding enable_shard shard_id [--synchronous] sharding remove_shard shard_id [--synchronous] sharding list_tables sharding_type sharding prune_shard table_name [--synchronous] sharding lookup_servers table_name key [--hint=LOCAL]
好,首先咱們須要建立一個definition:
$ mysqlfabric sharding create_definition RANGE group-g Fabric UUID: 5ca1ab1e-a007-feed-f00d-cab3fe13249e Time-To-Live: 1 uuid finished success result ------------------------------------ -------- ------- ------ c106bd7a-e8f8-405e-97ec-6886cec87346 1 1 1
記下result字段的數字1,這個就是shard_mapping_id,後續操做都須要他。
而後增長一個表定義,後面3各參數分別是shard_mapping_id, 表名,分片的字段名
$ mysqlfabric sharding add_table 1 lyw.table1 id
接着增長分片的區間定義,這時纔將那3個組用上
$ mysqlfabric sharding add_shard 1 "group-1/0, group-2/10000, group-3/20000" --state=ENABLED
由於咱們這裏用的是range方式,因此每一個組的後面都要加一個分組的起始數字。
後面的--state=ENABLED 表示立刻生效。
基於range的分片就建立好了,咱們仍是火燒眉毛的去測試一下。咱們仍是用python交互界面執行
$ python Python 2.7.9 (default, Apr 2 2015, 15:33:21) [GCC 4.9.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import mysql.connector >>> from mysql.connector import fabric >>> conn = mysql.connector.connect(fabric={"host":"localhost", "port":32274, "username":"lyw", "password":"123456"}, user="fabric", password="123456", autocommit=True) >>> conn.set_property(group='group-g', scope=fabric.SCOPE_GLOBAL, mode=fabric.MODE_READWRITE) >>> cur = conn.cursor() >>> cur.execute('create database lyw') >>> cur.execute('use lyw;') >>> cur.execute('create table table1 (id int, v varchar(32))')
這時,咱們去8個數據庫直接查看,會發現全部數據庫都建立了數據庫lyw和表table1;由於咱們使用了scope=fabric.SCOPE_GLOBAL 參數,因此這個操做在10091這個庫執行後,會同步到其餘全部數據庫中去,記得其餘數據庫的數據是有延遲的。
而後咱們進行分片插入數據,fabric的分片操做有點麻煩,用兩個函數輔助一下比較方便,下面代碼能夠粘貼到交互界面中去。
import random def ins(conn, table, key): conn.set_property(tables=[table], key=key, scope=fabric.SCOPE_LOCAL, mode=fabric.MODE_READWRITE) cur=conn.cursor() #cur.execute('use lyw;') cur.execute("insert into %s values('%s', 'aaa')" % (table, key) ) def rand_ins(conn, table, count): for i in range(count): key = random.randint(0, 30000) ins(conn, table, key)
而後咱們在交互界面執行rand_ins函數隨機插入若干條數據
>>> connl = mysql.connector.connect(fabric={"host":"localhost", "port":32274, "username":"lyw", "password":"123456"}, user="fabric", password="123456", autocommit=True) >>> rand_ins(connl, 'lyw.table1', 100)
這樣就向數據庫隨機插入了100條數據,咱們能夠用mysql客戶端直接連接後面的6個庫查看,通常狀況每一個庫都有數據庫,第一組數據都是小於10000的數據,第二組都是10000-20000的數據,第三組都是20000以上的數據,而且行數總和爲100,就是咱們插入的總條數。
注意:使用分片時,若是key換了,就須要從新得到遊標和數據庫,即ins函數的前3行,使用數據庫也能夠直接將表名寫在sql語句中。不然插入數據會不符合預期。
除了RANGE分片外,fabric還提供了其餘的方式,有HASH,RANGE_DATETIME, RANGE_STRING
咱們下面講一下HASH分片。
HASH 分片
$ mysqlfabric sharding create_definition HASH group-g Fabric UUID: 5ca1ab1e-a007-feed-f00d-cab3fe13249e Time-To-Live: 1 uuid finished success result ------------------------------------ -------- ------- ------ 9ba5c378-9f99-43bc-8f54-7580cff565f6 1 1 2 $ mysqlfabric sharding add_table 2 lyw.table2 id $ mysqlfabric sharding add_shard 2 "group-1, group-2, group-3" --state=ENABLED
配置已完成,只要3行命令,hash方式的分組後面不用加數字,分組由系統自行計算得到。
咱們仍是測試一下
>>> conn = mysql.connector.connect(fabric={"host":"localhost", "port":32274, "username":"lyw", "password":"123456"}, user="fabric", password="123456", autocommit=True) >>> conn.set_property(group='group-g', scope=fabric.SCOPE_GLOBAL, mode=fabric.MODE_READWRITE) >>> cur = conn.cursor() >>> cur.execute('use lyw;') >>> cur.execute('create table table2 (id int, v varchar(32))') >>> connl = mysql.connector.connect(fabric={"host":"localhost", "port":32274, "username":"lyw", "password":"123456"}, user="fabric", password="123456", autocommit=True) >>> rand_ins(connl, 'lyw.table2', 100)
一樣能夠發現每一個庫中都有了數據,只是沒有太好的規律,而且可能還會發現每一個數據庫的數據行數相差比較遠,這個看運氣,可能相差10倍之大,所以我以爲目前fabric的Hash方法不夠好,分佈太不均勻,HASH方式不建議使用。
RANGE_DATETIME 分片
$ mysqlfabric sharding create_definition RANGE_DATETIME group-g $ mysqlfabric sharding add_table 3 lyw.table3 dt $ mysqlfabric sharding add_shard 3 'group-1/2015-1-1, group-2/2015-2-1,group-3/2015-3-1' --state=ENABLED
這樣3行就能夠了,記得寫數據的時候key用datetime.date類型,不能用datetime.datetime。
當須要按照時間分區的時候,就能夠這樣作,然而我我的認爲,最近的時間是熱數據的狀況下,用fabric分片其實並非否穩當,用mysql自帶的時間分片會更好。
注意:目前版本fabric在datetime上有bug,若是加上幾分幾秒,須要修改3處代碼,方可運行,因爲我只是做了簡短測試,可能還有其餘bug,因此不在此發佈diff。
RANGE_STRING 分片
$ mysqlfabric sharding create_definition RANGE_STRING group-g $ mysqlfabric sharding add_table 4 lyw.table4 name $ mysqlfabric sharding add_shard 4 'group-1/a, group-2/c,group-3/e' --state=ENABLED
這樣name爲a和b開頭的行都會放在group-1,c和d開頭的都會放在group-2,大於等於e的都會放在group-3裏面了。這種分片方式仍是有挺大用處的,十分推薦。能夠用前面的ins函數測試。
以上是Fabric的基本功能使用,一點點去深究後會發現Fabric也存在這樣那樣的缺陷,可能不適合您的業務場景,另外我寫了篇Cobar集羣的部署使用,和MySQL Cluster的部署使用,請你們參考。
在多種集羣之間選擇猶豫時,能夠參考下《MySQL Cluster, Fabric, Cobar 三大集羣特性對比》這篇文章,必定會對你有所幫助的。