当前位置: 首页 > news >正文

springboot整合mycat实现读写分离

Mycat工作原理

  • 拦截用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:
    • 如分片分析、路由分析、读写分离分析、缓存分析等
    • 然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。
  • 步骤
    • mycat启动时,就生成了管理连接后端真实数据库的所有datasource
    • 客户端系统只能连接mycat发送sql语句
    • mycat接收到sql语句,执行各种计算,计算分片sql语句对应数据在哪个分片,计算读写分离,从这个分片主从结构中到哪个节点读/写,拿到了具体的数据源,获取连接发送sql语句
    • 数据库拿到mycat执行的sql开始执行
    • mycat将数据库返回结果返回给客户端.

Mycat特点

  • 读写分离:

    • 读写分离是建立在主从结构之上,让主节点去承载写操作,从节点承载读操作,这样做的目的就是可以分担主节点的压力,提升主从结构的整体效率。
  • 垂直拆分

    • 简单来说就是mycat中的表(不同的表)可以来自于多个不同的服务器。
  • 水平拆分

    • mycat中的表(一张表)来自于不同的服务器。

Mycat+Mysql节点关系说明

  • 三台服务器防火墙先关闭
    • systemctl stop firewalld.service
    • systemctl status firewalld.service
  • 三台服务器都需要安装mysql
mysql-master(192.168.174.136)
mysql-slave(192.168.174.137)
mycat(192.168.174.138)

Mysql安装

  • mysql 安装请在此文mysql5.7安装中搜索(mysql对应部分)

  • 安装完成后添加hui数据库,用于主从和mycat
    在这里插入图片描述

Mysql配置主从

  • whereis my.cnf 查找mysql 配置文件目录
    在这里插入图片描述
  • mater节点添加以下内容
server-id=1 # 定义服务器唯一ID
log-bin=mysql-bin # 启用二进制日志
binlog-do-db=hui # 设置需要主从复制的库
binlog_format=ROW # binlog记录内容的方式,记录被操作的每一行
  • slave节点添加以下内容
server-id=2 #从服务器唯一ID
log-bin=mysql-bin # 启用二进制日志
replicate-do-db=hui # 设置需要同步的数据库
binlog_format = ROW # binlog记录内容的方式,记录被操作的每一行
  • master节点登陆 建立一个从库复制的授权用户
create user 'slave1'@'192.168.174.137' identified by '123456'; # 创建用户
grant replication slave on *.* to 'slave1'@'192.168.174.137'; # 授权,这里为了方便,授予全部权限
flush privileges; # 刷新权限
  • service mysqld restart 重启master节点mysql服务
  • 登陆mysql,使用show master status; 查看主机 master 的状态

在这里插入图片描述

  • 记录下mysql-bin.000002 和 154的值
  • slave 节点 service mysqld restart 重启master节点mysql服务
  • 登陆后输入一下命令
change master to master_host='192.168.174.136',master_user='slave1',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=154;

#开启同步功能
start slave;


######如果产生了数据无法同步的情况,在从节点上执行以下步骤(标记1)
1. stop slave;
2. 执行change 步骤 
   -> 'mysql-bin.000002' 和 154两个值要视重新同步时修改,使用show master status;获取
3. 执行start slave;
  • show slave status \G;
    在这里插入图片描述
  • 图示部分Slave_IO_Running和Slave_SQL_Running为yes即为成功
  • 主从测试 (命令行和navicat都可以)
    • 如下为第一次同步时的数据
      在这里插入图片描述

在这里插入图片描述

  • 在master的enterprise表中分别修改和插入一条数据
    在这里插入图片描述
  • 刷新从库表
    在这里插入图片描述
  • 在master中插入一张表
    在这里插入图片描述
  • 刷新从库表
    在这里插入图片描述
  • 在从库表中新增的test表添加一个id
    在这里插入图片描述
  • 主库没有改变
    在这里插入图片描述
    注意
  • 主从同步可能会有一定的延迟
    • 在主库进行表的增删,表内行数据的增删改,从库会自动同步
    • 切勿手动操作
    • 无操作后可以参考上面(标记1)的方法重新同步

Mycat 安装

mycat(192.168.174.138)

需先安装jdk

  • yum install java-1.8.0-openjdk* -y
  • mycat-github下载
  • https://pan.baidu.com/s/1Xeyno8pRomT__AvmzcvKnQ
    • 提取码 hmhc
    • 上传至虚拟机并解压 tar -zxvf Mycat-server-1.6-linux.tar.gz
      在这里插入图片描述
  • 配置环境变量
    • vim /etc/profile
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.345.b01-1.el7_9.x86_64
export MYCAT_HOME=/home/mycat
export PATH=$PATH:$JAVA_HOME/bin:$MYCAT_HOME/bin

