MyCat - 使用篇(3)

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

全局序列号

数据切分后,原有的关系数据库中的主键约束在分布式条件下将无法使用,因此需要引入外部机制保证数据唯一性标识,这种保证全局性的数据唯一标识的机制就是全局序列号(sequence)。

1. 本地文件方式

classpath下有一个sequence_conf.properties文件:

    GLOBAL_SEQ.HISIDS=
    GLOBAL_SEQ.MINID=1001
    GLOBAL_SEQ.MAXID=1000000000
    GLOBAL_SEQ.CURID=1000

HISIDS表示历史使用过的值,MINID为ID最小值,MAXID为ID最大值,CURID为当前值。
需要在server.xml加入如下配置:

    <system><property name="sequnceHandlerType">0</property></system>

sequnceHandlerType 需要配置为 0,表示使用本地文件配置。
使用示例:

    insert into table1(id,name) values(next value for MYCATSEQ_GLOBAL,‘test’);

但是这么做,MyCat就不是无状态中间件,很难去做MyCat集群。而且,这样的id只是纯数字。最后,每次MyCat重新发布,id恢复初始值。所以,不推荐这种用法。

2.数据库方式

在数据库中建立一张表,存放 sequence 名称(name),sequence 当前值(current_value),步长(increment)每次读取多少个 sequence,假设为 K)等信息;
server.xml:

    <system><property name="sequnceHandlerType">1</property></system>

建表语句:

    DROP TABLE IF EXISTS MYCAT_SEQUENCE;
    CREATE TABLE MYCAT_SEQUENCE (name VARCHAR(50) NOT NULL,current_value INT NOT NULL,increment INT NOT NULL DEFAULT 100, PRIMARY KEY(name)) ENGINE=InnoDB;
    INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES (‘GLOBAL’, 100000, 100);

创建相关function:

    DROP FUNCTION IF EXISTS mycat_seq_currval;
    DELIMITER
    CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf-8
    DETERMINISTIC
    BEGIN
    DECLARE retval VARCHAR(64);
    SET retval=“-999999999,null”;
    SELECT concat(CAST(current_value AS CHAR),“,”,CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;
    RETURN retval;
    END
    DELIMITER;
    – 讴置 sequence 值
    DROP FUNCTION IF EXISTS mycat_seq_setval;
    DELIMITER
    CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS varchar(64) CHARSET utf-8
    DETERMINISTIC
    BEGIN
    UPDATE MYCAT_SEQUENCE
    SET current_value = value
    WHERE name = seq_name;
    RETURN mycat_seq_currval(seq_name);
    END
    DELIMITER;
    – 获叏下一个 sequence 值
    DROP FUNCTION IF EXISTS mycat_seq_nextval;
    DELIMITER
    CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf-8
    DETERMINISTIC
    BEGIN
    UPDATE MYCAT_SEQUENCE
    SET current_value = current_value + increment WHERE name = seq_name;
    RETURN mycat_seq_currval(seq_name);
    END
    DELIMITER;

sequence_db_conf.properties指定 sequence 相关配置在哪个节点上

    USER_SEQ=test_dn1

使用示例:

    insert into table1(id,name) values(next value for MYCATSEQ_GLOBAL,‘test’);

这样做虽然MyCat为无状态而且id有持久化,并且一次可以取出多个id,通过配置可以有主从切换。但是,id还是纯数字,没有有意义的信息,而且,MyCat主从切换并不可靠,id生成有故障,则整个服务都无法正常进行,这在架构上有单点问题,是不推荐的。

3.本地时间戳方式

ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加)
server.xml:

    <system><property name="sequnceHandlerType">2</property></system>

sequence_time_conf.properties:

    WORKID=0-31 任意整数
    DATAACENTERID=0-31 任意整数

4.通过继承或者重构相关类实现

修改源代码,主要是和MyCATSequnceProcessor相关的类,定制自己的id。之后源代码篇会讲

但是全局序列号还是推荐用独立的id生成器服务(独立于MyCat的服务)去实现最佳!

安装准备

环境

Red Hat Enterprise Linux Server release 6.6 (Santiago)
java version “1.8.0_79”

软件

配置并部署zookeeper

只要部署好即可,默认配置,将conf/zoo_sample.cfg 重命名为conf/zoo.cfg。启动后验证下即可(因为目前只为了为监控服务)

配置MyCat

