写在前面的话

在学习的索引的时候,有提到,当数据表数据达到 800W 的时候,索引的性能就开始逐步下降。对于一个公司而言,主要业务数据表达到 1000W 都很容易。同时这张表一般都是业务常用的表,操作还比较频繁。所以为了提升用户体验,需要采用另外的方式对数据库进行优化,那就是分库分表。而 MyCAT 就是能够帮助我们管理分库分表的这样一个中间件。

MyCAT 环境基础架构准备

架构图 1:

架构图 2:

【1】搭建基础环境:

1. 在 db01:192.168.100.111 上面安装数据库多实例:

  1. # 创建基础目录
  2. mkdir -p /data/{data,logs,backup,conf}/mysql-33{07,08,09,10}
  3. mkdir -p /data/logs/mysql-33{07,08,09,10}/{bin-log,slow-log,error-log,relay-log}
  4. mkdir -p /data/packages/mysql
  5. mkdir -p /data/services
  6.  
  7. # 添加用户
  8. useradd -s /sbin/nologin mysql
  9.  
  10. # 修改目录权限
  11. chown -R mysql.mysql /data/logs/mysql-33*
  12. chown -R mysql.mysql /data/data/mysql-33*
  13.  
  14. # 清理默认配置文件
  15. mv /etc/my.cnf /etc/my.cnf_bak
  16.  
  17. # 解压包
  18. cd /data/packages/mysql/
  19. tar -zxf mysql-5.7.25-linux-glibc2.12-x86_64.tar.gz -C /data/services/
  20. cd /data/services/
  21. mv mysql-5.7.25-linux-glibc2.12-x86_64/ mysql
  22.  
  23. # 配置环境变量并查看
  24. echo 'export PATH=$PATH:/data/services/mysql/bin' >> /etc/profile
  25. source /etc/profile
  26. mysql -V

2. 在 db01:192.168.100.111 上面初始化数据:

  1. # 初始化数据
  2. mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3307
  3. mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3308
  4. mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3309
  5. mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3310

3. 在 db01:192.168.100.111 上面初始化配置:

  1. #
  2. cat >/data/conf/mysql-3307/my.cnf<<EOF
  3. [mysqld]
  4. port=3307
  5. basedir=/data/services/mysql
  6. datadir=/data/data/mysql-3307
  7. socket=/data/logs/mysql-3307/mysql.sock
  8. log-error=/data/logs/mysql-3307/error-log/mysql.log
  9. log_bin=/data/logs/mysql-3307/bin-log/mysql-bin
  10. slow_query_log=1
  11. slow_query_log_file=/data/logs/mysql-3307/slow-log/slow.log
  12. long_query_time=2
  13. log_queries_not_using_indexes=1
  14. relay_log=/data/logs/mysql-3307/relay-log/relay-bin
  15. binlog_format=row
  16. skip-name-resolve
  17. server-id=107
  18. gtid-mode=on
  19. enforce-gtid-consistency=true
  20. log-slave-updates=1
  21. EOF
  22.  
  23. #
  24. cat >/data/conf/mysql-3308/my.cnf<<EOF
  25. [mysqld]
  26. port=3308
  27. basedir=/data/services/mysql
  28. datadir=/data/data/mysql-3308
  29. socket=/data/logs/mysql-3308/mysql.sock
  30. log-error=/data/logs/mysql-3308/error-log/mysql.log
  31. log_bin=/data/logs/mysql-3308/bin-log/mysql-bin
  32. slow_query_log=1
  33. slow_query_log_file=/data/logs/mysql-3308/slow-log/slow.log
  34. long_query_time=2
  35. log_queries_not_using_indexes=1
  36. relay_log=/data/logs/mysql-3308/relay-log/relay-bin
  37. binlog_format=row
  38. skip-name-resolve
  39. server-id=108
  40. gtid-mode=on
  41. enforce-gtid-consistency=true
  42. log-slave-updates=1
  43. EOF
  44.  
  45. #
  46. cat >/data/conf/mysql-3309/my.cnf<<EOF
  47. [mysqld]
  48. port=3309
  49. basedir=/data/services/mysql
  50. datadir=/data/data/mysql-3309
  51. socket=/data/logs/mysql-3309/mysql.sock
  52. log-error=/data/logs/mysql-3309/error-log/mysql.log
  53. log_bin=/data/logs/mysql-3309/bin-log/mysql-bin
  54. slow_query_log=1
  55. slow_query_log_file=/data/logs/mysql-3309/slow-log/slow.log
  56. long_query_time=2
  57. log_queries_not_using_indexes=1
  58. relay_log=/data/logs/mysql-3309/relay-log/relay-bin
  59. binlog_format=row
  60. skip-name-resolve
  61. server-id=109
  62. gtid-mode=on
  63. enforce-gtid-consistency=true
  64. log-slave-updates=1
  65. EOF
  66.  
  67. #
  68. cat >/data/conf/mysql-3310/my.cnf<<EOF
  69. [mysqld]
  70. port=3310
  71. basedir=/data/services/mysql
  72. datadir=/data/data/mysql-3310
  73. socket=/data/logs/mysql-3310/mysql.sock
  74. log-error=/data/logs/mysql-3310/error-log/mysql.log
  75. log_bin=/data/logs/mysql-3310/bin-log/mysql-bin
  76. slow_query_log=1
  77. slow_query_log_file=/data/logs/mysql-3310/slow-log/slow.log
  78. long_query_time=2
  79. log_queries_not_using_indexes=1
  80. relay_log=/data/logs/mysql-3310/relay-log/relay-bin
  81. binlog_format=row
  82. skip-name-resolve
  83. server-id=110
  84. gtid-mode=on
  85. enforce-gtid-consistency=true
  86. log-slave-updates=1
  87. EOF

