Mycat(基于HGDB的水平切分、主从复制、读写分离)

Mycat(基于HGDB的水平切分、主从复制、读写分离)

1.Mycat是什么?

    Mycat是一款基于阿里开源产品Cobar而研发的开源数据库分库分表中间件(基于Java语言开发)。官网所言:Mycat国内最活跃的、性能最好的开源数据库中间件!
    一个彻底开源的,面向企业应用开发的大数据库集群。
    支持事务、ACID、可以替代MySQL的加强版数据库。
    一个可以视为MySQL集群的企业级数据库,用来替代昂贵的Oracle集群。
    一个融合内存缓存技术、NoSQL技术、HDFS大数据的新型SQL Server。
    结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品。
    一个新颖的数据库中间件产品。

2.Mycat关键特性

支持SQL92标准
支持MySQL、Oracle、DB2、SQL Server、PostgreSQL等DB的常见SQL语法
遵守Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理
基于心跳的自动故障切换,支持读写分离,支持MySQL主从,以及galera cluster集群
支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster
基于Nio实现,有效管理线程,解决高并发问题
支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数,支持跨库分页
支持单库内部任意join,支持跨库2表join,甚至基于caltlet的多表join
支持通过全局表,ER关系的分片策略,实现了高效的多表join查询
支持多租户方案
支持分布式事务(弱xa)
支持XA分布式事务(1.6.5)
支持全局序列号,解决分布式下的主键生成问题
分片规则丰富,插件化开发,易于扩展
强大的web,命令行监控
支持前端作为MySQL通用代理,后端JDBC方式支持MySQL、PostgreSQL、Oracle、DB2、SQLServer、MongoDB、巨杉
支持密码加密
支持服务降级
支持IP白名单
支持SQL黑名单、sql注入攻击拦截
支持prepare预编译指令(1.6)
支持非堆内存(Direct Memory)聚合计算(1.6)
支持PostgreSQL的native协议(1.6)
支持mysql和oracle存储过程,out参数、多结果集返回(1.6)
支持zookeeper协调主从切换、zk序列、配置zk化(1.6)
支持库内分表(1.6)
集群基于ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(2.0开发版

3.安装与使用

下载地址

https://github.com/MyCATApache/Mycat-download/tree/master

#Mycat是基于Java开发的,确保安装好了Java环境,可命令行输入:java -version 进行测试。
#Linux下还需配置Mycat的解压目录:vim /etc/profile,配置完成后使用:source /etc/profile
export MYCAT_HOME=/usr/local/mycat
export JAVA_HOME=/usr/local/java/jdk1.8.0_291
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JRE_HOME/lib
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$MYCAT_HOME/bin:$PATH

#安装好了jdk,并且配置了环境变量后进入​​/usr/local/mycat/conf​​​目录下设置jvm
vim wrapper.conf
wrapper.java.command=/usr/local/java/jdk1.8.0_291/bin/java
#运行(Linux)
mycat start #启动
mycat stop #停止
mycat console #前台运行
mycat restart #重启服务
mycat pause #暂停
mycat status #查看启动状态

4.Mycat配置

4.1.目录说明
bin:启动目录
conf:配置文件目录
    server.xml:是Mycat服务器参数调整和用户授权的配置文件
    schema.xml:是逻辑库定义和表以及分片定义的配置文件
    rule.xml:是分片规则的配置文件,分片规则的具体一些参数信息单独存放为文件,也在这个目录下,配置文件修改                    需要重启MyCAT
    log4j.xml:日志存放在logs/log中,每天一个文件,日志的配置是在conf/log4j.xml中,根据自己的需要可以调整                   输出级别为debug,debug级别下,会输出更多的信息,方便排查问题
    autopartition-long.txt,partition-hash-int.txt,sequence_conf.properties,                                sequence_db_conf.properties  分片相关的id分片规则配置文件
lib:jar包目录
logs :日志目录
tmlogs:临时日志目录
4.2.配置文件server.xml
包含了Mycat需要的系统配置信息,用户配置信息以及逻辑库配置信息,源代码中的映射类为:SystemConfig.class
添加如下配置:相当于建立了一个叫做mycat用户,对应密码为123456,该用户管理了mycats这个逻辑库。当然了,也可以为用户添加管理多个逻辑库,以,(英文逗号)分隔开即可
<mycat:server xmlns:mycat="http://io.mycat/">
        <system>
                <property name="defaultSqlParser">druidparser</property>
                <property name="mutiNodeLimitType">1</property>
                <property name="serverPort">8066</property> <!--连接端口,替换连接mysql时的3306端口-->
                <property name="managerPort">9066</property>
        </system>
        <!--用户配置节点-->
        <user name="mycat"> <!-- 连接mycat的用户名-->
                <property name="password">123456</property> <!-- 连接mycat的密码-->
                <property name="schemas">mycats</property> <!-- 逻辑数据库名,这里会和schema.xml中的配置关联,多个用逗号分开 -->
                <property name="readOnly">false</property>
        </user>
</mycat:server>

4.3.配置文件schema.xml
可以说是最重要的配置文件,管理着 MyCat 的逻辑库、表、分片规则、DataNode 以及 DataSource
schema是实际逻辑库的配置,多个schema代表多个逻辑库
dataNode是逻辑库对应的分片,如果配置多个分片则需要添加多个dataNode即可
dataHost是实际的物理库配置,可以根据业务需要配置多主、主从等其他配置,多个dataHost代表分片对应的物理库地址,下面的writeHost、readHost代表该分片是否配置多写,主从,读写分离等高级特性
#添加如下配置:水平切分,数据按Id取模均匀划分到两个数据库中
<mycat:schema xmlns:mycat="http://io.mycat/">
        <!-- 逻辑数据库名:mycatDatbase,与server.xml中对应;student 是物理数据库中的表,这里在两个库都有这个表 ; dataNode 是自己定义的,区别两个数据库-->
        <schema name="mycats" checkSQLschema="false" sqlMaxLimit="100">
                <table name="student" primaryKey="id" dataNode="masterNode1,masterNode2" rule="ruleById"/>
        </schema>
        <!-- 设置dataNode 对应的数据库,name 和schema中对应 ,dataHost:自己定义的host配置 ,database是物理数据库,master1和master2是两个物理数据库 -->
        <dataNode name="masterNode1" dataHost="masterHost1" database="master1" />
        <dataNode name="masterNode2" dataHost="masterHost2" database="master2" />
        <!-- mycat 逻辑主机dataHost对应的物理主机.其中也设置对应的mysql登陆信息 balance 为1 表示读写分离-->
        <dataHost name="masterHost1" maxCon="100" minCon="10" balance="3" writeType="0" dbType="postgresql" dbDriver="jdbc">
            <heartbeat>select 1</heartbeat>
            <writeHost host="hostM1" url="jdbc:highgo://192.168.100.10:5866/master1" user="sysdba" password="Qwer@1234">
                <readHost host="hostS1" url="jdbc:highgo://192.168.100.11:5866/master1" user="sysdba" password="Qwer@1234"/>
            </writeHost>
        </dataHost>

        <dataHost name="masterHost2" maxCon="100" minCon="10" balance="3" writeType="0" dbType="postgresql" dbDriver="jdbc">
            <heartbeat>select 1</heartbeat>
            <writeHost host="hostM2" url="jdbc:highgo://192.168.100.10:5866/master2" user="sysdba" password="Qwer@1234">
                <readHost host="hostS2" url="jdbc:highgo://192.168.100.11:5866/master2" user="sysdba" password="Qwer@1234"/>
            </writeHost>
        </dataHost>
</mycat:schema>
4.4.配置文件rule.xml
    定义了表拆分所涉及到的规则定义。根据业务可以灵活的对表使用不同的分片算法(目前已实现十余种不同的分片规则,对应所在源码包为:io.mycat.route.function),或者对表使用相同的算法但具体的参数不同。
#添加如下配置:水平切分,数据按Id取模均匀划分到两个数据库中
<mycat:rule xmlns:mycat="http://io.mycat/">
        <tableRule name="ruleById">
                <rule>
                        <columns>id</columns>
                        <algorithm>mod-long</algorithm>
                </rule>
        </tableRule>
        <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
                <!-- 说明我们前边用多少个mode,数量要一致,不然会报错-->
                <property name="count">2</property>
        </function>
</mycat:rule>

5.Springboot项目通过Mycat连接HGDB

5.1.准备环境
1.瀚高数据库4.5.8搭建主从流复制集群,参考流复制搭建手册。
2.主节点创建数据库master1和master2,分别创建表student
CREATE TABLE public.student(
    id integer NOT NULL,
    name character varying(200),
    age integer,
    address character varying(200),
    PRIMARY KEY (id)
);
3.放入驱动HgdbJdbc-6.2.3.jar,路径为/usr/local/mycat/lib
5.2.配置application.properties
#注意了,这里都是用连mysql的方式去配置,Mycat会在后端做好对其它数据库的连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=mycat
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://192.168.100.5:8066/mycats
5.3.添加实体Student.java
public class Student implements Serializable{
    private int id;
    private String name;
    private int age;
    private String address;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Student(int id, String name, int age, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public Student() {
    }
    public String toString(){
        return "[id:"+this.id+",age:"+this.age+",name:"+this.name+",address:"+this.address+"]";
    }

}
5.4.添加StundentMapper.java
public interface StudentMapper {

    int  getCount();

    List<Student> getStuList();

    int insert(Student student);

    List<Student> getStuByAge(int age);

}

5.5.添加StudentService.java

@Service
public class StudentService implements StudentMapper {
    @Autowired
    private StudentMapper studentMapper;
    @Override
    public int getCount() {
        return studentMapper.getCount();
    }

    @Override
    public List<Student> getStuList() {
        return studentMapper.getStuList();
    }

    @Override
    public int insert(Student student) {
        return studentMapper.insert(student);
    }

    @Override
    public List<Student> getStuByAge(int age) {
        return studentMapper.getStuByAge(age);
    }

}
5.6.添加StudentController.java
@Api(value="StudentController",description = "学生信息相关接口,读写分离了")
@Controller
@RequestMapping("/stu")
public class StudentController {
    private static final Logger log = LoggerFactory.getLogger(StudentController.class);
    @Autowired
    private StudentService studentService;

    @RequestMapping(value = "/getCount",method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation("查询所有学生数量")
    public String getStuCount(){
        System.out.print("==========");
        int count = studentService.getCount();
        String str = "总计数量:"+count;
        return str;
    }
    @RequestMapping(value = "/getAllStudent",method = {RequestMethod.GET})
    @ResponseBody
    @ApiOperation("得到所有学生信息列表")
    public List<Student> getAllStudent(){
        log.info("======== getAllStudent start ==============");
        List<Student> studentList = studentService.getStuList();
        log.info("=============== studentList message ==============");
        log.info("studentList: "+studentList);
        log.info("======== getAllStudent end ==============");
        return studentList;
    }
    @RequestMapping(value = "/getStuByAge/{age}",method = {RequestMethod.GET})
    @ResponseBody
    @ApiOperation(value="查询年龄小于age的学生信息",notes = "查询年龄大于age的学生信息 ")
    public List<Student> getStuByAge(@PathVariable(value="age") Integer age){
        log.info("======== getStuByAge start ==============");
        log.info("=======================age:>"+age);
        List<Student> studentList = studentService.getStuByAge(age);
        return studentList;
    }
    @ApiOperation(value = "新增学生信息",notes = "")
    @RequestMapping(value = "/insertStu",method = RequestMethod.GET)
    @ResponseBody
    public String insertStu(){
        for (int i = 1; i <= 50; i++) {
            Student student = new Student();
            student.setId(i);
            student.setName("lisi"+i);
            student.setAge(18);
            student.setAddress("山东");
            studentService.insert(student);
        }
        System.out.println("=============insert success==================");
        return "success";
    }
}
5.7.启动项目
http://localhost:8080/stu/insertStu #测试插入
#查看master1和master2,数据按id取模的方式划分到了两个数据库中,同时从库同步了主库的数据
master1=# select * from student;
 id |  name  | age | address 
----+--------+-----+---------
  2 | lisi2  |  18 | 山东
  4 | lisi4  |  18 | 山东
  6 | lisi6  |  18 | 山东
  8 | lisi8  |  18 | 山东
 10 | lisi10 |  18 | 山东
 12 | lisi12 |  18 | 山东
 14 | lisi14 |  18 | 山东
 16 | lisi16 |  18 | 山东
 18 | lisi18 |  18 | 山东
 20 | lisi20 |  18 | 山东
 22 | lisi22 |  18 | 山东
 24 | lisi24 |  18 | 山东
 26 | lisi26 |  18 | 山东
 28 | lisi28 |  18 | 山东
 30 | lisi30 |  18 | 山东
 32 | lisi32 |  18 | 山东
 34 | lisi34 |  18 | 山东
 36 | lisi36 |  18 | 山东
 38 | lisi38 |  18 | 山东
 40 | lisi40 |  18 | 山东
 42 | lisi42 |  18 | 山东
 44 | lisi44 |  18 | 山东
 46 | lisi46 |  18 | 山东
 48 | lisi48 |  18 | 山东
 50 | lisi50 |  18 | 山东
(25 rows)
master2=# select * from student;
 id |  name  | age | address 
----+--------+-----+---------
  1 | lisi1  |  18 | 山东
  3 | lisi3  |  18 | 山东
  5 | lisi5  |  18 | 山东
  7 | lisi7  |  18 | 山东
  9 | lisi9  |  18 | 山东
 11 | lisi11 |  18 | 山东
 13 | lisi13 |  18 | 山东
 15 | lisi15 |  18 | 山东
 17 | lisi17 |  18 | 山东
 19 | lisi19 |  18 | 山东
 21 | lisi21 |  18 | 山东
 23 | lisi23 |  18 | 山东
 25 | lisi25 |  18 | 山东
 27 | lisi27 |  18 | 山东
 29 | lisi29 |  18 | 山东
 31 | lisi31 |  18 | 山东
 33 | lisi33 |  18 | 山东
 35 | lisi35 |  18 | 山东
 37 | lisi37 |  18 | 山东
 39 | lisi39 |  18 | 山东
 41 | lisi41 |  18 | 山东
 43 | lisi43 |  18 | 山东
 45 | lisi45 |  18 | 山东
 47 | lisi47 |  18 | 山东
 49 | lisi49 |  18 | 山东
(25 rows)
http://localhost:8080/stu/getAllStudent #测试查询
[{"id":1,"name":"lisi1","age":18,"address":"山东"},{"id":3,"name":"lisi3","age":18,"address":"山东"},{"id":5,"name":"lisi5","age":18,"address":"山东"},{"id":7,"name":"lisi7","age":18,"address":"山东"},{"id":9,"name":"lisi9","age":18,"address":"山东"},{"id":11,"name":"lisi11","age":18,"address":"山东"},{"id":13,"name":"lisi13","age":18,"address":"山东"},{"id":15,"name":"lisi15","age":18,"address":"山东"},{"id":17,"name":"lisi17","age":18,"address":"山东"},{"id":19,"name":"lisi19","age":18,"address":"山东"},{"id":21,"name":"lisi21","age":18,"address":"山东"},{"id":23,"name":"lisi23","age":18,"address":"山东"},{"id":2,"name":"lisi2","age":18,"address":"山东"},{"id":4,"name":"lisi4","age":18,"address":"山东"},{"id":6,"name":"lisi6","age":18,"address":"山东"},{"id":8,"name":"lisi8","age":18,"address":"山东"},{"id":10,"name":"lisi10","age":18,"address":"山东"},{"id":12,"name":"lisi12","age":18,"address":"山东"},{"id":14,"name":"lisi14","age":18,"address":"山东"},{"id":16,"name":"lisi16","age":18,"address":"山东"},{"id":18,"name":"lisi18","age":18,"address":"山东"},{"id":20,"name":"lisi20","age":18,"address":"山东"},{"id":22,"name":"lisi22","age":18,"address":"山东"},{"id":24,"name":"lisi24","age":18,"address":"山东"},{"id":26,"name":"lisi26","age":18,"address":"山东"},{"id":28,"name":"lisi28","age":18,"address":"山东"},{"id":30,"name":"lisi30","age":18,"address":"山东"},{"id":32,"name":"lisi32","age":18,"address":"山东"},{"id":34,"name":"lisi34","age":18,"address":"山东"},{"id":36,"name":"lisi36","age":18,"address":"山东"},{"id":38,"name":"lisi38","age":18,"address":"山东"},{"id":40,"name":"lisi40","age":18,"address":"山东"},{"id":42,"name":"lisi42","age":18,"address":"山东"},{"id":44,"name":"lisi44","age":18,"address":"山东"},{"id":46,"name":"lisi46","age":18,"address":"山东"},{"id":48,"name":"lisi48","age":18,"address":"山东"},{"id":50,"name":"lisi50","age":18,"address":"山东"},{"id":25,"name":"lisi25","age":18,"address":"山东"},{"id":27,"name":"lisi27","age":18,"address":"山东"},{"id":29,"name":"lisi29","age":18,"address":"山东"},{"id":31,"name":"lisi31","age":18,"address":"山东"},{"id":33,"name":"lisi33","age":18,"address":"山东"},{"id":35,"name":"lisi35","age":18,"address":"山东"},{"id":37,"name":"lisi37","age":18,"address":"山东"},{"id":39,"name":"lisi39","age":18,"address":"山东"},{"id":41,"name":"lisi41","age":18,"address":"山东"},{"id":43,"name":"lisi43","age":18,"address":"山东"},{"id":45,"name":"lisi45","age":18,"address":"山东"},{"id":47,"name":"lisi47","age":18,"address":"山东"},{"id":49,"name":"lisi49","age":18,"address":"山东"}]
#读操作都走了从库
#从库日志
2023-03-09 04:49:04.072 EST,"sysdba","master1",1504,"192.168.100.5:44528",6409ab54.5e0,8,"SELECT",2023-03-09 04:48:04 EST,2/10,0,LOG,00000,"execute <unnamed>: SELECT *
FROM student
LIMIT 100",,,,,,,,,"PostgreSQL JDBC Driver"
2023-03-09 04:49:04.072 EST,"sysdba","master2",1502,"192.168.100.5:44524",6409ab54.5de,10,"SELECT",2023-03-09 04:48:04 EST,6/12,0,LOG,00000,"execute <unnamed>: SELECT *
FROM student
LIMIT 100",,,,,,,,,"PostgreSQL JDBC Driver"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值