下载MyCat的源代码,并使用maven打包安装:mvn install -Dmaven.test.skip=true. 使用生成的linux下的tar.gz文件,解压。

1. 业务分析

接下来是我们的重点,MyCat的配置,还是拿之前的例子,我们只需要一个逻辑库(schema1),运单库则需要分成3片,客户库需要分成2片,统一由MyCat管理。业务上,客户和快递员查询和自己相关的运单比客户和快递员还有仓管员通过运单号查询相关信息的业务量少的,所以以运单为中心进行分片。


运单表根据运单号哈希取模分片;
运单子母件表作为运单表的子表;
快递员运单关系表作为运单表的子表;
客户运单关系表作为运单表的子表;
快递员信息变动不频繁,而且量不大,但是业务上基本没有需要和快递员join的场景,作为非分片表;
客户表根据客户id做哈希取模;
运单状态信息表,运单状态信息表记录状态的解释信息,做为公共表。

运单根据量放在3个分片节点上,客户根据量也放在两个分片节点上。(这里假设都撑得住未来10年的量,主要要考虑存储量级和tps/qps两个维度,采用涉及到哈希取模的分片规则,最好一开始就估计足量,避免未来的扩容麻烦)

综上,如下分片:

2. 配置conf/server.xml

server.xml几乎保存了所有mycat需要的系统配置信息。其在代码内直接的映射类为SystemConfig类。
参考完整配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mycat:server SYSTEM "server.dtd">
    <mycat:server xmlns:mycat="http://org.opencloudb/">
        <system>
            <property name="defaultSqlParser">druidparser</property>
            <!--  <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
            <!-- <property name="processorBufferChunk">40960</property> -->
            <!--
            <property name="processors">1</property>
            <property name="processorExecutor">32</property>
             -->
            <!--默认是65535 64K 用于sql解析时最大文本长度 -->
            <!--<property name="maxStringLiteralLength">65535</property>-->
            <!--<property name="sequnceHandlerType">0</property>-->
            <!-- 表示使用数据库方式生成sequence. -->
            <property name="sequnceHandlerType">1</property>
            <!--<property name="backSocketNoDelay">1</property>-->
            <!--<property name="frontSocketNoDelay">1</property>-->
            <!--<property name="processorExecutor">16</property>-->
            <!--
                <property name="mutiNodeLimitType">1</property> 0:开启小数量级(默认) ;1:开启亿级数据排序
                <property name="mutiNodePatchSize">100</property> 亿级数量排序批量
                <property name="processors">32</property> <property name="processorExecutor">32</property>
                <property name="serverPort">8066</property> <property name="managerPort">9066</property>
                <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
                <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
            <property name="serverPort">8066</property> <property name="managerPort">9066</property>
        </system>
        <user name="root">
            <!--从1.4.1开始,MyCat支持密文保存密码,这里明文密码为root -->
            <property name="usingDecrypt">1</property>
            <property name="password">CrjpLhvVJkHk0EPW35Y07dUeTimf52zMqClYQkIAN3/dqiG1DVUe9Zr4JLh8Kl+1KH1zd7YTKu5w04QgdyQeDw==</property>
            <property name="schemas">schema1</property>
        </user>
    <user name="test">
            <!--这里明文密码为test-->
            <property name="usingDecrypt">1</property>
            <property name="password">nYx8wxkKtgdPtMXIpapwbNadIWFzpse48NcO+42D1yS//1cNxxQquw07eV/7gvVpxzbjNv47t6QpChvVszKy9g==</property>
            <property name="readOnly">true</property>
            <property name="schemas">schema1</property>
        </user>
    </mycat:server>

2.1 生成密文密码

查看密文密码工具类org.opencloudb.util.DecryptUtil,可以发现main方法中接收的参数为如下格式:
0:test:test 分别对应的是

  • 加密方式:0 前端加密, 1 后端加密(后端是指后台具体数据库连接)
  • server.xml 文件中定义的用户名
  • 明文密码

这里我们是配置前端,用户名为test,密码为test。
(前端和后端用的密码盐不一样,盐中还有用户名的成分)
传入这个参数运行主类,在控制命令行得到密文密码。
nYx8wxkKtgdPtMXIpapwbNadIWFzpse48NcO+42D1yS//1cNxxQquw07eV/7gvVpxzbjNv47t6QpChvVszKy9g==