4. 在 db01:192.168.100.111 上面配置启动脚本:

  1. #
  2. cat >/etc/systemd/system/mysqld-3307.service<<EOF
  3. [Unit]
  4. Description=MySQL Server
  5. Documentation=man:mysqld(8)
  6. Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
  7. After=network.target
  8. After=syslog.target
  9. [Install]
  10. WantedBy=multi-user.target
  11. [Service]
  12. User=mysql
  13. Group=mysql
  14. ExecStart=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3307/my.cnf
  15. LimitNOFILE=5000
  16. EOF
  17.  
  18. #
  19. cat >/etc/systemd/system/mysqld-3308.service<<EOF
  20. [Unit]
  21. Description=MySQL Server
  22. Documentation=man:mysqld(8)
  23. Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
  24. After=network.target
  25. After=syslog.target
  26. [Install]
  27. WantedBy=multi-user.target
  28. [Service]
  29. User=mysql
  30. Group=mysql
  31. ExecStart=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3308/my.cnf
  32. LimitNOFILE=5000
  33. EOF
  34.  
  35. #
  36. cat >/etc/systemd/system/mysqld-3309.service<<EOF
  37. [Unit]
  38. Description=MySQL Server
  39. Documentation=man:mysqld(8)
  40. Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
  41. After=network.target
  42. After=syslog.target
  43. [Install]
  44. WantedBy=multi-user.target
  45. [Service]
  46. User=mysql
  47. Group=mysql
  48. ExecStart=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3309/my.cnf
  49. LimitNOFILE=5000
  50. EOF
  51.  
  52. #
  53. cat >/etc/systemd/system/mysqld-3310.service<<EOF
  54. [Unit]
  55. Description=MySQL Server
  56. Documentation=man:mysqld(8)
  57. Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
  58. After=network.target
  59. After=syslog.target
  60. [Install]
  61. WantedBy=multi-user.target
  62. [Service]
  63. User=mysql
  64. Group=mysql
  65. ExecStart=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3310/my.cnf
  66. LimitNOFILE=5000
  67. EOF

5. 在 db01:192.168.100.111 上面启动并查看:

  1. # 启动 MySQL
  2. systemctl start mysqld-3307.service
  3. systemctl start mysqld-3308.service
  4. systemctl start mysqld-3309.service
  5. systemctl start mysqld-3310.service
  6.  
  7. # 查看 MySQL
  8. mysql -S /data/logs/mysql-3307/mysql.sock -e "select @@server_id;"
  9. mysql -S /data/logs/mysql-3308/mysql.sock -e "select @@server_id;"
  10. mysql -S /data/logs/mysql-3309/mysql.sock -e "select @@server_id;"
  11. mysql -S /data/logs/mysql-3310/mysql.sock -e "select @@server_id;"
  12.  
  13. # 添加 root 密码
  14. mysql -S /data/logs/mysql-3307/mysql.sock -e "alter user root@'localhost' identified by '123';"
  15. mysql -S /data/logs/mysql-3308/mysql.sock -e "alter user root@'localhost' identified by '123';"
  16. mysql -S /data/logs/mysql-3309/mysql.sock -e "alter user root@'localhost' identified by '123';"
  17. mysql -S /data/logs/mysql-3310/mysql.sock -e "alter user root@'localhost' identified by '123';"

