zoukankan      html  css  js  c++  java
  • MySQL-读写分离与分布式架构

    MySQL读写分离概述

    读写分离原理

    基本原理是让数据库处理事务性增、改、删操作(INSERTUPDATEDELETE),而数据库处理SELECT查询操作。数据库复制被用来把事务性操作性操作导致的变更同步到集群中的从数据库=b。

    • 读写分离原理图:

    • 数据内部交换过程:

    为什么要读写分离

    面对越来越大的访问压力,单台的服务器的性能成为瓶颈需要分担负载

    1. 主从只负责各自的读和写,极大程度的缓解 X 锁和 S 锁争用

    2. 从库可配置 myisam 引擎,提升查询性能以及节约系统开销

    3. 增加冗余,提高可用性

    实现读写分离的方式

    一般有两种方式实现

    • 应用程序层实现,网站的程序实现

    • 实现程序层实现指的是在应用程序内部及连接器中实现读写分离

    程序层实现优点:

    1. 应用程序内部实现读写分离,安装即可以使用

    2. 减少一定部署难度

    3. 访问压力在一定级别以下,性能很好

    程序层实现缺点:

    1. 架构一但调整,代码要跟着变

    2. 难以实现高级应用,如自动分库,分表

    3. 无法适用大型应用场景

    中间件实现

    中间件层实现是指在外部中间件程序实现读写分离

    中间件优点:

    1. 架构设计更灵活

    2. 可以在程序上实现一些高级控制,如:透明化水平拆分,failover,监控

    3. 可以依靠技术手段提高MySQL性能

    4. 对业务代码的影响小,同时也安全

    中间件缺点:

    1. 需要一定的开发运维团队的支持

    Atlas中间件

    Atlas介绍

    360团队基于mysql proxy 把lua用C改写。原有版本是支持分表, 目前已经放出了分库分表版本。在网上看到一些朋友经常说在高并 发下会经常挂掉,如果大家要使用需要提前做好测试。

    • Atlas架构图

    Atlas安装

    环境准备:

    主机 IP地址 数据节点 vip地址
    db01 10.0.0.51 master 10.0.0.55
    db02 10.0.0.52 slave-1  
    db03 10.0.0.53 slave-2  

    官方地址:https://github.com/Qihoo360/Atlas/releases

    软件包链接:https://pan.baidu.com/s/15Cr3RgonQANLJ9aT_pFoRw 提取码:p6st

    #在线下载,可能会会比较慢或者失败
    wget https://github.com/Qihoo360/Atlas/releases/download/2.2.1/Atlas-2.2.1.el6.x86_64.rpm
    
    #直接在MHA-2019-6.28.zip里面有
    [root@db01 ~]# rpm -ivh Atlas-2.2.1.el6.x86_64.rpm 
    Preparing...                          ################################# [100%]
    Updating / installing...
       1:Atlas-2.2.1-1                    ################################# [100%]

    配置文件

    cd /usr/local/mysql-proxy/conf
    mv test.cnf test.cnf.bak
    cat > test.cnf <<EOF
    [mysql-proxy]
    admin-username = user
    admin-password = pwd
    proxy-backend-addresses = 10.0.0.55:3306
    proxy-read-only-backend-addresses = 10.0.0.52:3306,10.0.0.53:3306
    pwds = repl:3yb5jEku5h4=,mha:O2jBXONX098=
    daemon = true
    keepalive = true
    event-threads = 8
    log-level = message
    log-path = /usr/local/mysql-proxy/log
    sql-log=ON
    proxy-address = 0.0.0.0:33060
    admin-address = 0.0.0.0:2345
    charset=utf8
    EOF

    proxy-backend-addresses = 10.0.0.55:3306 #填写vip ip地址,谁有vip地址就去写数据

    proxy-read-only-backend-addresses = 10.0.0.52:3306,10.0.0.53:3306 #读数据的数据库

    • 启动atlas
    # /usr/local/mysql-proxy/bin/mysql-proxyd test start
    OK: MySQL-Proxy of test is started
    
    # ps -ef |grep proxy
    root      10236      1  0 12:59 ?        00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/test.cnf
    root      10237  10236  0 12:59 ?        00:00:00 /usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/mysql-proxy/conf/test.cnf
    root      10253   9305  0 13:00 pts/1    00:00:00 grep --color=auto proxy

    测试读写分离功能

    注:master节点在db01上,我们在db03上连接db01进行测试

    [root@db03 ~]# mysql -umha -pmha -h10.0.0.51 -P33060
    • 读操作测试:
    mysql> select @@server_id;
    +-------------+
    | @@server_id |
    +-------------+
    |          53 |
    +-------------+
    1 row in set (0.00 sec)
    
    mysql> select @@server_id;
    +-------------+
    | @@server_id |
    +-------------+
    |          52 |
    +-------------+
    1 row in set (0.00 sec)

    注:可以看到我们的读操作分别在db2和db3上进行了操作

    • 写操作测试:
    mysql> begin;select @@server_id;commit;
    Query OK, 0 rows affected (0.00 sec)
    
    +-------------+
    | @@server_id |
    +-------------+
    |          51 |
    +-------------+
    1 row in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> begin;select @@server_id;commit;
    Query OK, 0 rows affected (0.00 sec)
    
    +-------------+
    | @@server_id |
    +-------------+
    |          51 |
    +-------------+
    1 row in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)

    注:所有的写操作都在db1上进行

    Atlas的管理

    1. 连接查看管理帮助

    #登录管理
    [root@db01 ~]# mysql -uuser -ppwd  -h10.0.0.51 -P2345
    mysql> select * from  help;
    +----------------------------+---------------------------------------------------------+
    | command                    | description                                             |
    +----------------------------+---------------------------------------------------------+
    | SELECT * FROM help         | shows this help                                         |
    | SELECT * FROM backends     | lists the backends and their state                      |
    | SET OFFLINE $backend_id    | offline backend server, $backend_id is backend_ndx's id |
    | SET ONLINE $backend_id     | online backend server, ...                              |
    | ADD MASTER $backend        | example: "add master 127.0.0.1:3306", ...               |
    | ADD SLAVE $backend         | example: "add slave 127.0.0.1:3306", ...                |
    | REMOVE BACKEND $backend_id | example: "remove backend 1", ...                        |
    | SELECT * FROM clients      | lists the clients                                       |
    | ADD CLIENT $client         | example: "add client 192.168.1.2", ...                  |
    | REMOVE CLIENT $client      | example: "remove client 192.168.1.2", ...               |
    | SELECT * FROM pwds         | lists the pwds                                          |
    | ADD PWD $pwd               | example: "add pwd user:raw_password", ...               |
    | ADD ENPWD $pwd             | example: "add enpwd user:encrypted_password", ...       |
    | REMOVE PWD $pwd            | example: "remove pwd user", ...                         |
    | SAVE CONFIG                | save the backends to config file                        |
    | SELECT VERSION             | display the version of Atlas                            |
    +----------------------------+---------------------------------------------------------+
    16 rows in set (0.01 sec)

    2. 查看数据库节点状态

    mysql> select * from backends;
    +-------------+----------------+-------+------+
    | backend_ndx | address        | state | type |
    +-------------+----------------+-------+------+
    |           1 | 10.0.0.55:3306 | up    | rw   |
    |           2 | 10.0.0.52:3306 | up    | ro   |
    |           3 | 10.0.0.53:3306 | up    | ro   |
    +-------------+----------------+-------+------+
    3 rows in set (0.00 sec)
    • rw:支持读写

    • ro:支持只读

    3. 上线和下线节点

    set offline $backend_id        --下线例子:set    offline 2;
    set online    $backend_id        --上线例子:set    online    2;

    4. 添加删除节点

    ADD MASTER     $backend    --添加主节点例子:add master 10.0.0.54:3306;
    ADD slave    $backend    --添加从节点例子:add slave    10.0.0.54:3306;
    REMOVE    BACKEND    $backend_id    --删除节点    

    5. 用户管理

    select    * from pwds    --查看用户
    ADD    PWD    $pwd        --添加一个用户,使用的是明文
    ADD    ENPWD    $pwd    --添加一个用户,使用密文
    REMOVE    PWD    $pwd    --删除用户

    6. 永久生效

    mysql> save config;
    • 企业用户管理案例

    1. 数据库主节点

    grant all on *.* to china@'10.0.0.%' identified by '123';

    2. Atlas中添加数据库用户

    #明文
    ADD PWD china:123;
    
    #密文
    /usr/local/mysql-proxy/bin/encrypt 123
    [root@db01 ~]# /usr/local/mysql-proxy/bin/encrypt 123
    3yb5jEku5h4=
    
    ADD  ENPWD china:3yb5jEku5h4=

    配置永久生效

    save config;

    MySQL分布式架构

    基础环境准备

    • 架构表格
    主机 实例 端口 数据目录
    db01 mysql3307 3307 /data/3307/data
    db02 mysql3308 3308 /data/3308/data
      mysql3309 3309 /data/3309/data
      mysql3310 3310 /data/3310/data
    • 架构图:

    1. 环境准备

      •   数据库版本:MySQL 5.7.28

      •   两台虚拟机:db01、db02

      •   每台创建四个MySQL实例:3307、3308、3309、3310

    1. 删除历史环境

    pkill mysqld
    rm -rf /data/33{07..10}
    mv /etc/my.cnf /etc/my.cnf.bak

      3创建相关目录初始化数据

    mkdir /data/33{07..10}/data -p
    mysqld --initialize-insecure  --user=mysql --datadir=/data/3307/data --basedir=/app/database/mysql
    mysqld --initialize-insecure  --user=mysql --datadir=/data/3308/data --basedir=/app/database/mysql
    mysqld --initialize-insecure  --user=mysql --datadir=/data/3309/data --basedir=/app/database/mysql
    mysqld --initialize-insecure  --user=mysql --datadir=/data/3310/data --basedir=/app/database/mysql

      4.准备配置文件和脚本

    • db01配置文件和启动脚本
    #db01配置文件
    cat >/data/3307/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3307/data
    socket=/data/3307/mysql.sock
    port=3307
    log-error=/data/3307/mysql.log
    log_bin=/data/3307/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=7
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    
    cat >/data/3308/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3308/data
    port=3308
    socket=/data/3308/mysql.sock
    log-error=/data/3308/mysql.log
    log_bin=/data/3308/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=8
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    
    cat >/data/3309/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3309/data
    socket=/data/3309/mysql.sock
    port=3309
    log-error=/data/3309/mysql.log
    log_bin=/data/3309/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=9
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    
    cat >/data/3310/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3310/data
    socket=/data/3310/mysql.sock
    port=3310
    log-error=/data/3310/mysql.log
    log_bin=/data/3310/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=10
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    
    #db01启动文件
    cat >/etc/systemd/system/mysqld3307.service<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf
    LimitNOFILE = 5000
    EOF
    
    cat >/etc/systemd/system/mysqld3308.service<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3308/my.cnf
    LimitNOFILE = 5000
    EOF
    
    cat >/etc/systemd/system/mysqld3309.service<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3309/my.cnf
    LimitNOFILE = 5000
    EOF
    
    cat >/etc/systemd/system/mysqld3310.service<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3310/my.cnf
    LimitNOFILE = 5000
    EOF
    • db02配置文件和启动文件
    #配置文件
    cat >/data/3307/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3307/data
    socket=/data/3307/mysql.sock
    port=3307
    log-error=/data/3307/mysql.log
    log_bin=/data/3307/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=17
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    cat >/data/3308/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3308/data
    port=3308
    socket=/data/3308/mysql.sock
    log-error=/data/3308/mysql.log
    log_bin=/data/3308/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=18
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    cat >/data/3309/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3309/data
    socket=/data/3309/mysql.sock
    port=3309
    log-error=/data/3309/mysql.log
    log_bin=/data/3309/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=19
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    
    cat >/data/3310/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3310/data
    socket=/data/3310/mysql.sock
    port=3310
    log-error=/data/3310/mysql.log
    log_bin=/data/3310/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=20
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    
    #启动文件
    cat >/etc/systemd/system/mysqld3307.service<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf
    LimitNOFILE = 5000
    EOF
    
    cat >/etc/systemd/system/mysqld3308.service<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3308/my.cnf
    LimitNOFILE = 5000
    EOF
    
    cat >/etc/systemd/system/mysqld3309.service<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3309/my.cnf
    LimitNOFILE = 5000
    EOF
    
    cat >/etc/systemd/system/mysqld3310.service<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3310/my.cnf
    LimitNOFILE = 5000
    EOF

      5. 修改权限,启动多实例

    chown -R mysql.mysql /data/*
    systemctl start mysqld3307
    systemctl start mysqld3308
    systemctl start mysqld3309
    systemctl start mysqld3310
    netstat -lntup
    
    mysql -S /data/3307/mysql.sock -e "show variables like 'server_id'"
    mysql -S /data/3308/mysql.sock -e "show variables like 'server_id'"
    mysql -S /data/3309/mysql.sock -e "show variables like 'server_id'"
    mysql -S /data/3310/mysql.sock -e "show variables like 'server_id'"

      6. 节点主从规划

      箭头指向谁是主库

    • shard1

      10.0.0.51:3307 <-----> 10.0.0.52:3307

      10.0.0.51:3309 ------> 10.0.0.51:3307

      10.0.0.52:3309 ------> 10.0.0.52:3307

    • shard2

      10.0.0.52:3308 <-----> 10.0.0.51:3308
      10.0.0.52:3310 -----> 10.0.0.52:3308
      10.0.0.51:3310 -----> 10.0.0.51:3308

      7.开始配置

    ##shard1

    10.0.0.51:3307 <-----> 10.0.0.52:3307

    • db02
    mysql  -S /data/3307/mysql.sock -e "grant replication slave on *.* to repl@'10.0.0.%' identified by '123';"
    mysql  -S /data/3307/mysql.sock -e "grant all  on *.* to root@'10.0.0.%' identified by '123'  with grant option;"
    • db01
    mysql  -S /data/3307/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
    mysql  -S /data/3307/mysql.sock -e "start slave;"
    mysql  -S /data/3307/mysql.sock -e "show slave statusG"
    • db02
    mysql  -S /data/3307/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
    mysql  -S /data/3307/mysql.sock -e "start slave;"
    mysql  -S /data/3307/mysql.sock -e "show slave statusG"

    10.0.0.51:3309 ------> 10.0.0.51:3307

    • db01
    mysql  -S /data/3309/mysql.sock  -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
    mysql  -S /data/3309/mysql.sock  -e "start slave;"
    mysql  -S /data/3309/mysql.sock  -e "show slave statusG"

    10.0.0.52:3309 ------> 10.0.0.52:3307

    • db02
    mysql  -S /data/3309/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3307, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
    mysql  -S /data/3309/mysql.sock -e "start slave;"
    mysql  -S /data/3309/mysql.sock -e "show slave statusG"

    ##shard2

    10.0.0.52:3308 <-----> 10.0.0.51:3308

    • db01
    mysql  -S /data/3308/mysql.sock -e "grant replication slave on *.* to repl@'10.0.0.%' identified by '123';"
    mysql  -S /data/3308/mysql.sock -e "grant all  on *.* to root@'10.0.0.%' identified by '123'  with grant option;"
    • db02
    mysql  -S /data/3308/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
    mysql  -S /data/3308/mysql.sock -e "start slave;"
    mysql  -S /data/3308/mysql.sock -e "show slave statusG"
    • db01
    mysql  -S /data/3308/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
    mysql  -S /data/3308/mysql.sock -e "start slave;"
    mysql  -S /data/3308/mysql.sock -e "show slave statusG"

    10.0.0.52:3310 -----> 10.0.0.52:3308

    • db02
    mysql  -S /data/3310/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.52', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
    mysql  -S /data/3310/mysql.sock -e "start slave;"
    mysql  -S /data/3310/mysql.sock -e "show slave statusG"

    10.0.0.51:3310 -----> 10.0.0.51:3308

    • db01
    mysql  -S /data/3310/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='10.0.0.51', MASTER_PORT=3308, MASTER_AUTO_POSITION=1, MASTER_USER='repl', MASTER_PASSWORD='123';"
    mysql  -S /data/3310/mysql.sock -e "start slave;"
    mysql  -S /data/3310/mysql.sock -e "show slave statusG"

      8. 检查主从状态

    mysql -S /data/3307/mysql.sock -e "show slave statusG"|grep "Running:"
    mysql -S /data/3308/mysql.sock -e "show slave statusG"|grep "Running:"
    mysql -S /data/3309/mysql.sock -e "show slave statusG"|grep "Running:"
    mysql -S /data/3310/mysql.sock -e "show slave statusG"|grep "Running:"

    注:(没问题不要做这部!!!!) 如果中间出现错误,在每个节点进行执行以下命令

    mysql -S /data/3307/mysql.sock -e "stop slave; reset slave all;"
    mysql -S /data/3308/mysql.sock -e "stop slave; reset slave all;"
    mysql -S /data/3309/mysql.sock -e "stop slave; reset slave all;"
    mysql -S /data/3310/mysql.sock -e "stop slave; reset slave all;"

    分布式架构演变

    Mycat中间件安装

    Mycat介绍

    1. Mycat是目前最流行的基于Java语言编写的数据库中间件,是一个实现了MySQL协议的服务器,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分库分表。配合数据库的主从模式还可以实现读写分离

    2. Mycat是基于阿里开源的Cobar产品研发,Cobar的稳定性、可靠性、优秀的bib架构性能以及众多成熟的使用案例使得Mycat变得非常强大。

    3. Mycat发展到目前版本,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQL Server、Orale、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。而在最终用户看来,无论是那种存储方式,在Mycat里,都是一个传统的数据库表,支持标准的SQL语句,这样一来,对前端业务系统来说,可以大幅度降低开发难度,提升开发速度。

    Mycat架构图:

    Mycat应用

    官方下载主页:http://www.mycat.io

    下载地址:http://dl.mycat.io/

    上传解压软件

    mkdir /data/mycat/
    cd /data/mycat
    wget http://dl.mycat.io/1.6.7.1/Mycat-server-1.6.7.1-release-20190627191042-linux.tar.gz
    tar xf Mycat-server-1.6.7.1-release-20190627191042-linux.tar.gz
    
    #添加
    export PATH=/data/mycat/bin:$PATH
    
    #生效
    source  /etc/profile

    配置Java环境

    网盘地址:https://pan.baidu.com/s/1CN5Je6O9zPoIcDMDV91AFQ 提取码:zymi

    • 解压到/usr/local,创建软连接
    mkdir  /app/
    tar xf jdk-8u221-linux-x64.tar.gz -C /app/
    ln -s /app/jdk1.8.0_221/  /app/jdk
    • 全局环境变量
    export JAVA_HOME=/app/jdk
    export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
    export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jarq
    
    . /etc/profile
    • 测试版本
    [root@db01 /app]# java -version
    java version "1.8.0_221"
    Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
    Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)

    注:实验环境直接yum install java -y

    启动测试

    [root@db01 mycat]# mycat start
    Starting Mycat-server...
    [root@db01 mycat]#  mysql -uroot -p123456 -h 127.0.0.1 -P8066

    软件结构

    优秀博文:https://www.jianshu.com/p/04a26a1307f2

    bin:程序目录

    mycat 程序,启动和关闭mycat中间件

    conf:配置相关目录

    schema.xml 主配置文件

    rule.xml 分片配置

    server.xml mycat服务相关配置

    logs:日志相关目录

    wrapper.log

    mycat.log

    schema.xml配置文件结构

    [root@db01 conf]# cd /data/mycat/conf/
    mv schema.xml schema.xml.bak
    vim schema.xml
    # 逻辑库: 
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> 
    </schema>  
    # DN数据节点(逻辑分片):数据节点(逻辑分片): 
        <dataNode name="dn1" dataHost="localhost1" database= "world" />      
    作用: 
        垂直和水平查分。    
    # DH 数据主机
    作用: 高可用和读写分离
        <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
            <heartbeat>select user()</heartbeat>  
        <writeHost host="db1" url="10.0.0.51:3307" user="root" password="123">  #写的节点
                <readHost host="db2" url="10.0.0.51:3309" user="root" password="123" />  #读的节点
        </writeHost> 
        </dataHost>  
    </mycat:schema>
    • schema.xml文件逻辑结构

     

    测试环境准备

    注:测试word.sql数据库

    word.sql链接地址:https://pan.baidu.com/s/1kUecaHEjQzsRGUlFfw4_5A 提取码:j3o9

    • 配置文件
    vim /data/mycat/conf/schema.xml
    <?xml version="1.0"?>  
    <!DOCTYPE mycat:schema SYSTEM "schema.dtd">  
    <mycat:schema xmlns:mycat="http://io.mycat/">
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> 
    </schema>  
        <dataNode name="dn1" dataHost="localhost1" database= "world" />  
        <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
            <heartbeat>select user()</heartbeat>  
        <writeHost host="db1" url="10.0.0.51:3307" user="root" password="123"> 
                <readHost host="db2" url="10.0.0.51:3309" user="root" password="123" /> 
        </writeHost> 
        </dataHost>  
    </mycat:schema>
    • db01:
    mysql -S /data/3307/mysql.sock 
    grant all on *.* to root@'10.0.0.%' identified by '123';
    source /root/world.sql
    
    mysql -S /data/3308/mysql.sock 
    grant all on *.* to root@'10.0.0.%' identified by '123';
    source /root/world.sql
    • 重启mycat
    # mycat restart
    Stopping Mycat-server...
    Stopped Mycat-server.
    Starting Mycat-server...

    读写分离测试

    • 连接mycat服务
    [root@db01 ~]# mysql -uroot -p123456 -h 10.0.0.51 -P8066
    # 测试读
    mysql> select @@server_id;
    +-------------+
    | @@server_id |
    +-------------+
    |           9 |
    +-------------+
    1 row in set (0.05 sec)
    
    # 测试写
    mysql> begin ; select @@server_id;commit;
    +-------------+
    | @@server_id |
    +-------------+
    |           7 |
    +-------------+
    1 row in set (0.00 sec)

    配置读写分离及高可用

    [root@db01 conf]# mv schema.xml schema.xml.rw
    [root@db01 conf]# vim schema.xml
    <?xml version="1.0"?>  
    <!DOCTYPE mycat:schema SYSTEM "schema.dtd">  
    <mycat:schema xmlns:mycat="http://io.mycat/">
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="sh1"> 
    </schema>  
        <dataNode name="sh1" dataHost="oldguo1" database= "world" />  
        <dataHost name="oldguo1" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
            <heartbeat>select user()</heartbeat>  
        <writeHost host="db1" url="10.0.0.51:3307" user="root" password="123"> 
                <readHost host="db2" url="10.0.0.51:3309" user="root" password="123" /> 
        </writeHost> 
        <writeHost host="db3" url="10.0.0.52:3307" user="root" password="123"> 
                <readHost host="db4" url="10.0.0.52:3309" user="root" password="123" /> 
        </writeHost>        
        </dataHost>  
    </mycat:schema>
    
    [root@db01 conf]# mycat restart
    Stopping Mycat-server...
    Stopped Mycat-server.
    Starting Mycat-server...

    真正的 writehost:负责写操作的writehost

    standby writehost:和readhost一样,只提供读服务

    当写节点宕机后,后面跟的readhost也不提供服务,这时候standby的writehost就提供写服务,后面跟的readhost提供读服务

    • 测试
    mysql -uroot -p123456 -h 127.0.0.1 -P 8066
    show variables like 'server_id';
    • 读写分离测试
    mysql -uroot -p -h 127.0.0.1 -P8066
    show variables like 'server_id';
    show variables like 'server_id';
    show variables like 'server_id';
    begin;
    show variables like 'server_id';

    参数介绍

    有两个参数需要注意,balanceswitchType

    其中,balance指的负载均衡类型,目前的取值有4种:

    1. balance="0":不开启读写分离机制,所有读操作都发送发到当前可用的writeHost上。

    2. balance="1":全部的readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1-->S1,M2-->S2,并且 M1与 M2 互为主备),正常情况下,M2,S1,S2 都参与 select 语句的负载均衡。

    3. balance="2":所有读操作都随机的在writeHostreadhost上分发。

    4. balance="3":所有读请求随机的分发到writeHost对应的readhost执行,writeHost不负担读压力

    switchType指的是切换模式,目前的取值也有4种:

    1. switchType="-1":表示不自动切换

    2. switchType="1":默认值,表示自动切换

    3. switchType="2":基于MySQL主从同步的状态决定是否切换,心跳语句为 show slave status;

    4. switchType="3":基于 MySQL galary cluster 的切换机制(适合集群),心跳语句为 show status like 'wsrep%'

    datahost其他配置

    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1"> 
    • maxCon="1000":最大的并发连接数

    • minCon="10":mycat在启动之后,会在后端节点上自动连接线程

    • tempReadHostAvailable="1":这个一主一从(1个writehost,1个readhost时),可以开启这个参数,如果2个writehost,2个readhost时<heartbeat>select user()</heartbeat> 监测心跳

    Mycat分库分表

    环境恢复

    • 重启所有节点
    systemctl restart mysqld3307
    systemctl restart mysqld3308
    systemctl restart mysqld3309
    sysetmctl restart mysqld3310
    • 查看主从状态
    mysql -S /data/3307/mysql.sock -e "show slave statusG"|grep "Running:"
    mysql -S /data/3308/mysql.sock -e "show slave statusG"|grep "Running:"
    mysql -S /data/3309/mysql.sock -e "show slave statusG"|grep "Running:"
    mysql -S /data/3310/mysql.sock -e "show slave statusG"|grep "Running:"

    Mycat分布式架构--垂直分表

    分片

    • 垂直分片:将不同的表切分到不同的数据库中

    • 水平切片:将同一种表按照某个条件切分到不同的数据库中

    分表架构图:

    cd /data/mycat/conf
    mv schema.xml    schema.xml.ha
    vim schema.xml
    <?xml version="1.0"?>
    <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
    <mycat:schema xmlns:mycat="http://io.mycat/">
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="sh1">
            <table name="user" dataNode="sh1"/>
            <table name="order_t" dataNode="sh2"/>
    </schema>
        <dataNode name="sh1" dataHost="oldguo1" database= "taobao" />
        <dataNode name="sh2" dataHost="oldguo2" database= "taobao" />
        <dataHost name="oldguo1" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1">
            <heartbeat>select user()</heartbeat>
        <writeHost host="db1" url="10.0.0.51:3307" user="root" password="123">
                <readHost host="db2" url="10.0.0.51:3309" user="root" password="123" />
        </writeHost>
        <writeHost host="db3" url="10.0.0.52:3307" user="root" password="123">
                <readHost host="db4" url="10.0.0.52:3309" user="root" password="123" />
        </writeHost>
        </dataHost>
        
        <dataHost name="oldguo2" maxCon="1000" minCon="10" balance="1"  writeType="0" dbType="mysql"  dbDriver="native" switchType="1">
            <heartbeat>select user()</heartbeat>
        <writeHost host="db1" url="10.0.0.51:3308" user="root" password="123">
                <readHost host="db2" url="10.0.0.51:3310" user="root" password="123" />
        </writeHost>
        <writeHost host="db3" url="10.0.0.52:3308" user="root" password="123">
                <readHost host="db4" url="10.0.0.52:3310" user="root" password="123" />
        </writeHost>
        </dataHost>
        
    </mycat:schema>
    • 创建测试库和表
    mysql -S /data/3307/mysql.sock -e "create database taobao charset utf8;"
    mysql -S /data/3308/mysql.sock -e "create database taobao charset utf8;"
    mysql -S /data/3307/mysql.sock -e "use taobao;create table user(id int,name varchar(20))";
    mysql -S /data/3308/mysql.sock -e "use taobao;create table order_t(id int,name varchar(20))"
    • 重启mycat
    mycat restart
    • 读操作测试
    mysql -uroot -p123456 -h10.0.0.51 -P8066
    mysql> use TESTDB;
    mysql> show tables;
    +------------------+
    | Tables_in_taobao |
    +------------------+
    | order_t          |
    | user             |
    +------------------+
    2 rows in set (0.00 sec)
    
    [root@db01 /data/mycat/conf]# mysql -S /data/3307/mysql.sock -e "show tables from  taobao"
    +------------------+
    | Tables_in_taobao |
    +------------------+
    | user             |
    +------------------+
    [root@db01 /data/mycat/conf]# mysql -S /data/3308/mysql.sock -e "show tables from  taobao"
    +------------------+
    | Tables_in_taobao |
    +------------------+
    | order_t          |
    +------------------+

    Mycat分布式架构--水平拆分

    • 垂直分片:将不同的表切分到不同的数据库中

    • 水平切片:将同一种表按照某个条件切分到不同的数据库中

    水平拆分架构图:

    水平分库分表重要概念

    文章地址:https://cloud.tencent.com/developer/article/1526776

    水平拆分:

    水平拆分也有两种:水平分表和水平分库分表。

     

    水平分表:

    水平分表和垂直分表区别在于垂直分表针对列,将不常用的列拆分到辅助表。而水平分表针对的是表,在同一个数据库中创建多张一样的表,比如我们在order数据库中创建三张订单表order1、order2、order3,然后插入订单时将id对3取余,根据不同的值存入不同的订单表,但是由于水平分表是将数据表存放在同一个数据库,水平分表可以降低单标的数据量,有助于提高查询效率。如果业务量很大一样会受到服务器lo的瓶颈,所以我们经常使用的还是水平分库分表。

     

    水平分开库分表:

    水平分库实际上就是在多台不同的机器分别创建数据库和数据表,比如订单表我们可以在两个有主从复制和MHA的集群里分别创建order数据库和order数据表,然后根据一定的逻辑将不同的数据存放在不同机器的数据库中。一般来说水平拆分主要有以下几种拆分规则:

    • 范围拆分:比如订单表通过id拆分,id在1到500w在集群db01内的order数据库,id在501-1000w在集群db02内的order数据库,依次类推

    • 地理拆分:将订单表按照不同地区将表中的数据拆分到不同数据库的order数据库中存储。比如可以安装省份来进行拆分。

    • 取模拆分:取模就是刚才在水平分表讲到的比如有三个订单表,可以将id对3取余,但是区别在于水平分库分表是将同样的数据库和数据表存放在不同机器,所以可以说有效缓解单机瓶颈问题。

    • 时间拆分:根据时间来拆分表中的数据,可以将表中创建时间超过一年的数据拆分到其他数据库的order数据库存储,原表中只保留被查询概率较高的数据而这部分数据往往都是近期才创建的,所以可以通过时间拆分实现冷热数据分离。

    范围分片

    比如说t3表

    1. 行数非常多,2000w(1-1000w:sh1 1000w-2000w:sh2)

    2. 访问非常频繁,用户访问较离散

    • 修改schema.xml文件,定制分片策略
    cp schema.xml schema.xml.1  
    vim schema.xml
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="sh1"> 
            <table name="t3" dataNode="sh1,sh2" rule="auto-sharding-long" />  ---对t3表进行定制分片策略
    </schema>  
        <dataNode name="sh1" dataHost="oldguo1" database= "taobao" /> 
        <dataNode name="sh2" dataHost="oldguo2" database= "taobao" /> 
    • rule.xml文件配置切分规则
    vim rule.xml
    <!-- name属性指定分片规则的名称,必须在 rule.xml 文件中是唯一的 -->
    <tableRule name="auto-sharding-long">
                    <rule>
                    <!-- 指定使用表中的哪个列进行分片 -->
                            <columns>id</columns>
                            <!-- 指定表的分片算法,取值为<function>标签的name属性 -->
                            <algorithm>rang-long</algorithm>
                    </rule>     
    
                    
    <function name="rang-long"
        class="io.mycat.route.function.AutoPartitionByLong">
        <!-- 使用range-log需要搭配autopartition-long.txt这个文件 -->
        <property name="mapFile">autopartition-long.txt</property>
    </function>
    • autopartition-long.txt 定制范围-range
    # range start-end,data node index
    # k=1000,M=10000.
    0-10=0
    10-20=1
    
    # 0,1是分片的编号
    • 创建测试表
    mysql -S /data/3307/mysql.sock -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"
    mysql -S /data/3308/mysql.sock  -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"
    • 测试
    # 重启mycat
    mycat restart
    mysql -uroot -p123456 -h 127.0.0.1 -P 8066
    insert into t3(id,name) values(1,'a');
    insert into t3(id,name) values(2,'b');
    insert into t3(id,name) values(3,'c');
    insert into t3(id,name) values(4,'d');
    insert into t3(id,name) values(11,'aa');
    insert into t3(id,name) values(12,'bb');
    insert into t3(id,name) values(13,'cc');
    insert into t3(id,name) values(14,'dd');
    
    [root@db01 conf]# mysql -S /data/3308/mysql.sock  -e "select * from taobao.t3"
    +----+------+
    | id | name |
    +----+------+
    | 11 | aa   |
    | 12 | bb   |
    | 13 | cc   |
    | 14 | dd   |
    +----+------+
    [root@db01 conf]# mysql -S /data/3307/mysql.sock  -e "select * from taobao.t3"
    +----+------+
    | id | name |
    +----+------+
    |  1 | a    |
    |  2 | b    |
    |  3 | c    |
    |  4 | d    |
    +----+------+

    取模(取余数)分片

    取余分片方式:分片键(一个列)与节点数量进行取余,得到余数,将数据写入对应节点

    • 复制配置文件
    #修改配置文件
    vim schema.xml
    <table name="t4" dataNode="sh1,sh2" rule="mod-long" />
    
    #查看和定义分片使用
    vim rule.xml
    <property name="count">2</property>  #这里我们有几个节点就写几,这里我们是2个多实例节点
    • 准备测试环境
    #创建t4测试表
    mysql -S /data/3307/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"
    mysql -S /data/3308/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"
    
    #重启mycat
    mycat restart
    
    #测试
    mysql -root -p123456 -h10.0.0.051 -P8066
    
    use TESTDB
    insert into t4(id,name) values(1,'a');
    insert into t4(id,name) values(2,'b');
    insert into t4(id,name) values(3,'c');
    insert into t4(id,name) values(4,'d');
    insert into t4(id,name) values(6,'x'),(8,'y'),(10,'z');
    
    #分别登录后端节点查询数据
    mysql -S /data/3308/mysql.sock  -e "select * from taobao.t4"
    +----+------+
    | id | name |
    +----+------+
    |  1 | a    |
    |  3 | c    |
    +----+------+
    
    mysql -S /data/3307/mysql.sock  -e "select * from taobao.t4"
    +----+------+
    | id | name |
    +----+------+
    |  2 | b    |
    |  4 | d    |
    |  6 | x    |
    |  8 | y    |
    | 10 | z    |
    +----+------+

    枚举分片

    所谓的枚举分片,就是通过在配置文件中配置可能的枚举id,自己配置分片,本规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国省份区县固定的,具体使用场景可根据自己具体的业务场景确定。 

    • 表格规划
    t5 表
    id name telnum
    1   bj   1212
    2   sh   22222
    3   bj   3333
    4   sh   44444
    5   bj   5555
    
    #使用的函数
    sharding-by-intfile
    • schema.xml配置文件
    <table name="t5" dataNode="sh1,sh2" rule="sharding-by-intfile" />
    • rule.xml分片配置文件
    vim rule.xml
    <tableRule name="sharding-by-intfile"> 
    <rule> <columns>name</columns>
    <algorithm>hash-int</algorithm> 
    </rule> 
    </tableRule> 
    
    <function name="hash-int" class="org.opencloudb.route.function.PartitionByFileMap"> 
    <property name="mapFile">partition-hash-int.txt</property> 
      <property name="type">1</property>
      ###type这一列,打开中英文的支持
      <property name="defaultNode">1</property>
      ###这里行是添加的其他数据默认加入sh=1里面
    </function>

    注:根据name这个列条件分片<rule> <columns>name</columns>

    • partition-hash-int.txt配置
    bj=0 
    sh=1
    DEFAULT_NODE=1
    #上面这个参数是其他数据往sh=1这个表里走

    注:columns 标识将要分片的表字段,algorithm 分片函数, 其中分片函数配置中,mapFile标识配置文件名称

    • 准备测试环境
    mysql -S /data/3307/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"
    mysql -S /data/3308/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"
    • 重启mycat,查看结构
    #重启
    mycat restart 
    
    #连接加入表数据
    mysql -uroot -p123456 -h10.0.0.51 -P8066
    use TESTDB
    insert into t5(id,name) values(1,'bj');
    insert into t5(id,name) values(2,'sh');
    insert into t5(id,name) values(3,'bj');
    insert into t5(id,name) values(4,'sh');
    insert into t5(id,name) values(5,'tj');
    
    #查看结果
    mysql -S /data/3308/mysql.sock  -e "select * from taobao.t5"
    +----+------+
    | id | name |
    +----+------+
    |  2 | sh   |
    |  4 | sh   |
    |  5 | tj   |
    +----+------+
    
    mysql -S /data/3307/mysql.sock  -e "select * from taobao.t5"
    +----+------+
    | id | name |
    +----+------+
    |  1 | bj   |
    |  3 | bj   |
    +----+------+

    mycat全局表

    a   b   c  d   .....
    join 
    t
    
    select  t1.name   ,t.x  from  t1 
    join t 
    select  t2.name   ,t.x  from  t2 
    join t 
    select  t3.name   ,t.x  from  t3 
    join t

    注:所有表都要去join t这张表,我们要把这张表变成全局表

    • 应用场景:

      如果你的业务中有些数据类似于数据字典,比如配置文件的配置, 常用业务的配置或者数据量不大很少变动的表,这些表往往不是特别大, 而且大部分的业务场景都会用到,那么这种表适合于Mycat全局表,无须对数据进行切分, 要在所有的分片上保存一份数据即可,Mycat 在Join操作中,业务表与全局表进行Join聚合会优先选择相同分片内的全局表join, 避免跨库Join,在进行数据插入操作时,mycat将把数据分发到全局表对应的所有分片执行,在进行数据读取时候将会随机获取一个节点读取数据。

    • 编辑配置文件schema.xml

    vim schema.xml
    <table name="t_area" primaryKey="id"  type="global" dataNode="sh1,sh2" />
    • 后端数据准备
    mysql -S /data/3307/mysql.sock -e "use taobao;create table t_area (id int not null primary key auto_increment,name varchar(20) not null);"
    mysql -S /data/3308/mysql.sock -e "use taobao;create table t_area (id int not null primary key auto_increment,name varchar(20) not null);"
    • 重启mycat
    mycat restart
    • 测试
    mysql -uroot -p123456 -h10.0.0.51 -P8066
    
    use TESTDB
    insert into t_area(id,name) values(1,'a');
    insert into t_area(id,name) values(2,'b');
    insert into t_area(id,name) values(3,'c');
    insert into t_area(id,name) values(4,'d');
    
    #查看表
    mysql -S /data/3308/mysql.sock  -e "select * from taobao.t_area"
    +----+------+
    | id | name |
    +----+------+
    |  1 | a    |
    |  2 | b    |
    |  3 | c    |
    |  4 | d    |
    +----+------+
    
    mysql -S /data/3307/mysql.sock  -e "select * from taobao.t_area"
    +----+------+
    | id | name |
    +----+------+
    |  1 | a    |
    |  2 | b    |
    |  3 | c    |
    |  4 | d    |
    +----+------+

    E-R分片

    join是关系数据库最常用的一个特性,然而在分布式环境中,跨分片的join最复杂,最难解决

    比如:

    mycat逻辑库word,两张表格t1,t2.做了分库策略,t1放到了datanode1,t2放到了datanode2,如果我t1 join t2检索数据,

    怎么办?

    这就是E-R关系策略要解决的问题。

    mycat借鉴了table group的概念,将子表的存储位置依赖于子表,并且在物理上紧邻存放,解决了join的效率和性能问题。E-R关系的数据库分片策略,根据这一思路,将子表的记录和所关联的父表存档在同一个数据分片上。

    a
    join 
    b 
    on  a.xx =b.yy

    为了防止跨分片join,可以使用E-R模式

    <table name="a" dataNode="sh1,sh2" rule="mod-long"> 
           <childTable name="b" joinKey="aid" parentKey="id" /> 
    </table>
    ### a表结构
    id  name             
    1   a    
    2   b    
    3   c    
    4   d   
    
    
    ### b表结构 
    id   addr  aid
    1001  bj   1
    1002  sh   2 
    1003  tj   3
    1004  wh   4 
    
    ### 两表之间join关联
    select * from a join b on a.id = b.aid where a.name=d

    例子:a表和b表做E-R分片,并进行join

      1. 修改配置文件

    vim schema.xml
    <table name="a" dataNode="sh1,sh2" rule="mod-long_china"> 
           <childTable name="b" joinKey="aid" parentKey="id" /> 
    </table>

    注:a是主,b是负

      2. 修改rule.xml mod-log分片策略:

    vim rule.xml
            <tableRule name="mod-long_china">
                    <rule>
                            <columns>id</columns>
                            <algorithm>mod-long_china</algorithm>
                    </rule>
            </tableRule>
    
            <function name="mod-long_china" class="io.mycat.route.function.PartitionByMod">
                    <!-- how many data nodes -->
                    <property name="count">2</property>
            </function>

    注:tableRule里的name是我们自定义的,在文件下方的函数也要进行创建,可以参考旁边的mod-log

      3. 创建测试表

    mysql -S /data/3307/mysql.sock -e "use taobao;create table a (id int not null primary key auto_increment,name varchar(20) not null);"
    mysql -S /data/3307/mysql.sock -e "use taobao;create table b (id int not null primary key auto_increment,addr varchar(20) not null ,aid int );"
    
    mysql -S /data/3308/mysql.sock -e "use taobao;create table a (id int not null primary key auto_increment,name varchar(20) not null);"
    mysql -S /data/3308/mysql.sock -e "use taobao;create table b (id int not null primary key auto_increment,addr varchar(20) not null ,aid int );"

      4. 重启mycat测试

    mycat restart
    mysql -uroot -p123456 -h10.0.0.51 -P8066
    use TESTDB
    insert into a(id,name) values(1,'a');
    insert into a(id,name) values(2,'b');
    insert into a(id,name) values(3,'c');
    insert into a(id,name) values(4,'d');
    insert into a(id,name) values(5,'e');
    
    insert into b(id,addr,aid) values(1001,'bj',1);
    insert into b(id,addr,aid) values(1002,'sj',3);
    insert into b(id,addr,aid) values(1003,'sd',4);
    insert into b(id,addr,aid) values(1004,'we',2);
    insert into b(id,addr,aid) values(1005,'er',5);

      5. 后端数据节点数据分布

    mysql -S /data/3307/mysql.sock  -e "select * from taobao.a"
    mysql -S /data/3307/mysql.sock  -e "select * from taobao.b"
    
    mysql -S /data/3308/mysql.sock  -e "select * from taobao.a"
    mysql -S /data/3308/mysql.sock  -e "select * from taobao.b"

    server.xml解读

    管理逻辑库 默认是TESTDB

      1. 逻辑库名

    schema.xml 
    <schema name="china" checkSQLschema="false" sqlMaxLimit="100" dataNode="sh1">
    
    server.xml
     <user name="root" defaultAccount="true">
                    <property name="password">123456</property>
                    <property name="schemas">oldboy,oldguo</property>
                    <property name="defaultSchema">oldboy</property>
                    <!--No MyCAT Database selected 错误前会尝试使用该schema作为schema,不设置则为null,报错 -->
    
                    <!-- 表级 DML 权限设置 -->
                    <!--            
                    <privileges check="false">
                            <schema name="TESTDB" dml="0110" >
                                    <table name="tb01" dml="0000"></table>
                                    <table name="tb02" dml="1111"></table>
                            </schema>
                    </privileges>           
                     -->
            </user>
            <user name="user">
                    <property name="password">user</property>
                    <property name="schemas">oldboy</property>
                    <property name="readOnly">true</property>
                    <property name="defaultSchema">oldboy</property>
            </user>

      2. 添加一个逻辑库

    schema.xml 
    <schema name="china" checkSQLschema="false" sqlMaxLimit="100" dataNode="sh1">
    </schema>
    
    server.xml
     <property name="schemas">oldboy,oldguo</property>
  • 相关阅读:
    go语言从零学起(三) -- chat实现的思考
    go语言从零学起(二)--list循环删除元素(转载)
    go语言从零学起(一) -- 文档教程篇
    Spring框架事务支持模型的优势
    Thymeleaf
    社保到底是多交好,还是少交好?
    使用静态工厂方法而不是构造器
    EJB、RMI、XMLRPC、Hessian、Thrift 、Protobuf
    MySQL存储过程
    MySQL常用功能语句分类总结
  • 原文地址:https://www.cnblogs.com/Mercury-linux/p/12468506.html
Copyright © 2011-2022 走看看