1. MySQL クラスターの導入スキーム
MySQL クラスターの展開スキームは次のとおりです。
MySQL Cluster: MySQL が公式に提供する MySQL クラスタソリューション。MySQL のソースコードを変更することで MySQL クラスタの分散機能を実現します。
Galera Cluster: Galera Cluster は、MySQL をベースとした高可用性ソリューションであり、MySQL のマスター/スレーブ レプリケーション機能を拡張することで、MySQL クラスターの高可用性と拡張性を実現します。
Percona XtraDB Cluster: Percona XtraDB Cluster は、MySQL をベースとした高可用性ソリューションであり、MySQL のマスター/スレーブ レプリケーション機能を拡張することで、MySQL クラスターの高可用性と拡張性を実現します。
MySQL Replication: MySQL Replication は、MySQL が公式に提供する高可用性ソリューションであり、MySQL のマスター/スレーブ レプリケーション機能を拡張することで、MySQL クラスターの高可用性を実現します。
MySQL プロキシ: MySQL プロキシは、複数の MySQL インスタンスを MySQL クラスターに変換でき、MySQL クラスターのロード バランシングやフェイルオーバーなどの機能を提供する MySQL プロキシです。
2. Docker は、mysql マスター/スレーブ レプリケーション (1 つのマスターと複数のスレーブ) をデプロイします。
マスターノード
docker-compose.yml ファイルを準備する
version: '3.1'
services:
mysql-master:
image: mysql:8.0.32
container_name: mysql-master
restart: always
network_mode: "host"
environment:
TZ: Asia/Shanghai # 时区上海
MYSQL_ROOT_PASSWORD: "123456" #mysql密码
ports:
- "3306:3306"
volumes:
- ./data:/var/lib/mysql
- ./log:/var/log/mysql
- ./conf:/etc/mysql/conf.d
my.cnf 構成ファイルを準備します (公式 Web サイトにアクセスして自分でダウンロードできます。次のフィールドを変更するだけです)。
[mysqld]
#Mysql服务的唯一编号 每个mysql服务Id需唯一
server-id=11
# [必须]启用二进制日志
log-bin=mysql-bin
log-bin-index=mysql-bin.index
binlog-ignore-db=mysql
# 设置需要同步的数据库 binlog_do_db = 数据库名;
# 如果是多个同步库,就以此格式另写几行即可。
# 如果不指明对某个具体库同步,表示同步所有库。除了binlog-ignore-db设置的忽略的库
# 跳过所有的错误,继续执行复制操作
slave-skip-errors=all
# 二进制日志过期清理时间。默认值为0,表示不自动清理。
binlog_expire_logs_seconds=2592000
#以下内容每个节点保持一致
# By default we only accept connections from localhost
bind-address="0.0.0.0"
#数据库默认字符集,主流字符集支持一些特殊表情符号(特殊表情符占用4个字节)
character-set-server=utf8mb4
#数据库字符集对应一些排序等规则,注意要和character-set-server对应
collation-server=utf8mb4_general_ci
#设置client连接mysql时的字符集,防止乱码
init_connect='SET NAMES utf8mb4'
#是否对sql语句大小写敏感,1表示不敏感
lower_case_table_names = 1
#设置加密方式
default_authentication_plugin=mysql_native_password
スレーブノード
docker-compose.yml ファイルを準備する
version: '3.1'
services:
mysql-master:
image: mysql:8.0.32
container_name: mysql-slave01
restart: always
network_mode: "host"
environment:
TZ: Asia/Shanghai # 时区上海
MYSQL_ROOT_PASSWORD: "123456" #mysql密码
ports:
- "3306:3306"
volumes:
- ./data:/var/lib/mysql
- ./log:/var/log/mysql
- ./conf:/etc/mysql/conf.d
my.cnf 構成ファイルを準備する
[mysqld]
#Mysql服务的唯一编号 每个mysql服务Id需唯一
server-id=12
# 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
log-bin=mysql-bin
log-bin-index=mysql-bin.index
binlog-ignore-db=mysql
# 设置需要同步的数据库 binlog_do_db = 数据库名;
# 如果是多个同步库,就以此格式另写几行即可。
# 如果不指明对某个具体库同步,表示同步所有库。除了binlog-ignore-db设置的忽略的库
# 跳过所有的错误,继续执行复制操作
slave-skip-errors = all
# slave设置为只读(具有super权限的用户除外)
read_only=1
## relay_log配置中继日志
relay_log=mysql-relay-bin
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
# 二进制日志过期清理时间。默认值为0,表示不自动清理。
binlog_expire_logs_seconds=2592000
#以下内容每个节点保持一致
# By default we only accept connections from localhost
bind-address="0.0.0.0"
#数据库默认字符集,主流字符集支持一些特殊表情符号(特殊表情符占用4个字节)
character-set-server=utf8mb4
#数据库字符集对应一些排序等规则,注意要和character-set-server对应
collation-server=utf8mb4_general_ci
#设置client连接mysql时的字符集,防止乱码
init_connect='SET NAMES utf8mb4'
#是否对sql语句大小写敏感,1表示不敏感
lower_case_table_names = 1
#设置加密方式
default_authentication_plugin=mysql_native_password
mysqlのマスター/スレーブを構成する
マスターノードに入る
docker exec -it mysql-master mysql -u root -p
次のコードを実行して、slave01 および smile02 ユーザーを追加します。
#在主机MySQL里执行授权命令
CREATE USER 'slave01'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'slave01'@'%';
#此语句必须执行。否则见下面。
ALTER USER 'slave01'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
#在主机MySQL里执行授权命令
CREATE USER 'slave02'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'slave02'@'%';
#此语句必须执行。否则见下面。
ALTER USER 'slave02'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
flush privileges;
#查询master的状态,记住file和position对应的信息,为后来添加从到主做准备。
show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 1912 | | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
マスター/スレーブをslave01に設定します。
docker exec -it mysql-slave01 mysql -u root -p
#host替换为配置master的ip,master_log_file就是之前master对应的file信息,master_log_pos就是之前position对应的信息
change master to master_host='192.168.10.11', master_user='slave01', master_password='123456', master_port=3306, master_log_file='mysql-bin.000003', master_log_pos=1912, master_connect_retry=30;
start slave;
# 查看slave信息,如果Slave_IO_Running、Slave_SQL_Running两个信息是yes代表搭建从库成功
show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.10.11
Master_User: slave01
Master_Port: 3306
Connect_Retry: 30
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 1912
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 326
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 1912
Relay_Log_Space: 536
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 11
Master_UUID: 18e50f5e-cba8-11ed-b275-000c2930730f
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set, 1 warning (0.00 sec)
SLAVE02 上記と同じ
https://cloud.tencent.com/developer/article/2074869
3. springboot は mysql クラスターを統合します
読み取りと書き込みの分離、メイン ライブラリの書き込みとライブラリからの読み取り
以下に、一般的なサブデータベースおよびサブテーブルのミドルウェアをいくつか示します。
Sharding-JDBC: Sharding-JDBC は、データベースの水平拡張を簡単に実現できる非常に人気のあるサブデータベースおよびテーブル ミドルウェアです。複数のシャーディング戦略をサポートしており、Spring Boot と統合できます。データベースを水平方向に拡張する必要がある場合、Sharding-JDBC は非常に良い選択です。
MyCAT: MyCAT は、MySQL サブデータベースのサブテーブルと読み書き分離を実装できるオープン ソースの分散データベース システムです。複数のシャーディング戦略をサポートし、MySQL および MariaDB と統合できます。
TDDL: TDDL は Alibaba によって開発された分散データベース ミドルウェアで、MySQL サブデータベースのサブテーブルと読み書き分離を実装できます。複数のシャーディング戦略をサポートしており、Spring および MyBatis と統合できます。
Cobar: Cobar は、MySQL サブデータベースのサブテーブルと読み書き分離を実装できるオープンソースの分散データベース ミドルウェアです。複数のシャーディング戦略をサポートし、MySQL および MariaDB と統合できます。
シャーディングと JDBC の読み取りと書き込みの分離
公式ドキュメントのYaml 構成:: ShardingSphere (apache.org)を参照してください。
注: shardingsphere-jdbc5 の構成は以前のバージョンとは異なり、対応する springboot-start パッケージ名も異なります。
依存関係を導入する
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
yml設定を書き込む
spring:
#sharding-jdbc
shardingsphere:
datasource:
names: master,slave01,slave02
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.10.11:3306/test?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true
username: root
password: 123456
slave01:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.10.12:3306/test?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true
username: root
password: 123456
slave02:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.10.13:3306/test?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true
username: root
password: 123456
rules:
readwrite-splitting:
data-sources:
## 读写分离名称
pr_ds:
type: STATIC #静态类型,(动态Dynamic)
props:
## 自动发现数据源名称
# auto-aware-data-source-name: slave0
## 写数据源名称
write-data-source-name: master
## 读数据源名称
read-data-source-names: slave01,slave02
## 负载均衡算法名称
load-balancer-name: read-write-separation-load-balancer
load-balancers:
read-write-separation-load-balancer:
## 负载均衡算法类型
type: ROUND_ROBIN
props:
sql-show: true # 开启SQL显示,默认false
テスト
@Test
void saveAndGet() {
Student student = new Student("test", 11);
studentService.save(student);
Student student1 = studentService.getById(10);
System.out.println(student1);
}
ログ出力
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2a7ebe07] was not registered for synchronization because synchronization is not active
JDBC Connection [org.apache.shardingsphere.shardingjdbc.jdbc.core.connection.MasterSlaveConnection@3cd46491] will not be managed by Spring
==> Preparing: INSERT INTO student ( name, age ) VALUES ( ?, ? )
2023-04-06 21:14:40.535 INFO 22688 --- [main] ShardingSphere-SQL: Logic SQL: INSERT INTO student ( name,age ) VALUES ( ?,? )
2023-04-06 21:14:40.535 INFO 22688 --- [main] ShardingSphere-SQL: SQLStatement: CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.InsertStatement@7b29cdea, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@f08d676)
2023-04-06 21:14:40.535 INFO 22688 --- [main] ShardingSphere-SQL: Actual SQL: master ::: INSERT INTO student ( name,age ) VALUES ( ?,? )
==> Parameters: test(String), 11(Integer)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2a7ebe07]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@511d5e6e] was not registered for synchronization because synchronization is not active
JDBC Connection [org.apache.shardingsphere.shardingjdbc.jdbc.core.connection.MasterSlaveConnection@299eca90] will not be managed by Spring
==> Preparing: SELECT id,name,age FROM student WHERE id=?
2023-04-06 21:14:40.588 INFO 22688 --- [main] ShardingSphere-SQL: Logic SQL: SELECT id,name,age FROM student WHERE id=?
2023-04-06 21:14:40.588 INFO 22688 --- [main] ShardingSphere-SQL: SQLStatement: SelectStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.SelectStatement@6b289535, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@74619273), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@74619273, projectionsContext=ProjectionsContext(startIndex=7, stopIndex=17, distinctRow=false, projections=[ColumnProjection(owner=null, name=id, alias=Optional.empty), ColumnProjection(owner=null, name=name, alias=Optional.empty), ColumnProjection(owner=null, name=age, alias=Optional.empty)]), groupByContext=org.apache.shardingsphere.sql.parser.binder.segment.select.groupby.GroupByContext@38c55a8a, orderByContext=org.apache.shardingsphere.sql.parser.binder.segment.select.orderby.OrderByContext@1d7f7962, paginationContext=org.apache.shardingsphere.sql.parser.binder.segment.select.pagination.PaginationContext@32d1d6c5, containsSubquery=false)
2023-04-06 21:14:40.588 INFO 22688 --- [main] ShardingSphere-SQL: Actual SQL: slave01 ::: SELECT id,name,age FROM student WHERE id=?
==> Parameters: 10(Integer)
<== Columns: id, name, age
<== Row: 10, java, 22
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@511d5e6e]
挿入はマスターによって行われ、クエリはslave01によって行われることが示されています。
実際のSQL: master ::: INSERT INTO Student ( name,age ) VALUES ( ?,? )
実際のSQL:slave01 ::: SELECT id,name,age FROM Student WHERE id=?
シャーディング-JDBCサブデータベースサブテーブル
レベル表
server:
port: 8089
spring:
shardingsphere:
mode:
type: memory
# 是否开启
datasource:
# 数据源(逻辑名字)
names: master
# 配置数据源
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.10.11:3306/test?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
# 分片的配置
rules:
sharding:
# 表的分片策略
tables:
# 逻辑表的名称
student:
# 数据节点配置,采用Groovy表达式
actual-data-nodes: master.student_$->{0..3}
# 配置策略
table-strategy:
# 用于单分片键的标准分片场景
standard:
sharding-column: id
# 分片算法名字
sharding-algorithm-name: student_inline
key-generate-strategy: # 主键生成策略
column: id # 主键列
key-generator-name: snowflake # 策略算法名称(推荐使用雪花算法)
key-generators:
snowflake:
type: SNOWFLAKE
sharding-algorithms:
student_inline:
type: inline
props:
algorithm-expression: student_$->{id % 4}
props:
# 日志显示具体的SQL
sql-show: true
logging:
level:
com.wang.test.demo: DEBUG
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 address_book ---> addressBook
map-underscore-to-camel-case: true