6. 在 db02:192.168.100.112 上面执行相同的操作:注意修改配置文件中的 server-id,db02 可以改成 2 开头

  1. # 步骤略

【2】配置 db01 和 db02 的 3307 互为主从关系:

1. 在 db02:192.168.100.112:3307 上面配置同步用户:

  1. mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock -e "grant replication slave on *.* to repl@'192.168.100.%' identified by '123';"
  2. mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock -e "grant all on *.* to root@'192.168.100.%' identified by '123' with grant option;"

2. 在 db01:192.168.100.111:3307 上面配置同步 db02:3307:

登录数据库:

  1. mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock

执行 SQL:

  1. -- 创建同步信息
  2. CHANGE MASTER TO
  3. MASTER_HOST='192.168.100.112',
  4. MASTER_USER='repl',
  5. MASTER_PASSWORD='',
  6. MASTER_PORT=3307,
  7. MASTER_AUTO_POSITION=1;
  8.  
  9. -- 启动 slave
  10. start slave;
  11.  
  12. -- 查看状态
  13. show slave status\G

结果如图:

3. 在 db02:192.168.100.112:3307 上面配置同步 db01:3307:

登录数据库:

  1. mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock

执行 SQL:

  1. -- 创建同步信息
  2. CHANGE MASTER TO
  3. MASTER_HOST='192.168.100.111',
  4. MASTER_USER='repl',
  5. MASTER_PASSWORD='',
  6. MASTER_PORT=3307,
  7. MASTER_AUTO_POSITION=1;
  8.  
  9. -- 启动 slave
  10. start slave;
  11.  
  12. -- 查看状态
  13. show slave status\G

结果如下:

此时,db01 的 3307 和 db02 的 3307 互为主从!

【3】配置 db01:3309 为 db01:3307 的从,db02:3309 为 db02:3307 的从:

1. db01 操作:

  1. mysql -uroot -p123 -S /data/logs/mysql-3309/mysql.sock

执行 SQL:

  1. -- 创建同步信息
  2. CHANGE MASTER TO
  3. MASTER_HOST='192.168.100.111',
  4. MASTER_USER='repl',
  5. MASTER_PASSWORD='',
  6. MASTER_PORT=3307,
  7. MASTER_AUTO_POSITION=1;
  8.  
  9. -- 启动 slave
  10. start slave;
  11.  
  12. -- 查看状态
  13. show slave status\G

结果如下:

2. db02 操作:

  1. mysql -uroot -p123 -S /data/logs/mysql-3309/mysql.sock

执行 SQL:

  1. -- 创建同步信息
  2. CHANGE MASTER TO
  3. MASTER_HOST='192.168.100.112',
  4. MASTER_USER='repl',
  5. MASTER_PASSWORD='',
  6. MASTER_PORT=3307,
  7. MASTER_AUTO_POSITION=1;
  8.  
  9. -- 启动 slave
  10. start slave;
  11.  
  12. -- 查看状态
  13. show slave status\G

结果如下:

【4】同理配置另外一组:3308 和 3310,方法类似,注意 IP 端口就行。步骤略

【5】检查主从状态:

  1. mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock -e "show slave status\G" | grep "Yes"
  2. mysql -uroot -p123 -S /data/logs/mysql-3308/mysql.sock -e "show slave status\G" | grep "Yes"
  3. mysql -uroot -p123 -S /data/logs/mysql-3309/mysql.sock -e "show slave status\G" | grep "Yes"
  4. mysql -uroot -p123 -S /data/logs/mysql-3310/mysql.sock -e "show slave status\G" | grep "Yes"

结果如图:

至此,简单的基础架构搭建完成!

分布式架构演进

举一个例子,假如淘宝服务,在公司创建的时候,由于业务量很小,然后久都存在一个数据库里面。但是随着后后期数据量的增加,发现如果都存在一个库,那么数据库的性能有些吃不消,于是为了分担性能压力,将某些数据量大并且访问频繁的表单独抽出来放到单独的机器上面去。这就是垂直拆分(分库分表)。但是随着时间的推移,可能某个表的数据越来越大,达到了上亿数据量,虽然我们见他放在单独的库中,但是性能依旧跟不上了,于是想出了一个办法,能不能将这个表分成一组一组的数据,放到不同的数据库中,这就是水平拆分(分片),如图所示:

