zoukankan      html  css  js  c++  java
  • MySQL for OPS 10:MyCAT 分布式架构

    写在前面的话

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

    MyCAT 环境基础架构准备

    架构图 1:

    架构图 2:

     

    【1】搭建基础环境:

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

    # 创建基础目录
    mkdir -p /data/{data,logs,backup,conf}/mysql-33{07,08,09,10}
    mkdir -p /data/logs/mysql-33{07,08,09,10}/{bin-log,slow-log,error-log,relay-log}
    mkdir -p /data/packages/mysql
    mkdir -p /data/services
    
    # 添加用户
    useradd -s /sbin/nologin mysql
    
    # 修改目录权限
    chown -R mysql.mysql /data/logs/mysql-33*
    chown -R mysql.mysql /data/data/mysql-33*
    
    # 清理默认配置文件
    mv /etc/my.cnf /etc/my.cnf_bak
    
    # 解压包
    cd /data/packages/mysql/
    tar -zxf mysql-5.7.25-linux-glibc2.12-x86_64.tar.gz -C /data/services/
    cd /data/services/
    mv mysql-5.7.25-linux-glibc2.12-x86_64/ mysql
    
    # 配置环境变量并查看
    echo 'export PATH=$PATH:/data/services/mysql/bin' >> /etc/profile
    source /etc/profile
    mysql -V

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

    # 初始化数据
    mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3307
    mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3308
    mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3309
    mysqld --initialize-insecure --user=mysql --basedir=/data/services/mysql --datadir=/data/data/mysql-3310

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

    # 3307
    cat >/data/conf/mysql-3307/my.cnf<<EOF
    [mysqld]
    port=3307
    basedir=/data/services/mysql
    datadir=/data/data/mysql-3307
    socket=/data/logs/mysql-3307/mysql.sock
    log-error=/data/logs/mysql-3307/error-log/mysql.log
    log_bin=/data/logs/mysql-3307/bin-log/mysql-bin
    slow_query_log=1
    slow_query_log_file=/data/logs/mysql-3307/slow-log/slow.log
    long_query_time=2
    log_queries_not_using_indexes=1
    relay_log=/data/logs/mysql-3307/relay-log/relay-bin
    binlog_format=row
    skip-name-resolve
    server-id=107
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    
    # 3308
    cat >/data/conf/mysql-3308/my.cnf<<EOF
    [mysqld]
    port=3308
    basedir=/data/services/mysql
    datadir=/data/data/mysql-3308
    socket=/data/logs/mysql-3308/mysql.sock
    log-error=/data/logs/mysql-3308/error-log/mysql.log
    log_bin=/data/logs/mysql-3308/bin-log/mysql-bin
    slow_query_log=1
    slow_query_log_file=/data/logs/mysql-3308/slow-log/slow.log
    long_query_time=2
    log_queries_not_using_indexes=1
    relay_log=/data/logs/mysql-3308/relay-log/relay-bin
    binlog_format=row
    skip-name-resolve
    server-id=108
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    
    # 3309
    cat >/data/conf/mysql-3309/my.cnf<<EOF
    [mysqld]
    port=3309
    basedir=/data/services/mysql
    datadir=/data/data/mysql-3309
    socket=/data/logs/mysql-3309/mysql.sock
    log-error=/data/logs/mysql-3309/error-log/mysql.log
    log_bin=/data/logs/mysql-3309/bin-log/mysql-bin
    slow_query_log=1
    slow_query_log_file=/data/logs/mysql-3309/slow-log/slow.log
    long_query_time=2
    log_queries_not_using_indexes=1
    relay_log=/data/logs/mysql-3309/relay-log/relay-bin
    binlog_format=row
    skip-name-resolve
    server-id=109
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF
    
    # 3310
    cat >/data/conf/mysql-3310/my.cnf<<EOF
    [mysqld]
    port=3310
    basedir=/data/services/mysql
    datadir=/data/data/mysql-3310
    socket=/data/logs/mysql-3310/mysql.sock
    log-error=/data/logs/mysql-3310/error-log/mysql.log
    log_bin=/data/logs/mysql-3310/bin-log/mysql-bin
    slow_query_log=1
    slow_query_log_file=/data/logs/mysql-3310/slow-log/slow.log
    long_query_time=2
    log_queries_not_using_indexes=1
    relay_log=/data/logs/mysql-3310/relay-log/relay-bin
    binlog_format=row
    skip-name-resolve
    server-id=110
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF

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

    # 3307
    cat >/etc/systemd/system/mysqld-3307.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=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3307/my.cnf
    LimitNOFILE=5000
    EOF
    
    # 3308
    cat >/etc/systemd/system/mysqld-3308.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=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3308/my.cnf
    LimitNOFILE=5000
    EOF
    
    # 3309
    cat >/etc/systemd/system/mysqld-3309.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=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3309/my.cnf
    LimitNOFILE=5000
    EOF
    
    # 3310
    cat >/etc/systemd/system/mysqld-3310.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=/data/services/mysql/bin/mysqld --defaults-file=/data/conf/mysql-3310/my.cnf
    LimitNOFILE=5000
    EOF

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

    # 启动 MySQL
    systemctl start mysqld-3307.service 
    systemctl start mysqld-3308.service 
    systemctl start mysqld-3309.service 
    systemctl start mysqld-3310.service 
    
    # 查看 MySQL
    mysql -S /data/logs/mysql-3307/mysql.sock -e "select @@server_id;"
    mysql -S /data/logs/mysql-3308/mysql.sock -e "select @@server_id;"
    mysql -S /data/logs/mysql-3309/mysql.sock -e "select @@server_id;"
    mysql -S /data/logs/mysql-3310/mysql.sock -e "select @@server_id;"
    
    # 添加 root 密码
    mysql -S /data/logs/mysql-3307/mysql.sock -e "alter user root@'localhost' identified by '123';"
    mysql -S /data/logs/mysql-3308/mysql.sock -e "alter user root@'localhost' identified by '123';"
    mysql -S /data/logs/mysql-3309/mysql.sock -e "alter user root@'localhost' identified by '123';"
    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 开头

    # 步骤略

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

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

    mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock -e "grant replication slave on *.* to repl@'192.168.100.%' identified by '123';"
    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:

    登录数据库:

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

    执行 SQL:

    -- 创建同步信息
    CHANGE MASTER TO
      MASTER_HOST='192.168.100.112',
      MASTER_USER='repl',
      MASTER_PASSWORD='123',
      MASTER_PORT=3307,
      MASTER_AUTO_POSITION=1;
    
    -- 启动 slave
    start slave;
    
    -- 查看状态
    show slave statusG

    结果如图:

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

    登录数据库:

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

    执行 SQL:

    -- 创建同步信息
    CHANGE MASTER TO
      MASTER_HOST='192.168.100.111',
      MASTER_USER='repl',
      MASTER_PASSWORD='123',
      MASTER_PORT=3307,
      MASTER_AUTO_POSITION=1;
    
    -- 启动 slave
    start slave;
    
    -- 查看状态
    show slave statusG

    结果如下:

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

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

    1. db01 操作:

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

    执行 SQL:

    -- 创建同步信息
    CHANGE MASTER TO
      MASTER_HOST='192.168.100.111',
      MASTER_USER='repl',
      MASTER_PASSWORD='123',
      MASTER_PORT=3307,
      MASTER_AUTO_POSITION=1;
    
    -- 启动 slave
    start slave;
    
    -- 查看状态
    show slave statusG

    结果如下:

    2. db02 操作:

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

    执行 SQL:

    -- 创建同步信息
    CHANGE MASTER TO
      MASTER_HOST='192.168.100.112',
      MASTER_USER='repl',
      MASTER_PASSWORD='123',
      MASTER_PORT=3307,
      MASTER_AUTO_POSITION=1;
    
    -- 启动 slave
    start slave;
    
    -- 查看状态
    show slave statusG

    结果如下:

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

    【5】检查主从状态:

    mysql -uroot -p123 -S /data/logs/mysql-3307/mysql.sock -e "show slave statusG" | grep "Yes"
    mysql -uroot -p123 -S /data/logs/mysql-3308/mysql.sock -e "show slave statusG" | grep "Yes"
    mysql -uroot -p123 -S /data/logs/mysql-3309/mysql.sock -e "show slave statusG" | grep "Yes"
    mysql -uroot -p123 -S /data/logs/mysql-3310/mysql.sock -e "show slave statusG" | 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 但是不用初始化:

    # 创建必要用户和目录
    useradd -s /sbin/nologin mysql
    mkdir -p /data/{data,logs,backup,packages}/mysql
    mkdir -p /data/services
    chown mysql.mysql /data/logs/mysql/
    chown mysql.mysql /data/data/mysql/
    
    # 安装 MySQL
    cd /data/packages/mysql/
    tar -zxf mysql-5.7.25-linux-glibc2.12-x86_64.tar.gz -C /data/services/
    cd /data/services/
    mv mysql-5.7.25-linux-glibc2.12-x86_64/ mysql
    
    # 配置环境变量
    echo 'export PATH=$PATH:/data/services/mysql/bin' >> /etc/profile
    source /etc/profile
    
    # 查看安装结果
    mysql -V

    2. 安装 JDK:

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

    3. 安装 MyCAT:

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

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

    <user name="root" defaultAccount="true">
        <property name="password">123456</property>
        <property name="schemas">TESTDB</property>
        ....
    </user>

    4. 访问测试:

    登录 MyCAT 数据库:

    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

    <?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="DATANODE01"></schema>  
        <dataNode name="DATANODE01" dataHost="DATAHOST01" database= "taobao" />         
        <dataHost name="DATAHOST01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">    
            <heartbeat>select user()</heartbeat>  
            <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="123"> 
                <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="123" /> 
            </writeHost> 
        </dataHost>  
    </mycat:schema>

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

    2. 重启 MyCAT 测试读写:

    mycat restart

    测试读写:

    mysql -uroot -p123456 -h 127.0.0.1 -P8066

    查看结果:

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

    MyCAT 配置读写分离高可用

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

    <?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="DATANODE01"></schema>
        <dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
        <dataHost name="DATAHOST01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
            <heartbeat>select user()</heartbeat>
            <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="123">
                <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="123" />
            </writeHost>
            <writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="123">
                <readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="123" />
            </writeHost>
        </dataHost>
    </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

    <?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="DATANODE01">
            <table name="t1" dataNode="DATANODE01"/>
            <table name="t2" dataNode="DATANODE02"/>
        </schema>
        <dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
        <dataNode name="DATANODE02" dataHost="DATAHOST02" database="taobao" />
        <!-- node 1 -->
        <dataHost name="DATAHOST01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
            <heartbeat>select user()</heartbeat>
            <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="123">
                <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="123" />
            </writeHost>
            <writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="123">
                <readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="123" />
            </writeHost>
        </dataHost>
        <!-- node 2 --> 
        <dataHost name="DATAHOST02" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
            <heartbeat>select user()</heartbeat>
            <writeHost host="WRITEHOST01" url="192.168.100.111:3308" user="root" password="123">
                <readHost host="READHOST01" url="192.168.100.111:3310" user="root" password="123" />
            </writeHost>
            <writeHost host="WRITEHOST02" url="192.168.100.112:3308" user="root" password="123">
                <readHost host="READHOST02" url="192.168.100.112:3310" user="root" password="123" />
            </writeHost>
        </dataHost>
    </mycat:schema>

    4. 重启测试:

    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 表:

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

    2. 修改 mycat 的配置 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="DATANODE01">
            <table name="t3" dataNode="DATANODE01,DATANODE02" rule="auto-sharding-long" />
        </schema>
        <dataNode name="DATANODE01" dataHost="DATAHOST01" database="taobao" />
        <dataNode name="DATANODE02" dataHost="DATAHOST02" database="taobao" />
        <!-- node 1 -->
        <dataHost name="DATAHOST01" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
            <heartbeat>select user()</heartbeat>
            <writeHost host="WRITEHOST01" url="192.168.100.111:3307" user="root" password="123">
                <readHost host="READHOST01" url="192.168.100.111:3309" user="root" password="123" />
            </writeHost>
            <writeHost host="WRITEHOST02" url="192.168.100.112:3307" user="root" password="123">
                <readHost host="READHOST02" url="192.168.100.112:3309" user="root" password="123" />
            </writeHost>
        </dataHost>
        <!-- node 2 --> 
        <dataHost name="DATAHOST02" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
            <heartbeat>select user()</heartbeat>
            <writeHost host="WRITEHOST01" url="192.168.100.111:3308" user="root" password="123">
                <readHost host="READHOST01" url="192.168.100.111:3310" user="root" password="123" />
            </writeHost>
            <writeHost host="WRITEHOST02" url="192.168.100.112:3308" user="root" password="123">
                <readHost host="READHOST02" url="192.168.100.112:3310" user="root" password="123" />
            </writeHost>
        </dataHost>
    </mycat:schema>

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

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

    <!-- 配置按照哪个字段分 -->
    <tableRule name="auto-sharding-long">
        <rule>
            <columns>id</columns>
            <algorithm>rang-long</algorithm>
        </rule>
    </tableRule>
    
    <!-- 分配规则的文件 -->
    <function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
        <property name="mapFile">autopartition-long.txt</property>
    </function>

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

    0-10=0
    11-20=1

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

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

    mysql -uroot -p123456 -h 127.0.0.1 -P 8066

    执行 SQL:

    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(11,"aa");
    insert into t3(id,name) values(12,"bb");
    insert into t3(id,name) values(13,"cc");

    结果:

    4. 去节点查看:

    3307 节点:

    3308 节点:

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

    MyCAT 水平拆分 - 取模 mod

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

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

    1. 修改 schema.xml:

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

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

    2. 修改 rule.xml

    <!-- 配置按照哪个字段取模 -->
    <tableRule name="mod-long">
        <rule>
            <columns>id</columns>
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>
    
    <!-- 分配节点数 -->
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- how many data nodes -->
        <property name="count">2</property>
    </function>

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

    3. 重启 MyCAT 测试:

    连接:

    mysql -uroot -p123456 -h 127.0.0.1 -P 8066

    执行 SQL:

    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,"x");
    insert into t4(id,name) values(5,"d");
    insert into t4(id,name) values(6,"e");
    insert into t4(id,name) values(7,"f");
    insert into t4(id,name) values(8,"g");
    insert into t4(id,name) values(11,"g");
    insert into t4(id,name) values(13,"g");

    结果:

    4. 去单独的节点查看:

    3307 节点:

    3308 节点:

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

    MyCAT 水平拆分 - 枚举

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

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

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

    2. 修改 schema.xml:

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

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

    3. 修改 rule.xml 配置:

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

    4. 配置 partition-hash-int.txt

    北京=0
    深圳=1

    5. 重启 MyCAT 查看:

    mysql -uroot -p123456 -h 127.0.0.1 -P 8066

    执行 SQL:

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

    结果:

    6. 去节点查看:

    3307 节点:

    3308 节点:

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

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

    全局表和 E-R 分片

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

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

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

    这就是全局表。

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

    A join B
    on a.xx=b.yy
    join C
    on A.id=C.id

    可以增加配置:

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

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

    小结

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

  • 相关阅读:
    为何总是在无聊的事中浪费生命
    Objective-C Polymorphism
    [MONGODB]: WHEN ARBITER REQUIRED FOR REPLICA SET
    巴菲特已四度战胜股灾 称A股长期仍将向上(2015年09月14日)
    visual studio 2012 has stopped working
    [2015-04-17] 2015年的股市比2008年还危险……
    Using HiveServer2
    有了Hadoop MapReduce, 为什么还要Spark?
    HIVE: Map Join Vs Common Join, and SMB
    ORA-12170:TNS:连接超时
  • 原文地址:https://www.cnblogs.com/Dy1an/p/11571605.html
Copyright © 2011-2022 走看看