mycat分片表全局自增主键测试
mycat分片表全局自增主键测试
一、全局序列号介绍
在实现分库分表的情况下,数据库自增主键已无法保证自增主键的全局唯一。为此,MyCat 提供了全局
sequence,并且提供了包含本地配置和数据库配置等多种实现方式。
1.本地文件方式
使用服务器本地磁盘文件的方式
2.数据库方式
使用专用数据库的方式
3.本地时间戳方式
使用时间戳算法方式
4.分布式ZK ID 生成器
基于ZK 与本地配置的分布式ID 生成器(可以通过ZK 获取集群(机房)唯一InstanceID,也可以通过配置文
件配置InstanceID)
5.Zk 递增方式
另一种ZK生成方式
6.其他方式
二、配置方式详解
1.本地文件方式
配置方式:
在sequence_conf.properties
文件中做如下配置:
# 这是全局表的设置
GLOBAL_SEQ.HISIDS=
GLOBAL_SEQ.MINID=1001
GLOBAL_SEQ.MAXID=1000000000
GLOBAL_SEQ.CURID=1000
# 下面是自定义表的设置
其中
HISIDS
表示使用过的历史分段(一般无特殊需要可不配置),MINID
表示最小ID 值,MAXID
表示最大ID 值,
CURID
表示当前ID 值。server.xml
中配置:
<system><property name="sequnceHandlerType">0</property></system>
注:
sequnceHandlerType
需要配置为0,表示使用本地文件方式。使用示例:
insert into table1(id,name) values(next value for MYCATSEQ_GLOBAL,‘test’);
缺点:当MyCAT 重新发布后,配置文件中的sequence 会恢复到初始值。
优点:本地加载,读取速度较快。
[本地文件方式详细配置和测试]
1.1 修改配置文件server.xml
,指定加密方式为本地文件方式
<system><property name="sequnceHandlerType">0</property></system>
1.2 在
schema.xml
文件中配置,增加表tt
,ID为主键,在dn$1-3上分片,分片方式mod-log
<table name="tt" primaryKey="id" autoIncrement="true" dataNode="dn$1-3" rule="mod-long"/>
1.3 修改
sequence_conf.properties
文件中做如下配置:# 这是全局表的设置
GLOBAL.HISIDS=
GLOBAL.MINID=10001
GLOBAL.MAXID=1000000000
GLOBAL.CURID=10000
# 下面是自定义表的设置
TT.HISIDS=
TT.MINID=1001
TT.MAXID=2000
TT.CURID=1000
1.4 建表
tt
CREATE TABLE tt(
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name_` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
查看表结构
mysql> desc tt;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name_ | int(10) unsigned | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
查看表分片情况
mysql> explain select * from tt;
+-----------+--------------------------------+
| DATA_NODE | SQL |
+-----------+--------------------------------+
| dn1 | SELECT * FROM tt LIMIT 3000000 |
| dn2 | SELECT * FROM tt LIMIT 3000000 |
| dn3 | SELECT * FROM tt LIMIT 3000000 |
+-----------+--------------------------------+
3 rows in set (0.07 sec)
1.5 插入数据测试
插入一条使用全局序列号
insert into tt(id,name_) values(next value for MYCATSEQ_GLOBAL,1);
查看序列号使用
mysql> SELECT * FROM TT;
+-------+-------+
| id | name_ |
+-------+-------+
| 10001 | 1 |
+-------+-------+
1 row in set (0.00 sec)
插入一条使用TT序列号
insert into tt(id,name_) values(next value for MYCATSEQ_TT,2);
查看序列好使用情况
mysql> SELECT * FROM TT ORDER BY name_;
+-------+-------+
| id | name_ |
+-------+-------+
| 10001 | 1 |
| 1001 | 2 |
+-------+-------+
2 rows in set (0.01 sec)
多插入一些数据,查询结果
mysql> SELECT * FROM TT ORDER BY name_;
+-------+-------+
| id | name_ |
+-------+-------+
| 10001 | 1 |
| 1001 | 2 |
| 1002 | 3 |
| 1003 | 4 |
| 1004 | 5 |
| 1005 | 6 |
+-------+-------+
6 rows in set (0.00 sec)
这些数据再分片上的情况
mysql (db1)>select * from tt;
+------+-------+
| id | name_ |
+------+-------+
| 1002 | 3 |
| 1005 | 6 |
+------+-------+
2 rows in set (0.00 sec)
mysql (db2)>select * from tt;
+------+-------+
| id | name_ |
+------+-------+
| 1003 | 4 |
+------+-------+
1 row in set (0.00 sec)
mysql (db3)>select * from tt;
+-------+-------+
| id | name_ |
+-------+-------+
| 1001 | 2 |
| 1004 | 5 |
| 10001 | 1 |
+-------+-------+
OK It works!!
优点:配置简单,本地文件,读写速度快
缺点:导致MYCAT变成有状态的中间件,不利于部署集群
2.数据库方式
数据库方式存在比较明显的缺点,即MYCAT集群切换和保持序列的数据库主从切换之后,不可控内容较多
需要非常仔细的处理这些问题,维护成本较高,虽然实现MYCAT无状态,但有单点问题
3.本地时间戳方式
ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加) server.xml
:
<system><property name="sequnceHandlerType">2</property></system>
sequence_time_conf.properties
:WORKID=0-31 任意整数
DATAACENTERID=0-31 任意整数
是个好方式
4.分布式ZK ID 生成器
-----最想测试的还是这个
配置选项:
<property name="sequnceHandlerType">3</property>
原理说明:
Zk 的连接信息统一在
myid.properties
的zkURL
属性中配置。基于ZK 与本地配置的分布式ID 生成器(可以通过ZK 获取集群(机房)唯一
InstanceID
,也可以通过配置文件配置InstanceID
)ID 结构:long 64 位,ID 最大可占63 位current time millis (微秒时间戳38 位,可以使用17 年) |
---|
instanceId (实例ID,可以通过ZK 或者配置文件获取,5 位,也就是十进制0-31) |
threadId (线程ID,9 位) |
increment (自增,6 位) |
一共63 位,可以承受单机房单机器单线程1000*(2^6)=640000 的并发。
无悲观锁,无强竞争,吞吐量更高
配置文件:sequence_distributed_conf.properties
,只要配置里面:INSTANCEID=ZK
就是从ZK 上获取InstanceID
。
配置ZK ID生成器的主要步骤
4.1 配置zookeeper
zookeeper是hadoop的一个子项目
一般生产上需要配置zookeeper集群,奇数个节点,至少三个节点
为了测试mycat的相关特性,我们只搭建一个单节点的zookeeper
ZooKeeper Standalone模式
从Apache网站上(zookeeper.apache.org)下载ZooKeeper软件包,我选择了3.3.4版本的(zookeeper-3.3.4.tar.gz),在一台Linux机器上安装非常容易,只需要解压缩后,简单配置一下即可以启动ZooKeeper服务器进程。
将zookeeper-3.3.4/conf目录下面的 zoo_sample.cfg
修改为zoo.cfg
,配置文件内容如下所示:
tickTime=2000
dataDir=/home/hadoop/storage/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
下面启动ZooKeeper服务器进程:
cd zookeeper-3.3.4/
bin/zkServer.sh start
这样zookeeper就可以使用了,防火墙的配置自行处理
ZooKeeper 分布式模式
搭建生产网络或夸机房分布式的时候再进行补充
4.2 配置mycat
主要涉及三个方面,修改myid.properties
,修改server.xml
,修改sequence_distributed_conf.properties
myid.properties:
loadZk=true #使用zk管理mycat和ID
zkURL=127.0.0.1:2181 #zk服务器的地址和端口
clusterId=010 #本机房mycat集群的ID
myid=01001 #集群内mycat的ID
clusterNodes=mycat-02 #mycat节点的名称
#server booster ; booster install on db same server,will reset all minCon to 1
#type=server
#boosterDataHosts=dn2,dn3
server.xml:
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="defaultSqlParser">druidparser</property>
<property name="useCompression">1</property>
<property name="serverPort">3306</property>
<property name="managerPort">3308</property>
<property name="maxStringLiteralLength">65535</property>
<!-- sequnceHandlerType 0:文件模式 1: 2:3:zookeeper分布式管理模式 -->
<property name="sequnceHandlerType">3</property>
</system>
<user name="root">
<property name="password">password</property>
<property name="schemas">dbykt</property>
</user>
</mycat:server>
sequence_distributed_conf.properties:
INSTANCEID=01
CLUSTERID=01
上面三个文件修改完成后,复制conf下的所有文件到 conf/zkconf/目录下
cp *.txt *.xml *.properties zkconf/
初始化:
cd ./bin/
./init_zk_data.sh
4.3 启动mycat
先使用console看看启动是否正常
./bin/mycat console
正常之后再进行启动
./bin/mycat start
4.4 测试mycat ZK 分布式ID生成器
使用工具Jmeter,此处不赘述
配置表ot1:
.....
<table name="ot1" dataNode="dn$1-20,dn$21-40,dn$41-60" rule="card_no" primaryKey="id" autoIncrement="true"/>
......
重启mycat
./bin/mycat restart
建表(因为同时测试了插入性能,所以表较为复杂)
CREATE TABLE `ot1` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
...............
...............
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Jmeter 插入数据测试
使用的sql语句如下:
INSERT INTO `ot1` (
`id`,
................
................
)
VALUES
(
next value for MYCATSEQ_OT,
...............
...............
);
查询观察结果
mysql> SELECT id FROM ot1 ORDER BY id;
........
| 3894484648986705980 |
| 3894484648986705981 |
| 3894484649020260414 |
| 3894484649053814784 |
| 3894484649053814847 |
| 3894484649389359105 |
| 3894484649926230018 |
| 3894484649926230019 |
| 3894484649926230020 |
| 3894484649926230021 |
| 3894484649959784454 |
| 3894484649959784455 |
| 3894484649959784456 |
| 3894484649993338889 |
| 3894484649993338890 |
| 3894484650026893323 |
| 3894484650026893324 |
| 3894484650060447757 |
| 3894484650060447758 |
| 3894484650094002191 |
........
查询数据总量:
mysql> select count(id) id_count from ot1;
+----------+
| id_count |
+----------+
| 37784391 |
+----------+
查出最大ID:
mysql> select max(id) id from ot1 ;
+---------------------+
| id |
+---------------------+
| 3897338173617897525 |
+---------------------+
1 row in set (0.03 sec)
判断一下是否有重复ID:
mysql> select count(id),id from ot1 group by id having count(id)>1;
Empty set (1 min 42.85 sec)
4.5 结论
分布式ZK ID生成器,果然强大。这为数据库跨机房双活提供了新的方案,使得双A机房架构下的数据最终一致性有了新的思路。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341