MySQL 学习笔记(运维篇2)

一、分库分表(延续上节博客的内容)

1. 垂直拆分

(1) 场景

(2) 配置

XML 复制代码
<schema name="SHOPPING" checkSQLschema="true" sqlMaxLimit="100" >
    <table name="tb_goods_base" dataNode="dn1" primaryKey="id"/>
    <table name="tb_goods_cat" dataNode="dn1" primaryKey="id"/>
    <table name="tb_goods_desc" dataNode="dn1" primaryKey="goods_id"/>
    <table name="tb_goods_item" dataNode="dn1" primaryKey="id"/>
    <table name="tb_order_item" dataNode="dn2" primaryKey="id"/>
    <table name="tb_order_master" dataNode="dn2" primaryKey="order_id" rule="order_rule" />
    <table name="tb_order_pay_log" dataNode="dn2" primaryKey="out_trade_no"/>
    <table name="tb_user" dataNode="dn3" primaryKey="id"/>
    <table name="tb_areas_provinces" dataNode="dn3" primaryKey="id"/>
    <table name="tb_areas_city" dataNode="dn3" primaryKey="id"/>
    <table name="tb_areas_region" dataNode="dn3" primaryKey="id"/>
    <table name="tb_user_address" dataNode="dn3" primaryKey="id"/>
</schema>

<dataNode name="dn1" dataHost="dhost1" database="shopping" />
<dataNode name="dn2" dataHost="dhost2" database="shopping" />
<dataNode name="dn3" dataHost="dhost3" database="shopping" />

说明:

schema 节点下关联多个 table 标签,不同 table 对应不同 dataNode:

① dn1 对应商品类表(如 tb_goods_base、tb_goods_cat 等)

② dn2 对应订单类表(如 tb_order_item、tb_order_master 等)

③ dn3 对应用户及地址类表(如 tb_user、tb_areas_provinces 等)

(3) 测试

① 在 mycat 的命令行中,通过 source 指令导入表结构及对应数据,查看数据分布情况:

bash 复制代码
source /root/shopping_table.sql
source /root/shopping_insert.sql

② 查询用户的收件人及收件人地址信息 (包含省、市、区):

sql 复制代码
select ua.user_id,ua.contact,p.province,c.city,r.area,ua.address from tb_user_address ua,tb_areas_city c,tb_areas_provinces p,tb_areas_region r where ua.province_id = p.provinceid and ua.city_id = c.cityid and ua.town_id = r.areaid ;

③ 查询每一笔订单及订单的收件地址信息 (包含省、市、区):

sql 复制代码
SELECT o.order_id, p.payment,o.receiver,p.province,c.city,r.area FROM tb_order_master o,tb_areas_provinces p,tb_areas_city c,tb_areas_region r WHERE o.receiver_province = p.provinceid AND o.receiver_city = c.cityid AND o.receiver_region = r.areaid ;

(4) 全局表配置

对于省、市、区 / 县表tb_areas_provinces, tb_areas_city, tb_areas_region,是属于数据字典表,在多个业务模块中都可能会遇到,可以将其设置为全局表,利于业务操作。

XML 复制代码
<table name="tb_areas_provinces" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
<table name="tb_areas_city" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
<table name="tb_areas_region" dataNode="dn1,dn2,dn3" primaryKey="id" type="global"/>
2. 水平拆分

(1) 场景

在业务系统中,有一张表 (日志表),业务系统每天都会产生大量的日志数据,单台服务器的数据存储及处理能力是有限的,可以对数据库表进行拆分。

(2) 配置

① shema.xml

XML 复制代码
<schema name="ITCAST" checkSQLschema="true" sqlMaxLimit="100" >
    <table name="tb_log" dataNode="dn4,dn5,dn6" rule="mod-long" />
</schema>
<dataNode name="dn4" dataHost="dhost1" database="itcast" />
<dataNode name="dn5" dataHost="dhost2" database="itcast" />
<dataNode name="dn6" dataHost="dhost3" database="itcast" />

② server.xml

XML 复制代码
<user name="root" defaultAccount="true">
    <property name="password">123456</property>
    <property name="schemas">SHOPPING,ITCAST</property>
    <!-- 表级 DML 权限设置 -->
    <!--
    <privileges check="false">
        <schema name="TESTDB" dml="0110">
            <table name="tb01" dml="0000"></table>
            <table name="tb02" dml="1111"></table>
        </schema>
    </privileges>
    -->
</user>

(3) 测试

在 mycat 的命令行中,执行如下 SQL 建表、并插入数据,查看数据分布情况。

