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 三大集群特性对比》这篇文章,必定会对你有所帮助的。