2.2 配置用户和逻辑库与权限
    <user name="root">
            <!--从1.4.1开始,MyCat支持密文保存密码,这里明文密码为root -->
            <property name="usingDecrypt">1</property>
            <property name="password">CrjpLhvVJkHk0EPW35Y07dUeTimf52zMqClYQkIAN3/dqiG1DVUe9Zr4JLh8Kl+1KH1zd7YTKu5w04QgdyQeDw==</property>
            <!--规定可以访问的逻辑库,可以配置多个,用,分割-->
            <property name="schemas">schema1</property>
        </user>
    <user name="test">
            <!--这里明文密码为test-->
            <property name="usingDecrypt">1</property>
            <property name="password">nYx8wxkKtgdPtMXIpapwbNadIWFzpse48NcO+42D1yS//1cNxxQquw07eV/7gvVpxzbjNv47t6QpChvVszKy9g==</property>
            <!--对于数据库只读访问-->
            <property name="readOnly">true</property>
            <property name="schemas">schema1</property>
        </user>

上面的注释已经很清楚,在1.5版本,用户权限更全面,并且还有ip白名单和sql黑名单的功能。

2.3 配置系统参数
    <system>
            <!--默认sql解析器,之后我们会仔细分析,这里设置为淘宝开源的druidparser最为高效-->
            <property name="defaultSqlParser">druidparser</property>
            <!--是否开启mysql压缩协议,客户端、mycat、mysql三者都启用才行,参考下面1-->
            <!--  <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
            <!-- <property name="processorBufferChunk">40960</property> -->
            <!--
            <property name="processors">1</property>
            <property name="processorExecutor">32</property>
             -->
            <!--默认是65535 64K 用于sql解析时最大文本长度 -->
            <!--<property name="maxStringLiteralLength">65535</property>-->
            <!--<property name="sequnceHandlerType">0</property>-->
            <!-- 指定使用Mycat全局序列的类型。0为本地文件方式,1为数据库方式。默认是使用本地文件方式,文件方式主要只是用于测试使
    用。根据之前的讨论,最好还是用id生成器-->
            <!--<property name="sequnceHandlerType">1</property>-->
            <!--<property name="backSocketNoDelay">1</property>-->
            <!--<property name="frontSocketNoDelay">1</property>-->
            <!--<property name="processorExecutor">16</property>-->
            <!--
                <property name="mutiNodeLimitType">1</property> 0:开启小数量级(默认) ;1:开启亿级数据排序
                <property name="mutiNodePatchSize">100</property> 亿级数量排序批量
                <property name="processors">32</property> <property name="processorExecutor">32</property>
                <property name="serverPort">8066</property> <property name="managerPort">9066</property>
                <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
                <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
            <property name="serverPort">8066</property> <property name="managerPort">9066</property>
        </system>

