手机版
你好,游客 登录 注册 搜索
背景:
阅读新闻

MySQL分片高可用集群之Fabric部署使用

[日期:2015-10-22] 来源:Linux社区  作者:bangbangba [字体: ]

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

linux
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款