实现的方式有以下这些:

1. 360 的 Atlas-sharding

2. Alibaba 的 Cobar / TDDL

3. Aliyun 的 DRDS

4. MyCAT 等

部署 MyCAT

部署 MyCAT 非常简单,由于 MyCAT 是 Java 开发的,所以得先准备 Java 环境,我这里使用JDK 8:

可以前往 MyCAT 的 FTP 地址下载相关的包:

http://dl.mycat.io/

1. 新准备一台机器,安装 MySQL 但是不用初始化:

  1. # 创建必要用户和目录
  2. useradd -s /sbin/nologin mysql
  3. mkdir -p /data/{data,logs,backup,packages}/mysql
  4. mkdir -p /data/services
  5. chown mysql.mysql /data/logs/mysql/
  6. chown mysql.mysql /data/data/mysql/
  7.  
  8. # 安装 MySQL
  9. cd /data/packages/mysql/
  10. tar -zxf mysql-5.7.25-linux-glibc2.12-x86_64.tar.gz -C /data/services/
  11. cd /data/services/
  12. mv mysql-5.7.25-linux-glibc2.12-x86_64/ mysql
  13.  
  14. # 配置环境变量
  15. echo 'export PATH=$PATH:/data/services/mysql/bin' >> /etc/profile
  16. source /etc/profile
  17.  
  18. # 查看安装结果
  19. mysql -V

2. 安装 JDK:

  1. # 解压 jdk
  2. tar -zxf jdk-8u45-linux-x64.tar.gz -C /data/services/
  3. cd /data/services/
  4. mv jdk1.8.0_45/ jdk8
  5.  
  6. # 配置环境变量
  7. echo 'export JAVA_HOME=/data/services/jdk8
  8. export CLASSPATH=$JAVA_HOME/lib/tools.jar
  9. export PATH=$PATH:$JAVA_HOME/bin
  10. export JRE_HOME=$JAVA_HOME/jre' >> /etc/profile
  11.  
  12. # 生效和查看
  13. source /etc/profile
  14. java -version

3. 安装 MyCAT:

  1. # 解压安装
  2. cd /data/packages/mycat/
  3. tar -zxf Mycat-server-1.6.7.3-release-20190828135747-linux.tar.gz -C /data/services/
  4.  
  5. # 配置环境变量
  6. echo 'export PATH=$PATH:/data/services/mycat/bin' >> /etc/profile
  7.  
  8. # 生效和查看
  9. source /etc/profile
  10.  
  11. # 启动 MyCAT
  12. mycat start

此时默认访问端口:8066,用户名:root,密码:123456,配置文件:server.xml

  1. <user name="root" defaultAccount="true">
  2. <property name="password">123456</property>
  3. <property name="schemas">TESTDB</property>
  4. ....
  5. </user>

4. 访问测试:

登录 MyCAT 数据库:

  1. mysql -uroot -p123456 -h 127.0.0.1 -P 8066

这都是默认的方式,执行  SQL:

至此,MyCAT 安装完成,具体目录结构:

日志路径:/data/services/mycat/logs

配置路径:/data/services/mycat/conf

MyCAT 实现读写分离

1. 事先创建 taobao 库,修改配置文件:schema.xml

  1. <?xml version="1.0"?>
  2. <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
  3. <mycat:schema xmlns:mycat="http://io.mycat/">
  4. <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="" dataNode="DATANODE01"></schema>
  5. <dataNode name="DATANODE01" dataHost="DATAHOST01" database= "taobao" />
  6. <dataHost name="DATAHOST01" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
  7. <heartbeat>select user()</heartbeat>
  8. <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="">
  9. <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="" />
  10. </writeHost>
  11. </dataHost>
  12. </mycat:schema>

注意,命名不能有下划线这些,否则有问题!

2. 重启 MyCAT 测试读写:

  1. mycat restart

测试读写:

  1. mysql -uroot -p123456 -h 127.0.0.1 -P8066

查看结果:

该读写分离最终实现主库宕机,从库也无法使用。

MyCAT 配置读写分离高可用

1. 修改上面的配置,增加另外一组主从:

  1. <?xml version="1.0"?>
  2. <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
  3. <mycat:schema xmlns:mycat="http://io.mycat/">
  4. <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="" dataNode="DATANODE01"></schema>
  5. <dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
  6. <dataHost name="DATAHOST01" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
  7. <heartbeat>select user()</heartbeat>
  8. <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="">
  9. <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="" />
  10. </writeHost>
  11. <writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="123">
  12. <readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="123" />
  13. </writeHost>
  14. </dataHost>
  15. </mycat:schema>