在这里插入图片描述

  • source /etc/profile

  • cat /home/mycat/conf/server.xml

    • schemas中的名称要与与schema.xml关联(TESTDB)
      在这里插入图片描述
  • server.xml文件里登录mycat的用户名和密码可以任意定义,这个账号和密码是为客户机登录mycat时使用的账号信息

  • 逻辑库名(如上面的TESTDB,也就是登录mycat后显示的库名,切换这个库之后,显示的就是代理的真实mysq|数据库的表)要在schema.xml里面也定义,否则会导致mycat服务启动失败!

  • 如果定义多个标签,即设置多个连接mycat的用户名和密码,那么就需要在schema.xml文件中定义多个对应的库

  • vi /home/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="host1" database="hui" />
        <dataHost name="host1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="192.168.174.136:3306" user="root" password="123456">
                        <readHost host="hostS1" url="192.168.174.137:3306" user="root" password="123456"/>
                </writeHost>
        </dataHost>
</mycat:schema>
  • writeType 表示写模式

    • 0 所有的操作发送到配置的第一个writehost
    • 1 随机发送到配置的所有writehost
    • 2 不执行写操作
  • switchType 切换的模式

    • -1 表示不自动切换
    • 1 默认值,表示自动切换
    • 2 基于MySQL主从同步的状态决定是否切换,心跳语句为show slave status
    • 3 基于MySQL galary cluster的切换机制(适合集群)(1.4.1),心跳语句为show status like ‘wsrep%‘。
  • balance

    • 0 不开启读写分离机制,所有读操作都发送到当前可用的writeHost上。
    • 1 全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡。
    • 2 所有读操作都随机的在writeHost、readhost上分发。
    • 3 所有读请求随机的分发到writeHost下的readhost执行,writeHost不负担读压力
  • cd /home/mycat/bin

    • ./mycat start
    • ./mycat status
      在这里插入图片描述
  • 启动后发现navicat无法连接到mycat

    • 连接报错ERROR 2003 (HY000): Can’t connect to MySQL server on ‘192.168.174.138’
    • 通过mycat console查看得知以下问题
      在这里插入图片描述
  • 进入conf下的wrapper.conf注释掉以下行,然后重启 mycat restart

    • #wrapper.java.additional.3=-XX:MaxPermSize=64M在这里插入图片描述
  • 如果打开表出现ERROR 3009 (HY000): java.lang.IllegalArgumentException: Invalid DataSource:0

    • 原因是没有导入数据库hui
      • <dataNode name="dn1" dataHost="host1" database="hui" />
    • 在mysql-master和mysql-slave中导入就可以了
      • 此处是因为博主先部署了mycat,后设置的mysql主从,正常不会遇到这个问题
  • 通过navicat操作mycat测试读写分离

    • 在TESTDB下新建执行以下操作,添加一条数据
      在这里插入图片描述
  • 可以看到mysql-master节点执行了操作

在这里插入图片描述

  • mysql-slave节点自动同步了数据
    在这里插入图片描述
  • TESTDB中也有了
    在这里插入图片描述
  • 测试delete
    • DELETE FROM enterprise where id = 5
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

Java整合mycat (本文使用springboot项目)

  • 新建一个boot-mycat项目
  • pom.xml
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.42</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

  • 修改配置.yml文件
server:
  port: 8080

spring:
  main:
    allow-bean-definition-overriding: true
  application:
    name: mycat
  # Mycat配置信息
  datasource:
    url: jdbc:mysql://192.168.174.138:8066/TESTDB?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 123456
    # mybatis是依赖5.*的版本,所以相对于8.*的少个cj;
    driver-class-name: com.mysql.jdbc.Driver

# MyBatis
mybatis:
  type-aliases-package: com.example.bootmycat.dao
  mapper-locations: classpath:/mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
  • 新建一个实体类
/**
 * @author jigua
 * @version 1.0
 * @className Enterprise
 * @description
 * @create 2022/9/27 16:14
 */

public class Enterprise {

    private Long id;

    private String phone;

    private String name;

    public Long getId() {
        return id;
    }

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

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getName() {
        return name;
    }

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

  • 新建一个dao
import com.example.bootmycat.pojo.Enterprise;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @author jigua
 * @version 1.0
 * @className TestDao
 * @description
 * @create 2022/9/27 16:13
 */
@Mapper
public interface TestDao {