以下2、3、4的属性不理解不用着急,之后的源代码篇会讲述得更清楚,这里可以都不配置。

  1. Mycat可以在server.xml中配置1启用。
    客户端如果是mysql命令行,则加参数-C启用压缩协议。
    客户端如果是jdbc则在jdbc的url上加上参数useCompression=true,例如:jdbc:mysql://127.0.0.1:8066
    /base?useCompression=true
    一般网路条件越差,性能提升越明显。

  2. processors:这个属性主要用于指定系统可用的线程数,默认值为Runtime.getRuntime().availableProcessors()方法返回的值。主要影响processorBufferPool、processorBufferLocalPercent、processorExecutor属性。NIOProcessor的个数也是由这个属性定义的,所以调优的时候可以适当的调高这个属性。

  3. 由于每次执行NIO读、写操作都需要使用到buffer,系统初始化的时候会建立一定长度的buffer池来加快读、写的效率,减少建立buffer的时间。Mycat中有两个主要的buffer池:BufferPool和ThreadLocalPool
    BufferPool由ThreadLocalPool组合而成,每次从BufferPool中获取buffer都会优先获取ThreadLocalPool中的buffer,未命中之
    后才会去获取BufferPool中的buffer。也就是说ThreadLocalPool是作为BufferPool的二级缓存,每个线程内部自己使用的。当
    然,这其中还有一些限制条件需要线程的名字是由$_开头。然而,BufferPool上的buffer则是每个NIOProcessor都共享的。
    默认这个属性的值为: 默认bufferChunkSize(4096) * processors属性 * 1000
    BufferPool的总长度 = bufferPool / bufferChunk。
    若bufferPool不是bufferChunk的整数倍,则总长度为前面计算得出的商 + 1
    假设系统线程数为4,其他都为属性的默认值,则:
    bufferPool = 4096 * 4 * 1000
    BufferPool的总长度 : 4000 = 16384000 / 4096

  4. processorExecutor属性
    这个属性主要用于指定NIOProcessor上共享的businessExecutor固定线程池大小。mycat在需要处理一些异步逻辑的时候会把任务提交到这个线程池中。新版本中这个连接池的使用频率不是很大了,可以设置一个较小的值。

  5. TCP相关参数,前端后端分别为:
    frontSocketSoRcvbuf 默认值: 1024 * 1024
    frontSocketSoSndbuf 默认值: 4 * 1024 * 1024
    frontSocketNoDelay 默认值: 1
    backSocketSoRcvbuf 默认值: 4 * 1024 * 1024
    backSocketSoSndbuf 默认值: 1024 * 1024
    backSocketNoDelay 默认值: 1

  6. MySql连接相关属性:
    packetHeaderSize : 指定Mysql协议中的报文头长度。默认4。
    maxPacketSize : 指定Mysql协议可以携带的数据最大长度。默认16M。
    idleTimeout : 指定连接的空闲超时时间。某连接在发起空闲检查下,发现距离上次使用超过了空闲时间,那么这个连接会被回收,就是被直接的关闭掉。默认30分钟。
    charset : 连接的初始化字符集。默认为utf8。
    txIsolation : 前端连接的初始化事务隔离级别,只在初始化的时候使用,后续会根据客户端传递过来的属性对后端数据库连接进行同步。默认为REPEATED_READ。
    **sqlExecuteTimeout:**SQL执行超时的时间,Mycat会检查连接上最后一次执行SQL的时间,若超过这个时间则会直接关闭这连接。默认时间为300秒

  7. 定时任务:
    processorCheckPeriod : 清理NIOProcessor上前后端空闲、超时和关闭连接的间隔时间。默认是1秒。
    dataNodeIdleCheckPeriod : 对后端连接进行空闲、超时检查的时间间隔,默认是60秒。
    dataNodeHeartbeatPeriod : 对后端所有读、写库发起心跳的间隔时间,默认是10秒

  8. 服务相关属性:
    bindIp : mycat服务监听的IP地址,默认值为0.0.0.0。
    serverPort : 定义mycat的使用端口,默认值为8066。就是客户端接入端口(应用接入,mysql客户端接入端口),MyCat的主要服务都是通过这个端口发出。
    managerPort : 定义mycat的管理端口,默认值为9066。有很多监控命令

它是一个开源的分布式数据库系统,是一个实现了 MySQL 协议的的 Server,前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和命令行访问,而其后端可以用 MySQL 原生(Native)协议与多个 MySQL 服务器通信,也可以用 JDBC 协议与大多数主流数据库服务器通信, 其核心功能是分表分库,即将一个大表水平分割为 N 个小表,存储在后端 MySQL 服务器里或者其他数据库里。 Mycat 发展到目前的版本,已经不是一个单纯的 MySQL 代理了,它的后端可以支持 MySQL、SQL Server、 Oracle、DB2、PostgreSQL 等主流数据库,也支持 MongoDB 这种新型 NoSQL 方式的存储,未来还会支持更 多类型的存储。而在最终用户看来,无论是那种存储方式,在 Mycat 里,都是一个传统的数据库表,支持标准的 SQL 语句进行数据的操作,这样一来,对前端业务系统来说,可以大幅降低开发难度,提升开发速度,在测试阶 段,可以将一个表定义为任何一种 Mycat 支持的存储方式,比如 MySQL 的 MyASIM 表、内存表、或者 MongoDB、LevelDB 以及号称是世界上最快的内存数据库 MemSQL 上。试想一下,用户表存放在 MemSQL 上, 32 大量读频率远超过写频率的数据如订单的快照数据存放于 InnoDB 中,一些日志数据存放于 MongoDB 中,而且 还能把 Oracle 的表跟 MySQL 的表做关联查询,你是否有一种不能呼吸的感觉?而未来,还能通过 Mycat 自动 将一些计算分析后的数据灌入到 Hadoop 中,并能用 Mycat+Storm/Spark Stream 引擎做大规模数据分析,看 到这里,你大概明白了,Mycat 是什么?Mycat 就是 BigSQL,Big Data On SQL Database。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值