2. 重启 MyCAT 测试:

写操作:

读操作:

可以发现,写操作都是在第一个 write host 上面,其余 3 个尽管有一个也是 write host,但是它由于是 standby write host 的原因,它也只提供读操作。

3. 此时关闭 db01 的 3307 数据库:

写操作:

读操作:

可以发现,当主停掉之后,其附带的从库也跟着停止了服务,最终只剩下一个节点读,一个节点写。

当我们重启恢复 db01 的 3307 时,需要重启 db01 的 3309 的同步服务,否则会出现同步失败。SQL 线程一直 Connecting 状态。

MyCAT schema.xml 参数简单说明

1. dataHost 中的 balance,有三个值:0,1,2:

当值为 0 时,不开启读写分离,所有操作都在 writehost。

当值为 1 时,全部 write host,readhost,standby writehost 都参与负载均衡,也就是一写多读。

当值为 2 时,所有机器都能够执行读操作。

2.  dataHost 中的 writeType,有两个值:0,1:

当值为 0 时,所有写操作都放到一个 writehost 上面。

当值为 1 时,所有写操作都随机分配到所有 writehost 上面,不推荐,容易数据混乱。

3. dataHost 中的 switchType,值有三个:-1,1,2:

当值为 -1 时,不自动切换。

当值为 1 时,自动切换,默认。

当值为 2 时,基于 MySQL 主从状态决定是否切换。

4. dataHost 中的 maxCon,最大连接数。

5. dataHost 中的 minCon,MyCAT 启动后,会在后端数据库开这么多个线程,用于处理请求。

6. heartbeat 心跳检测。

MyCAT 垂直分表

1. 在 3307 组的 tabao 库创建 t1 表:

2. 在 3308 组的 tabao 库创建 t2 表:

3. 配置 schema.xml

  1. <?xml version="1.0"?>
  2. <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
  3. <mycat:schema xmlns:mycat="http://io.mycat/">
  4. <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="" dataNode="DATANODE01">
  5. <table name="t1" dataNode="DATANODE01"/>
  6. <table name="t2" dataNode="DATANODE02"/>
  7. </schema>
  8. <dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
  9. <dataNode name="DATANODE02" dataHost="DATAHOST02" database="taobao" />
  10. <!-- node 1 -->
  11. <dataHost name="DATAHOST01" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
  12. <heartbeat>select user()</heartbeat>
  13. <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="">
  14. <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="" />
  15. </writeHost>
  16. <writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="">
  17. <readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="" />
  18. </writeHost>
  19. </dataHost>
  20. <!-- node 2 -->
  21. <dataHost name="DATAHOST02" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
  22. <heartbeat>select user()</heartbeat>
  23. <writeHost host="WRITEHOST01" url="192.168.100.111:3308" user="root" password="">
  24. <readHost host="READHOST01" url="192.168.100.111:3310" user="root" password="" />
  25. </writeHost>
  26. <writeHost host="WRITEHOST02" url="192.168.100.112:3308" user="root" password="">
  27. <readHost host="READHOST02" url="192.168.100.112:3310" user="root" password="" />
  28. </writeHost>
  29. </dataHost>
  30. </mycat:schema>

4. 重启测试:

  1. mysql -uroot -p123456 -h 127.0.0.1 -P8066

查看:

可以看到,这样就把分布在各个库的表集中到了一个数据库,而且后端还是高可用读写分离的。

MyCAT 水平拆分 - 范围 range

当某个单表数据量实在太大了,就得想办法将其放到不同的库上面,以此来提升查询性能。常用的水平拆分表的方法:范围,取模,枚举,哈希,时间等。

比如对于一张表而言,数据量达到 800 - 1000 万就有个瓶颈了,这时候可能就得想办法对其进行优化了。

假如此时 tabao 库有一张表叫做 t3,我们希望根据他的 ID  1 - 10 存放在数据库集群 1,11 - 20 存放到集群 2。

1. 在 3307 和 3308 的 tabao 库都创建 t3 表:

  1. use taobao;
  2. create table t3(id int, name varchar(10));