sql 复制代码
CREATE TABLE tb_log (
id bigint(20) NOT NULL COMMENT 'ID',
model_name varchar(200) DEFAULT NULL COMMENT '模块名',
model_value varchar(200) DEFAULT NULL COMMENT '模块值',
type varchar(200) DEFAULT NULL COMMENT '类型',
return_value varchar(200) DEFAULT NULL COMMENT '返回值',
return_class varchar(200) DEFAULT NULL COMMENT '返回类型',
operate_user varchar(200) DEFAULT NULL COMMENT '操作用户',
operate_time timestamp NULL DEFAULT NULL COMMENT '操作时间',
param_and_value varchar(500) DEFAULT NULL COMMENT '请求参数名及参数值',
operate_class varchar(200) DEFAULT NULL COMMENT '操作类',
operate_method varchar(200) DEFAULT NULL COMMENT '操作方法',
cost_time bigint(20) DEFAULT NULL COMMENT '执行方法耗时,单位ms',
summary text DEFAULT NULL COMMENT '摘要 1.2,Arond.102',
PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 分片规则

(1) 范围分片

根据指定的字段及其配置的范围与数据节点的对应情况,来决定该数据属于哪一个分片。

说明:

  • 0~5000000 → dataNode1
  • 5000001~10000000 → dataNode2
  • 10000001 及以上 → dataNode3

(2) 取模分片

根据指定的字段值与节点数量进行求模运算,根据运算结果,来决定该数据属于哪一个分片。

说明: 通过id % 3的结果分配数据:

  • id%3=0 → dataNode1
  • id%3=1 → dataNode2
  • id%3=2 → dataNode3

(3) 一致性hash 分片

所谓一致性哈希,相同的哈希因子计算总是被划分到相同的分区表中,不会因为分区节点的增加而改变原来数据的分区位置。

① schema.xml

XML 复制代码
<table name="tb_order" dataNode="dn4,dn5,dn6" rule="sharding-by-murmur" />

<dataNode name="dn4" dataHost="dhost1" database="itcast" />
<dataNode name="dn5" dataHost="dhost2" database="itcast" />
<dataNode name="dn6" dataHost="dhost3" database="itcast" />

② rule.xml

XML 复制代码
<tableRule name="sharding-by-murmur">
    <rule>
        <columns>id</columns>
        <algorithm>murmur</algorithm>
    </rule>
</tableRule>

<function name="murmur" class="io.mycat.route.function.PartitionByMurmurHash">
    <property name="seed">0</property> <!-- 默认是0 -->
    <property name="count">3</property> <!-- 要分片的数据库节点数,必须指定,否则没法分片 -->
    <property name="virtualBucketTimes">160</property> <!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
    <!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。 -->
</function>

(4) 枚举分片

通过在配置文件中配置可能的枚举值,指定数据分布到不同数据库节点上。本规则适用于按照省份、性别、状态拆分数据等业务。

(5) 应用指定算法

运行阶段由应用自主决定路由到哪个分片,直接根据字符串(必须是数字)计算分片号。

说明:

  • 00xxxx → 对应 dataNode1 的数据库
  • 01xxxx → 对应 dataNode2 的数据库
  • 02xxxx → 对应 dataNode3 的数据库

(6) 固定hash算法

该算法类似于十进制的求模运算,但是为二进制的操作,例如,取 id 的二进制低 10 位与1111111111进行位 & 运算。

说明:

① 任何一个十位的二进制与 1111111111(十位全1)进行与运算后的结果,结果就是这个十位二进制数本身。

② 原因是这个二进制数的每一位都是 1,因此在与运算中:

  • 如果原数某一位是 1 → 1 & 1 = 1
  • 如果原数某一位是 0 → 0 & 1 = 0

也就是说,它不会改变原数的任何一位,只是保留原数的所有位。

③ 举例验证:假设原数是 1010101010(十位):

bash 复制代码
    1010101010
  & 1111111111
  -----------
    1010101010  ← 结果和原数完全相同

(7) 字符串hash解析

截取字符串中的指定位置的子字符串,进行hash算法,算出分片

运算示例:

以 "world" 为例:

  • 截取子串:world → 取0:2对应 "wor"
  • 执行 hash 运算:得到结果 26629
  • 计算分片:26629 & (1024-1) = 5

(8) 按天分片

说明:

配置参数: begin:2022-01-01end:2022-01-30partitionDay:10

分片时间区间与 dataNode 对应:

  • 2022-01-01 ~ 2022-01-10 → dataNode1
  • 2022-01-11 ~ 2022-01-20 → dataNode2
  • 2022-01-21 ~ 2022-01-30 → dataNode3

(9) 按月分片

使用场景为按月份来分片,每个自然月为一个分片

说明:

分片时间范围为 begin:2022-01-01end:2022-03-31,数据按月份对应到不同 dataNode:

  • dataNode1 对应数据:2022-01-10、2022-04-12(注:结束时间后会循环分片)
  • dataNode2 对应数据:2022-02-20
  • dataNode3 对应数据:2022-03-31

​​​​​​​

4. Mycat 管理及监控

(1) Mycat 原理

select * from tb_user;

  • 客户端把 SQL 发给 Mycat Server;
  • Mycat 先解析 SQL ,再做分片分析(按规则,这个 SQL 要查所有分片);
  • 路由分析,确定要访问右边 3 个数据库节点;
  • 从 3 个节点取数据后,做分页、排序、聚合、结果合并
  • 把合并后的结果返回给客户端。

select * from tb_user where status in(1,3) order by id;

  • 客户端发 SQL 后,Mycat 解析出status条件;
  • 分片分析 + 路由分析:只需要访问status=1(dn1)和status=3(dn3)的数据库;
  • 从这 2 个节点取数据后,做排序处理 + 结果合并
  • 返回最终结果给客户端。

(2) Mycat 管理

① Mycat 默认开通 2 个端口,可在server.xml中修改:

  • 8066 数据访问端口,用于执行 DML 和 DDL 操作。
  • 9066 数据库管理端口,用于管理 Mycat 集群状态。

② 连接管理端口的命令:

bash 复制代码
mysql -h 192.168.200.210 -P 9066 -uroot -p123456

③ Mycat 管理命令及含义:

命令 含义
show @@help 查看 Mycat 管理工具文档
show @@version 查看 Mycat 的版本
reload @@config 重新加载 Mycat 的配置文件
show @@datasource 查看 Mycat 的数据源信息
show @@datanode 查看 Mycat 现有的分片节点信息
show @@threadpool 查看 Mycat 的线程池信息
show @@sql 查看执行的 SQL
show @@sql.sum 查看执行的 SQL 统计

二、读写分离

1. 介绍

(1) 读写分离,简单地说是把对数据库的读和写操作分开,对应不同的数据库服务器。主数据库提供写操作,从数据库提供读操作,这样能有效地减轻单台数据库的压力。

(2) 通过 MyCat 即可轻易实现上述功能,不仅可以支持 MySQL,也可以支持 Oracle 和 SQL Server。

说明:

① 应用程序连接 MyCat,MyCat 将insert/update/delete操作路由到writeHost对应的主库(mysql (m))

② 将select操作路由到readHost对应的从库(mysql (s))

③ 主库与从库之间通过主从复制(blog)同步数据

2. 一主一从读写分离

(1) 配置

Mycat 中balance参数的取值及含义说明表:

参数值 含义
0 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上
1 全部的 readHost 与备用的 writeHost 都参与 select 语句的负载均衡(主要针对于双主双从模式)
2 所有的读写操作都随机在 writeHost、readHost 上分发
3 所有的读请求随机分发到 writeHost 对应的 readHost 上执行,writeHost 不负担读压力
3. 双主双从

(1) 介绍

一个主机 Master1 用于处理所有写请求,它的从机 Slave1 和另一台主机 Master2 还有它的从机 Slave2 负责所有读请求。当 Master1 主机宕机后,Master2 主机负责写请求,Master1、Master2 互为备机。架构图如下:

说明:

① 应用程序连接 MyCat,MyCat 分发请求;

② mysql (m1)(Master1)复制数据到 mysql (s1)(Slave1),mysql (m2)(Master2)复制数据到 mysql (s2)(Slave2),同时 mysql (m1) 与 mysql (m2) 之间也存在复制关系,mysql (m1) 为主、mysql (m2) 为备

**Q:**主库不是负责写的吗?为什么 Master2 负责读了?

A: 双主双从中,Master1 是 "主用主库":默认承担所有写请求; 而 Master2 是"备用主库"

  • 平时(Master1 正常运行时),它不处理写请求,而是作为读节点来分担读压力(和 Slave1、Slave2 一起负责读请求);
  • 只有当 Master1 宕机后,它才会切换为 "主库",接手写请求。

(2) 准备工作

我们需要准备 5 台服务器,具体的服务器及软件安装情况如下:

编号 IP 预装软件 角色
1 192.168.200.210 MyCat、MySQL MyCat 中间件服务器
2 192.168.200.211 MySQL M1(Master1)
3 192.168.200.212 MySQL S1(Slave1)
4 192.168.200.213 MySQL M2(Master2)
5 192.168.200.214 MySQL S2(Slave2)

关闭以上所有服务器的防火墙:

  • systemctl stop firewalld
  • systemctl disable firewalld

(3) 搭建

① 主库配置(M1)

修改配置文件 /etc/my.cnf

bash 复制代码
#mysql 服务ID,保证整个集群环境中唯一,取值范围:1 - 2^32-1,默认为1
server-id=1
#指定同步的数据库
binlog-do-db=db01
binlog-do-db=db02
binlog-do-db=db03
#在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates

重启 MySQL 服务器

bash 复制代码
systemctl restart mysqld

② 主库配置(M2)

修改配置文件 /etc/my.cnf

bash 复制代码
#mysql 服务ID,保证整个集群环境中唯一,取值范围:1 - 2^32-1,默认为1
server-id=3
#指定同步的数据库
binlog-do-db=db01
binlog-do-db=db02
binlog-do-db=db03
#在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates

重启 MySQL 服务器

bash 复制代码
systemctl restart mysqld

③ 两台主库创建账户并授权(注:该操作需在 Master1、Master2 两台主库分别执行)

bash 复制代码
# 创建itcast用户,并设置密码,该用户可在任意主机连接该MySQL服务
CREATE USER 'itcast'@'%' IDENTIFIED WITH mysql_native_password BY 'Root@123456';

# 为'itcast'@'%'用户分配主从复制权限
GRANT REPLICATION SLAVE ON *.* TO 'itcast'@'%';

查看两台主库的二进制日志坐标

bash 复制代码
show master status;

④ 从库配置(S1)

修改配置文件 /etc/my.cnf

bash 复制代码
#mysql 服务ID,保证整个集群环境中唯一,取值范围:1 - 2^32-1,默认为1
server-id=2

重启 MySQL 服务器

bash 复制代码
systemctl restart mysqld

⑤ 从库配置(S2)

修改配置文件 /etc/my.cnf

bash 复制代码
#mysql 服务ID,保证整个集群环境中唯一,取值范围:1 - 2^32-1,默认为1
server-id=4

重启 MySQL 服务器

bash 复制代码
systemctl restart mysqld

⑥ 两台从库关联的从库

执行CHANGE MASTER TO命令,关联对应的主库(注意:slave1 对应 master1,slave2 对应 master2):

sql 复制代码
CHANGE MASTER TO 
MASTER_HOST='xxx.xxx.xxx.xxx',  # 对应主库的IP
MASTER_USER='xxx',             # 主库授权的复制用户(如itcast)
MASTER_PASSWORD='xxx',         # 复制用户的密码(如Root@123456)
MASTER_LOG_FILE='xxx',         # 主库`show master status`查到的日志文件名
MASTER_LOG_POS=xxx;            # 主库`show master status`查到的日志位置

启动两台从库主从复制,查看从库状态

sql 复制代码
# 启动主从复制
start slave;

# 查看从库状态(需确保Slave_IO_Running、Slave_SQL_Running均为Yes)
show slave status\G;

(4) 测试

分别在两台主库Master1、Master2上执行DDL、DML语句,查看涉及到的数据库服务器的数据同步情况。

sql 复制代码
create database db01;
use db01;
create table tb_user(
	id in(11)not null primary key,
	name varchar(50) not null,
	sex varcahr(1)
)engine=innodb default charset=utf8mb4

insert into tb user(id,name,sex) values(l,'Tom','1');
insert into tb user(id,name,sex) values(2,'Trigger','0');
insert into tb user(id,name,sex) values(3,'Dawn','1');
insert into tb user(id,name,sex) values(4,"ack Ma','1');
insertinto tb user(id,name,sex) values(5,'Coco','0');
insert into tb user(id,name,sex) values(6,'erry','1');
4. 双主双从读写分离

(1) 配置

(2) 测试

① 登录MyCat,测试查询及更新操作,判定是否能够进行读写分离,以及读写分离的策略是否正确。

② 当主库挂掉一个之后,是否能够自动切换。

相关推荐
羑悻的小杀马特10 小时前
PostgreSQL + Cpolar 组合拳,彻底打破局域网限制,远程访问数据库像本地一样简单
数据库·postgresql
fanged10 小时前
前端的调试(TODO)
笔记
松涛和鸣10 小时前
DAY61 IMX6ULL UART Serial Communication Practice
linux·服务器·网络·arm开发·数据库·驱动开发
二哈喇子!12 小时前
MySQL数据库概述
mysql
二哈喇子!16 小时前
MySQL数据更新操作
数据库·sql
二哈喇子!16 小时前
MySQL命令行导入数据库
数据库·sql·mysql·vs code
心动啊12116 小时前
SQLAlchemy 的使用
数据库
强子感冒了16 小时前
Java网络编程学习笔记,从网络编程三要素到TCP/UDP协议
java·网络·学习
Quintus五等升16 小时前
深度学习④|分类任务—VGG13
人工智能·经验分享·深度学习·神经网络·学习·机器学习·分类
二哈喇子!17 小时前
Java框架精品项目【用于个人学习】
java·spring boot·学习