如果我有一个32核心的服务器,我就可以实现1个亿的数据分片,我有32核心的服务器么?没有,所以我至今无法实现1个亿的数据库分片。---Mycat's Plan
Mycat是什么?
对于DBA来说,可以这么理解Mycat:
对于软件工程师来说,可以这么理解Mycat:
对于架构师来说,可以这么理解Mycat:
Mycat原理
应用场景
Mycat长期路线图
数据库中间件
逻辑库(schema)
逻辑表(table)
既然有逻辑库,那么就会有逻辑表,分布式数据库中,对应用来说,读写数据的表就是逻辑表。逻辑表,可 以是数据切分后,分布在一个或多个分片库中,也可以不做数据切分,不分片,只有一个表构成。
分片表
<table name=nt_noden primaryKey=nvidn autoincrement=ntruen dataNode=ndn1,dn2n rule=nrule1n />
非分片表
<table name=nt_noden primaryKey=nvidn autoincrement=ntruen dataNode=ndn1" />
ER 表
全局表
分片节点(dataNode)
多租户
1.1 独立数据库
1.2共享数据库,隔离数据架构
共享数据库,共享数据架构
何为数据切分?
简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主 机)上面,以达到分散单台设备负载的效果。
数据的切分(Sharding )根据其切分规则的类型,可以分为两种切分模式。一种是按照不同的表(或者 Schema )来切分到不同的数据库(主机)之上,这种切可以称之为数据的垂直(纵向)切分;另外一种则是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。
垂直切分的最大特点就是规则简单,实施也更为方便,尤其适合各业务之间的耦合度非常低,相互影响很小,业务逻辑非常清晰的系统。在这种系统中,可以很容易做到将不同业务模块所使用的表分拆到不同的数据库中。根据不同的表来进行拆分,对应用程序的影响也更小,拆分规则也会比较简单清晰。
水平切分于垂直切分相比,相对来说稍微复杂一些。因为要将同一个表中的不同数据拆分到不同的据库中,对于应用程序来说,拆分规则本身就较根据表名来拆分更为复杂,后期的数据维护也会更为复杂一些。
垂直切分
下面来分析下垂直切分的优缺点:
- 拆分后业务清晰,拆分规则明确。
- 系统之间整合或扩展容易。
- 数据维护简单。
- 部分业务表无法join ,只能通过接口方式解决,提高了系统复杂度。
- 受每种业务不同的限制存在单库性能瓶颈,不易扩展跟性能提高。
- 事务处理复杂。由于垂直切分是按照业务的分类将表分散到不同的库,所以有些业务表会过于庞大,存在单库读写与存储瓶颈,所以就需要水平拆分来做解决。
水平切分
几种典型的分片规则包括:
前面讲了垂直切分跟水平切分的不同跟优缺点,会发现每种切分都有缺点,但共同的特点缺点有:
针对数据源管理,目前主要有两种思路:
可能 90%以上的人在面对上面这两种解决思路的时候都会倾向于选择第二种,尤其是系统不断变得庞大复杂的时候。确实,这是一个非常正确的选择,虽然短期内需要付出的成本可能会相对更大一些,但是对整个系统的扩展性来讲,是非常有帮助的数据切分的原则:
数据切分的原则:
安装Mycat
wget https://github.com/MyCATApache/Mycat-download/raw/master/1.5-RELEASE/Mycat-server-1.5.1-RELEASE-20160622153300-linux.tar.gz
tar zxf Mycat-server-1.5.1-RELEASE-20160622153300-linux.tar.gz
mv mycat /application/
echo "export PATH=/application/mycat/bin:$PATH">>/etc/profile
source /etc/profile
echo $PATH
下载安装JDK
wget http://download.oracle.com/otn-pub/java/jdk/8u91-b14/jdk-8u91-linux-x64.rpm
rpm -ivh jdk-8u91-linux-x64.rpm
配置环境变量
echo "export JAVA_HOME=/usr/java/jdk1.8.0_91/" >>/etc/profile
echo "export PATH=$JAVA_HOME/bin:/application/mycat/bin/:$PATH">>/etc/profile
echo "export CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar">>/etc/profile
source /etc/profile
[root@Linuxdemo3 ~]# java -version
java version "1.8.0_91"
Java(TM) SE RuntimeEnvironment(build 1.8.0_91-b14)
JavaHotSpot(TM)64-BitServer VM (build 25.91-b14, mixed mode)
创建管理用户
主库上对rep和rep_r用户授权如下:
用户:rep 密码:oldboy 端口:3306
权限:all
命令:
grant replication slave on test.* to 'rep'@'10.0.0.%' identified by 'oldboy';
grant replication slave on test.* to 'rep_r'@'10.0.0.%' identified by 'oldboy';
flush privileges;
注:为了方便下面的主从切换,两个用户都授予了所有的权限,生产环境尽量不要这样子授权!
[root@Linuxdemo3 mycat]# pwd
/application/mycat
[root@Linuxdemo3 mycat]# ll
total 24
drwxr-xr-x 2 root root 4096Jul 403:13 bin
drwxrwxrwx 2 root root 4096Dec13 2015 catlet
drwxrwxrwx 2 root root 4096Jul 403:13 conf
drwxr-xr-x 2 root root 4096Jul 403:13 lib
drwxrwxrwx 2 root root 4096Dec13 2015 logs
-rwxrwxrwx 1 root root 219Jun2215:33 version.txt
修改server.xml文件
[root@Linuxdemo3 conf]# vim server.xml
</system>
<user name="rep">
<property name="password">oldboy</property>
<property name="schemas">test</property>
</user>
<user name="rep_r">
<property name="password">oldboy</property>
<property name="schemas"> test</property>
<property name="readOnly">true</property>
</user>
修改schema.xml文件
[root@Linuxdemo3 conf]# vim schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<schema name="test" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
</schema>
<dataNode name="dn1" dataHost="localhost1" database="test"/>
<dataNode name="dn2" dataHost="localhost1" database=" test "/>
<dataNode name="dn3" dataHost="localhost1" database=" test "/>
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="10.0.0.202:3306" user="rep"
password="oldboy">
</writeHost>
<readHost host="hostS1" url="10.0.0.202:3307" user="rep_r"
password="oldboy"/>
</readHost>
</dataHost>
</mycat:schema>
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
需要配置的位置:
balance="1" writeType="0" switchType="1"
balance
writeType
switchType
<writeHost host="hostM1" url="10.0.0.202:3306" user="rep"
password="oldboy">
<!-- can have multi read hosts -->
<readHost host="hostS1" url="10.0.0.202:3306" user="rep_r"
password="oldboy"/>
启动Mycat
[root@Linuxdemo3 conf]#/application/mycat/bin/mycat start
StartingMycat-server...
[root@Linuxdemo3 logs]#
mysql -urep -poldboy -h10.0.0.202 -P8066
mysql> explain create table company(id int not null primary key,name varchar(100));
+-----------+---------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------------------------------+
| dn1 | create table company(id int not null primary key,name varchar(100)) |
| dn2 | create table company(id int not null primary key,name varchar(100)) |
| dn3 | create table company(id int not null primary key,name varchar(100)) |
+-----------+---------------------------------------------------------------------+
3 rows in set (0.06 sec)
mysql> create table company(id int not null primary key,name varchar(100));
Query OK, 0 rows affected (1.82 sec)
mysql> explain insert into company(id, name) values (100, 'abc');
+-----------+---------------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------------+
| dn1 | insert into company(id, name) values (100, 'abc') |
| dn2 | insert into company(id, name) values (100, 'abc') |
| dn3 | insert into company(id, name) values (100, 'abc') |
+-----------+---------------------------------------------------+
3 rows in set (0.00 sec)
mysql> insert into company(id, name) values (100, 'abc');
Query OK, 1 row affected (0.24 sec)
查看日志
分别在主从库中执行以下命令:
mysql> select * from company where id =100;
+-----+------+
| id | name |
+-----+------+
|100| abc |
+-----+------+
1 row in set(0.00 sec)
mysql> insert into company(id, name) values (4,'abcwq');
ERROR 1495(HY000):User readonly
#从库只读
主从切换测试
将schema.xml文件做如下修改:
[root@Linuxdemo3 conf]# vim schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<schema name="test" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
</schema>
<dataNode name="dn1" dataHost="localhost1" database="test"/>
<dataNode name="dn2" dataHost="localhost1" database=" test "/>
<dataNode name="dn3" dataHost="localhost1" database=" test "/>
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100">
<heartbeat>show slave status</heartbeat>
<writeHost host="hostM1" url="10.0.0.202:3306" user="rep"
password="oldboy">
</writeHost>
<readHost host="hostS1" url="10.0.0.202:3307" user="rep_r"
password="oldboy"/>
</readHost>
<writeHost host="hostM2" url="10.0.0.202:3307" user="rep"
password="oldboy">
</writeHost>
</dataHost>
</mycat:schema>
重启mycat服务
[root@Linuxdemo2 conf]#/application/mycat/bin/mycat restart
StoppingMycat-server...
StoppedMycat-server.
StartingMycat-server...
- [root@Linuxdemo2 conf]#/data/3306/mysql stop
Mycat-Web
安装zookpeer
wget http://mirrors.hust.edu.cn/apache/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz
tar -xzvf zookeeper-3.4.6.tar.gz
cd zookeeper-3.4.6/conf
cp zoo_sample.cfg zoo.cfg
cd zookeeper-3.4.6/bin
./zkServer.sh start
出现一下信息说明启动成功
JMX enabled by default
Using config:/usr1/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
安装mycat-web
wget https://github.com/MyCATApache/Mycat-download/raw/master/mycat-web-1.0/Mycat-web-1.0-SNAPSHOT-20160617163048-linux.tar.gz
tar zxf Mycat-web-1.0-SNAPSHOT-20160617163048-linux.tar.gz
cd mycat-web/mycat-web/WEB-INF/classes
vim mycat.properties
zookeeper=127.0.0.1:2181
sqlonline.server=10.0.0.202
cd mycat-web
#将start.sh文件中的JVM调整到合适的大小
./start.sh &
#8082端口是web端口
访问10.0.0.202:8082/mycat即可进入web页面
cd /application/mycat/bin
/application/mycat/bin/xml_to_yaml.sh 根据mycat配置生成 zookeeper yaml 配置工具
/application/mycat/bin/init_zk_data.sh 将生成的yaml配置文件导入远程zookeeper
/application/mycat/conf/myid.properties zookeeper 路径配置参数信息
/application/mycat/conf/zk-create.yaml 自动生成的zk配置
1)确认安装好zookeeper 环境
2)启动mycat服务,确认本地服务一切正常。
3)执行xml_to_yaml.sh脚本(确认本地配置过 JAVA_HOME 和 MYCAT_HOME环境变量,)
[root@Linuxdemo3 bin]#./xml_to_yaml.sh
4)执行 init_zk_data.sh 脚本,注意下默认情况下脚本会将zookeeper定位在同一台服务器上面,如有需要可以调整下 ZK 的 IP : PORT
[root@Linuxdemo3 bin]#./init_zk_data.sh
管理命令与监控
mysql -urep -poldboy -h10.0.0.202-P9066 -Dtest
1、查看所有的命令,如下:
mysql> show @@help;
+--------------------------------------+-----------------------------------+
| STATEMENT | DESCRIPTION |
+--------------------------------------+-----------------------------------+
| clear @@slowwhere datanode =? |Clear slow sql by datanode |
| clear @@slowwhere schema =? |Clear slow sql by schema |
| kill @@connection id1,id2,... |Kill the specified connections |
| offline |ChangeMyCat status to OFF |
| online |ChangeMyCat status to ON |
| reload @@config |Reload basic config from file |
| reload @@config_all |Reload all config from file |
| reload @@route |Reload route config from file |
| reload @@user |Reload user config from file |
| rollback @@config |Rollback all config from memory |
| rollback @@route |Rollback route config from memory |
| rollback @@user |Rollback user config from memory |
| show @@backend |Report backend connection status |
| show @@cache |Report system cache usage |
| show @@command |Report commands status |
| show @@connection |Report connection status |
| show @@connection.sql |Report connection sql |
| show @@database |Report databases |
| show @@datanode |Report dataNodes |
| show @@datanodewhere schema =? |Report dataNodes |
| show @@datasource |Report dataSources |
| show @@datasourcewhere dataNode =?|Report dataSources |
| show @@heartbeat |Report heartbeat status |
| show @@parser |Report parser status |
| show @@processor |Report processor status |
| show @@router |Report router status |
| show @@server |Report server status |
| show @@session |Report front session details |
| show @@slowwhere datanode =? |Report datanode slow sql |
| show @@slowwhere schema =? |Report schema slow sql |
| show @@sqlwhere id =? |Report specify SQL |
| show @@sql.detail where id =? |Report execute detail status |
| show @@sql.execute |Report execute status |
| show @@sql.slow |Report slow SQL |
| show @@threadpool |Report threadPool status |
| show @@time.current |Report current timestamp |
| show @@time.startup |Report startup timestamp |
| show @@version |ReportMycatServer version |
| stop @@heartbeat name:time |Pause dataNode heartbeat |
|switch@@datasource name:index |Switch dataSource
2、更新配置文件
mysql> reload @@config;
Query OK,1 row affected (0.13 sec)
Reload config success
3、显示mycat数据库的列表,对应的在scehma.xml配置的逻辑库
mysql> show @@database;
+----------+
| DATABASE |
+----------+
| oldboy |
+----------+
1 row in set(0.00 sec)
4、显示mycat数据节点的列表,对应的是scehma.xml配置文件的dataNode节点
mysql> show @@datanode;
+------+-------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+
| NAME | DATHOST | INDEX | TYPE | ACTIVE | IDLE | SIZE | EXECUTE | TOTAL_TIME | MAX_TIME | MAX_SQL | RECOVERY_TIME |
+------+-------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+
| dn1 | localhost1/oldboy | 0| mysql | 0| 10|1000| 457| 0| 0| 0| -1|
| dn2 | localhost1/oldboy | 0| mysql | 0| 10|1000| 457| 0| 0| 0| -1|
| dn3 | localhost1/oldboy | 0| mysql | 0| 10|1000| 457| 0| 0| 0| -1|
+------+-------------------+-------+-------+--------+------+------+---------+------------+----------+---------+---------------+
3 rows in set(0.00 sec)
5、报告心跳状态
mysql> show @@heartbeat;
+--------+-------+-------------+------+---------+-------+--------+---------+--------------+---------------------+-------+
| NAME | TYPE | HOST | PORT | RS_CODE | RETRY | STATUS | TIMEOUT | EXECUTE_TIME | LAST_ACTIVE_TIME | STOP |
+--------+-------+-------------+------+---------+-------+--------+---------+--------------+---------------------+-------+
| hostM1 | mysql |10.0.0.202|3306| 1| 0| idle | 0|1,1,1 |2015-12-2921:39:40|false|
| hostS1 | mysql |10.0.0.202|3307| 1| 0| idle | 0|3,3,3 |2015-12-2921:39:40|false|
+--------+-------+-------------+------+---------+-------+--------+---------+--------------+---------------------+-------+
2 rows in set(0.01 sec)
6、获取当前mycat的版本
mysql> show @@version;
+--------------------------------------+
| VERSION |
+--------------------------------------+
|5.5.8-mycat-1.4-alpha-20150520235658|
+--------------------------------------+
1 row in set(0.00 sec)
7、显示mycat前端连接状态
mysql> show @@connection;
+------------+------+-----------+------+------------+--------+---------+--------+---------+---------------+-------------+------------+---------+------------+
| PROCESSOR | ID | HOST | PORT | LOCAL_PORT | SCHEMA | CHARSET | NET_IN | NET_OUT | ALIVE_TIME(S)| RECV_BUFFER | SEND_QUEUE | txlevel | autocommit |
+------------+------+-----------+------+------------+--------+---------+--------+---------+---------------+-------------+------------+---------+------------+
|Processor0| 6|127.0.0.1|9066| 46490| oldboy | utf8:33| 281| 6164| 1008| 4096| 0| | |
+------------+------+-----------+------+------------+--------+---------+--------+---------+---------------+-------------+------------+---------+------------+
1 row in set(0.00 sec)
8、显示mycat后端连接状态
mysql> show @@backend;
+------------+------+---------+-------------+------+--------+--------+---------+------+--------+----------+------------+--------+---------+---------+------------+
| processor | id | mysqlId | host | port | l_port | net_in | net_out | life | closed | borrowed | SEND_QUEUE | schema | charset | txlevel | autocommit |
+------------+------+---------+-------------+------+--------+--------+---------+------+--------+----------+------------+--------+---------+---------+------------+
|Processor0| 1| 30|10.0.0.202|3306| 14881| 3554| 1068|5041|false |false | 0| oldboy | utf8:33|3 |true |
|Processor0| 2| 32|10.0.0.202|3306| 14883| 3554| 1068|5041|false |false | 0| oldboy | utf8:33|3 |true |
|Processor0| 3| 24|10.0.0.202|3306| 14875| 3515| 1068|5041|false |false | 0| oldboy | utf8:33|3 |true |
|Processor0| 4| 28|10.0.0.202|3306| 14879| 3561| 986|5041|false |false | 0| oldboy | utf8:33|0 |true |
9、显示数据源
mysql> show @@datasource;
+----------+--------+-------+-------------+------+------+--------+------+------+---------+
| DATANODE | NAME | TYPE | HOST | PORT | W/R | ACTIVE | IDLE | SIZE | EXECUTE |
+----------+--------+-------+-------------+------+------+--------+------+------+---------+
| dn1 | hostM1 | mysql |10.0.0.202|3306| W | 0| 10|1000| 525|
| dn1 | hostS1 | mysql |10.0.0.202|3306| R | 0| 8|1000| 522|
| dn3 | hostM1 | mysql |10.0.0.202|3306| W | 0| 10|1000| 525|
| dn3 | hostS1 | mysql |10.0.0.202|3306| R | 0| 8|1000| 522|
| dn2 | hostM1 | mysql |10.0.0.202|3306| W | 0| 10|1000| 525|
| dn2 | hostS1 | mysql |10.0.0.202|3306| R | 0| 8|1000| 522|
+----------+--------+-------+-------------+------+------+--------+------+------+---------+
6 rows in set(0.01 sec)