2. 修改 mycat 的配置 schema.xml:

  1. <?xml version="1.0"?>
  2. <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
  3. <mycat:schema xmlns:mycat="http://io.mycat/">
  4. <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="" dataNode="DATANODE01">
  5. <table name="t3" dataNode="DATANODE01,DATANODE02" rule="auto-sharding-long" />
  6. </schema>
  7. <dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
  8. <dataNode name="DATANODE02" dataHost="DATAHOST02" database="taobao" />
  9. <!-- node 1 -->
  10. <dataHost name="DATAHOST01" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
  11. <heartbeat>select user()</heartbeat>
  12. <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="">
  13. <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="" />
  14. </writeHost>
  15. <writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="">
  16. <readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="" />
  17. </writeHost>
  18. </dataHost>
  19. <!-- node 2 -->
  20. <dataHost name="DATAHOST02" maxCon="" minCon="" balance="" writeType="" dbType="mysql" dbDriver="native" switchType="">
  21. <heartbeat>select user()</heartbeat>
  22. <writeHost host="WRITEHOST01" url="192.168.100.111:3308" user="root" password="">
  23. <readHost host="READHOST01" url="192.168.100.111:3310" user="root" password="" />
  24. </writeHost>
  25. <writeHost host="WRITEHOST02" url="192.168.100.112:3308" user="root" password="">
  26. <readHost host="READHOST02" url="192.168.100.112:3310" user="root" password="" />
  27. </writeHost>
  28. </dataHost>
  29. </mycat:schema>

和之前的配置不一样的就是 table 定义的部分,因为我们只有一个表,最后我们选择 rule 就是普通的范围方式。

该配置 rule 的配置可以查看 mycat 的配置 rule.xml 中:

  1. <!-- 配置按照哪个字段分 -->
  2. <tableRule name="auto-sharding-long">
  3. <rule>
  4. <columns>id</columns>
  5. <algorithm>rang-long</algorithm>
  6. </rule>
  7. </tableRule>
  8.  
  9. <!-- 分配规则的文件 -->
  10. <function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
  11. <property name="mapFile">autopartition-long.txt</property>
  12. </function>

2. 由于我们本身就是使用 id 字段,所有直接修改 autopartition-long.txt 文件:

  1. 0-10=0
  2. 11-20=1

表示 id 0 - 10 存储到 0 节点,11 - 20 存储到 1 节点。节点计数从 0 开始,如果超出限制 id,是无法插入的,找不到节点。

3. 重启 MyCAT 在  MyCAT 插入数据:

  1. mysql -uroot -p123456 -h 127.0.0.1 -P 8066

执行 SQL:

  1. insert into t3(id,name) values(1,"a");
  2. insert into t3(id,name) values(2,"b");
  3. insert into t3(id,name) values(3,"c");
  4. insert into t3(id,name) values(11,"aa");
  5. insert into t3(id,name) values(12,"bb");
  6. insert into t3(id,name) values(13,"cc");

结果:

4. 去节点查看:

3307 节点:

3308 节点:

可以发现数据被成功分开存储,但是对于 MyCAT 而言,他们还是在一个表。

MyCAT 水平拆分 - 取模 mod

现在准备 tabao 库中准备一个 t4 表,我们希望最终的数据平均的分配到两个节点上面,这时候就用到了取模。

  1. create table t4(id int, name varchar(10));

1. 修改 schema.xml:

  1. <table name="t4" dataNode="DATANODE01,DATANODE02" rule="mod-long" />

和之前的配置只需要修改 rule 的方式为:mod-long

2. 修改 rule.xml

  1. <!-- 配置按照哪个字段取模 -->
  2. <tableRule name="mod-long">
  3. <rule>
  4. <columns>id</columns>
  5. <algorithm>mod-long</algorithm>
  6. </rule>
  7. </tableRule>
  8.  
  9. <!-- 分配节点数 -->
  10. <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
  11. <!-- how many data nodes -->
  12. <property name="count">2</property>
  13. </function>

配置有多少个节点参与进来。由于我们只有两个集群,所有改为 2。

3. 重启 MyCAT 测试:

连接:

  1. mysql -uroot -p123456 -h 127.0.0.1 -P 8066

执行 SQL:

  1. insert into t4(id,name) values(1,"a");
  2. insert into t4(id,name) values(2,"b");
  3. insert into t4(id,name) values(3,"c");
  4. insert into t4(id,name) values(4,"x");
  5. insert into t4(id,name) values(5,"d");
  6. insert into t4(id,name) values(6,"e");
  7. insert into t4(id,name) values(7,"f");
  8. insert into t4(id,name) values(8,"g");
  9. insert into t4(id,name) values(11,"g");
  10. insert into t4(id,name) values(13,"g");