    @Select("select * from enterprise")
    List<Enterprise> selectAll();

    @Insert("insert into enterprise(phone,name) values(#{phone},#{name})")
    int add(Enterprise enterprise);
}

  • 新建一个controller
    • 示例提供一个查询和一个插入方法
import com.example.bootmycat.dao.TestDao;
import com.example.bootmycat.pojo.Enterprise;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.UUID;

/**
 * @author jigua
 * @version 1.0
 * @className TestController
 * @description
 * @create 2022/9/27 16:15
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private TestDao testDao;

    @GetMapping("/selectAll")
    @ResponseBody
    public List<Enterprise> selectAll() {
        List<Enterprise> enterprises = testDao.selectAll();

        return enterprises;
    }

    @GetMapping("/insert")
    @ResponseBody
    public String insert() {
        Enterprise enterprise = new Enterprise();
        String name = UUID.randomUUID().toString().replaceAll("-", "");
        enterprise.setName(name);
        enterprise.setPhone(name.substring(0, 3));
        int i = testDao.add(enterprise);
        if (i > 0) {
            return "success";
        }
        return "fail";
    }
}

测试插入
  • http://localhost:8080/test/insert

在这里插入图片描述

  • 可以发现master-slave-TESTDB中都新增了一条
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
测试查询
  • http://localhost:8080/test/selectAll

在这里插入图片描述

  • 成功获取数据

注意:如果此时master节点挂掉,slave也不可用

keepalived实现Mycat高可用

--------------------最近忙,过阵子更------------------------------

相关文章:

  • iOS 16 SwiftUI 4.0 列表(List)项分隔线变短的原因及解决
  • 创邻科技入选Gartner全球《图数据库管理系统市场指南》代表厂商
  • OpenHarmony如何控制屏幕亮度
  • jenkins 2.346.1 从git拉取后自动构建部署springboot maven项目
  • vue搭建项目、创建登录页面和后台交互之引入axios
  • MySQL-存储过程-函数-触发器-游标
  • JVM入门教程
  • python毕业设计项目源码选题(20)教室图书馆座位预约系统毕业设计毕设作品开题报告开题答辩PPT
  • 拿走吧,你,可视化大屏一次性解决
  • 基于SpringBoot零食销售系统的设计与实现【Java毕业设计·安装调试·代码讲解·文档报告】
  • C++面向对象程序设计(第2版)第七章(输入输出流)知识点总结
  • MATLAB | 全网唯一,使用MATLAB绘制精致的环形树状图
  • Nuxt3 简单集成 GoogleMap
  • 历届蓝桥杯青少年编程选拔赛 科技素养题真题讲解 STEMA评测比赛真题解析【持续更新 已更新至18套】
  • 【Java面试宝典】线程安全问题|线程死锁的出现|线程安全的集合类
  • JavaScript 如何正确处理 Unicode 编码问题!
  • (三)从jvm层面了解线程的启动和停止
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 【知识碎片】第三方登录弹窗效果
  • 2017-08-04 前端日报
  • Android框架之Volley
  • flutter的key在widget list的作用以及必要性
  • laravel5.5 视图共享数据
  • nodejs:开发并发布一个nodejs包
  • Spring-boot 启动时碰到的错误
  • Vue全家桶实现一个Web App
  • 记录一下第一次使用npm
  • 悄悄地说一个bug
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 自定义函数
  • #13 yum、编译安装与sed命令的使用
  • $(selector).each()和$.each()的区别
  • $jQuery 重写Alert样式方法
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (二)windows配置JDK环境
  • (三)Honghu Cloud云架构一定时调度平台
  • (四)图像的%2线性拉伸
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (转)EXC_BREAKPOINT僵尸错误
  • (转)linux下的时间函数使用
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .gitignore文件设置了忽略但不生效
  • .NET Core WebAPI中封装Swagger配置
  • .Net Core与存储过程(一)
  • .NET 读取 JSON格式的数据
  • .NET 反射 Reflect
  • .NET:自动将请求参数绑定到ASPX、ASHX和MVC(菜鸟必看)
  • .net6 webapi log4net完整配置使用流程
  • .net流程开发平台的一些难点(1)
  • /bin/rm: 参数列表过长"的解决办法
  • @media screen 针对不同移动设备
  • [ vulhub漏洞复现篇 ] Hadoop-yarn-RPC 未授权访问漏洞复现
  • [C#]手把手教你打造Socket的TCP通讯连接(一)
  • [C++进阶篇]STL中vector的使用
  • [cb]UIGrid+UIStretch的自适应