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集群的部署使用: 大家可以参考。我过几天再写一篇关于Fabric和Cobar的对比文章,使用时看您的选择了。
本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-10/124419.htm