结果:

4. 去单独的节点查看:

3307 节点:

3308 节点:

两个节点取模分配刚好能够实现奇数偶数 id 分开存放。

MyCAT 水平拆分 - 枚举

在某些特殊情况下,例如按照地区进行分配的时候,用前面的方式可能就不合适,所有就有了枚举。可以按照某些规定的值进行分配。

1. 创建一张包含地区的表 t5:

  1. create table t5(id int, name varchar(10), city varchar(10)) charset utf8;

2. 修改 schema.xml:

  1. <table name="t5" dataNode="DATANODE01,DATANODE02" rule="sharding-by-intfile" />

修改 rule 方法为:sharding-by-intfile

3. 修改 rule.xml 配置:

  1. <!-- 配置按照哪个字段枚举 -->
  2. <tableRule name="sharding-by-intfile">
  3. <rule>
  4. <columns>city</columns>
  5. <algorithm>hash-int</algorithm>
  6. </rule>
  7. </tableRule>
  8.  
  9. <!-- 指定配置文件,类型支持中文,默认节点 -->
  10. <function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
  11. <property name="mapFile">partition-hash-int.txt</property>
  12. <property name="type">1</property>
  13. <property name="defaultNode">0</property>
  14. </function>

4. 配置 partition-hash-int.txt

  1. 北京=0
  2. 深圳=1

5. 重启 MyCAT 查看:

  1. mysql -uroot -p123456 -h 127.0.0.1 -P 8066

执行 SQL:

  1. insert into t5(id,name,city) values(1,"a","北京");
  2. insert into t5(id,name,city) values(2,"b","深圳");
  3. insert into t5(id,name,city) values(3,"c","深圳");
  4. insert into t5(id,name,city) values(4,"x","上海");
  5. insert into t5(id,name,city) values(5,"d","天津");
  6. insert into t5(id,name,city) values(6,"d","北京");
  7. insert into t5(id,name,city) values(7,"d","深圳");

结果:

6. 去节点查看:

3307 节点:

3308 节点:

此时发现,北京被保存到了集群 0,深圳保存到了集群 1,其它默认保存到集群 0。

更复杂的按照时间切分可以下去自己了解一下。

全局表和 E-R 分片

我们可以想象这样一个现象,数据库中有很多表,但是这些表分布在不同的数据库,这时候需要将他们 join 查询,会发现他们会有很多不应该存在的开销,而且这个被 join 的表还是那种数据比较稳定,数据量不大,而且不容易更新,例如省市区这种表。这个时候就适合用于全局表,让他在所有节点都保存一份,这样在 join 的适合就职于一用自己主机上面磁盘分区上面的该表,由此节约计算成本,跨库 join 的出现。

只需要在 schema.xml 中将 table 改写为:

  1. <table name="t_area" primaryKey="id" type="global" ataNode="DATANODE01,DATANODE02" />

这就是全局表。

至于 E- R 分片,例如在使用 SQL:

  1. A join B
  2. on a.xx=b.yy
  3. join C
  4. on A.id=C.id

可以增加配置:

  1. <table name="A" dataNode="sh1,sh2" rule="mod-long">
  2. <childTable name="B" joinKey="yy" parentKey="xx" />
  3. </table>

以此来避免跨分片 join 操作。

小结

MyCAT 为我们提供了一种更加全面的读写分离高可用方式,同时分库分表的应用为我们拓宽了数据库横向扩展的道路。

MySQL for OPS 10:MyCAT 分布式架构的更多相关文章

  1. [待完善]mycat分布式架构部署

    mycat介绍:http://mycat.org.cn/ mycat分布式架构部署

  2. MySQL之九---分布式架构(Mycat/DBLE)

    MyCAT基础架构图 双主双从结构 MyCAT基础架构准备 准备环境  环境准备: 两台虚拟机 db01 db02 每台创建四个mysql实例:3307 3308 3309 3310 删除历史环境 p ...

  3. 分享 : 警惕MySQL运维陷阱:基于MyCat的伪分布式架构

    分布式数据库已经进入了全面快速发展阶段.这种发展是与时俱进的,与人的需求分不开,因为现在信息时代的高速发展,导致数据量和交易量越来越大.这种现象首先导致的就是存储瓶颈,因为MySQL数据库实质上还是一 ...

  4. 转:三思!大规模MySQL运维陷阱之基于MyCat的伪分布式架构

    在微信公众号看到一篇关于mycat的文章,觉得分析的很不错,给大家分享一下 三思!大规模MySQL运维陷阱之基于MyCat的伪分布式架构 原文链接:https://mp.weixin.qq.com/s ...

  5. Mysql 高可用(MHA)-读写分离(Atlas)-分布式架构(Mycat)

    Mysql 高可用(MHA)-读写分离(Atlas) 1. 搭建主从复制(一主两从) 1.1 准备环境 1 主库:10.0.0.51/db01 2 从库:10.0.0.52/db02,10.0.0.5 ...

  6. Mycat分布式数据库架构解决方案--Mycat实现读写分离

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 安装完 ...

  7. Mycat分布式数据库架构解决方案--Mycat实现数据库分表

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 准备工 ...

  8. Mycat分布式数据库架构解决方案--schema.xml详解

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 该文件 ...

  9. 安排:《蚂蚁花呗1234面:Redis+分布式架构+MySQL+linux+红黑树》

    前言: 大厂面试机会难得,为了提高面试通关率,建议朋友们在面试前先复盘自己的知识栈,依据掌握程度划分重要.优先级,系统地去学习!如果不准备充分就去参加面试,既会失去进入大厂的机会,更是对自己的不负责. ...

随机推荐

  1. C语言程序设计100例之(19):欢乐的跳

    例19   欢乐的跳 题目描述 一个n个元素的整数数组,如果数组两个连续元素之间差的绝对值包括了[1,n-1]之间的所有整数,则称之符合“欢乐的跳”,如数组1 4 2 3符合“欢乐的跳”,因为差的绝对 ...

  2. 编译原理 #04# 中缀表达式转化为四元式(JavaScript实现)

    // 实验存档 运行截图: 代码中的总体转化流程:中缀表达式字符串→tokens→逆波兰tokens(即后缀表达式)→四元式. 由后缀表达式写出四元式非常容易,比较繁琐的地方在于中缀转逆波兰,这里采用 ...

  3. [WPF 自定义控件]开始一个自定义控件库项目

    1. 目标 我实现了一个自定义控件库,并且打算用这个控件库作例子写一些博客.这个控件库主要目标是用于教学,希望通过这些博客初学者可以学会为自己或公司创建自定义控件,并且对WPF有更深入的了解. 控件库 ...

  4. Java操作数据库——在JDBC里使用事务

    Java操作数据库——在JDBC里使用事务 摘要:本文主要学习了如何在JDBC里使用事务. 使用Connection的事务控制方法 当JDBC程序向数据库获得一个Connection对象时,默认情况下 ...

  5. 简约工作汇报总结演讲辩论创业投资PPT模板

    不管是什么风格的PPT模板,排版布局条例清新,画面干净,也会跟文字内容相辅相成,完成一个好的学生答辩PPT.  模版来源:http://ppt.dede58.com/gongzuohuibao/262 ...

  6. 洗牌算法及 random 中 shuffle 方法和 sample 方法浅析

    对于算法书买了一本又一本却没一本读完超过 10%,Leetcode 刷题从来没坚持超过 3 天的我来说,算法能力真的是渣渣.但是,今天决定写一篇跟算法有关的文章.起因是读了吴师兄的文章<扫雷与算 ...

  7. JavaScript 使用new关键字调用函数

    使用new关键字调用函数 test.js 代码如下 function Person(name, age, obj) { var o = new Object(); o.name = name; o.a ...

  8. canvas绘制星星和月亮

    用变量的方式绘制一个五角星,首先求五角星十个顶点的坐标. 可以把每个五角星看成外顶点用一个大圆绘制,内顶点用小圆绘制.在坐标系(0deg)下,根据每个顶点的角度和圆的半径求得x,y. 而每个大顶点相差 ...

  9. 简单的LNMP安全加固

    安全加固 Nginx安全加固: Nginx配置文件 (nginx.conf):/usr/local/nginx/nginx.conf 禁用autoindex: autoindex:是Nginx的目录浏 ...

  10. 高性能go服务之高效内存分配

    高性能go服务之高效内存分配 手动内存管理真的很坑爹(如C C++),好在我们有强大的自动化系统能够管理内存分配和生命周期,从而解放我们的双手. 但是呢,如果你想通过调整JVM垃圾回收器参数或者是优化 ...