[版权申明] 非商业目的注明出处可自由转载
出自:shusheng007
今天我们来聊一下软件系统架构中数据库侧的一些常用设计和具体搭建吧,小朋友如果是做软件开发的现在其实也应该对运维这块有一些了解的,软件开发方法论的发展,特别是敏捷开发的发展竟然不知不觉使得开发与运维都紧密的融为一起了,俗称DevOps(DevOps is a set of practices that combines software development (Dev) and IT operations (Ops))。近年来微服务的发展更使得DevOps成为不可获取的一个角色。
数据库在一个软件系统的重要程度我们就不多说了。我们今天就简单聊聊为什么要搞主从架构?如何搞?
最开始的时候我们对软件系统的要求很低,但后来要求越来越高,对数据库的要求相应也就变的越来越多:兄弟我希望你7X24小时稳定运行50年,兄弟最近流量暴增了你的给抗住啊,兄弟机房断电你也不能给我丢数据啊,兄弟机房断电我还是想让你能正常工作,兄弟… 数据库兄弟怒了:我R你LL…
你看就是由于要求越来越多,单机数据库根本就不能满足这些要求,所以就出来很多架构方式来解决这些问题,今天说的主从架构就是非常经典和有效的一种。
软件架构的思想其实非常朴素:你一个人是不是搞不定?那就再给你加几个! 特别是在解决系统高可用上,在单机可用性已经无法提高了的情况下,就剩下冗余一招。
主从架构的意思就是多个数据库在一起干活,但是被人为的分了个主次,他们之间的数据结构以及存储的数据完全一样。主从架构有很多种,一主一从,一主多从,多主多从,都差不多,只要理解了一主一从就可以了,其他的都是变种。
现在有两份一模一样的数据,主库出问题,从库就可以顶上。
现在有两份一模一样的数据,主库负责写,从库就负责读
在备份数据的时候可以从从库备份,这样就不需需要锁主库的表,那么系统的性能会提升
Mysql的主从复制是基于日志的。主数据库将数据库修改写入它的binlog日志中,从数据库呢启动两个线程,一个Io线程一个sql线程。Io线程去主库把binlog日志读取过来写入自己的中继日志(relay log),然后sql线程读取relaylog 然后解析成sql将数据插入到从库中。
理解了目的和原理,我们就来实际搭建一下mysql的主从架构。
我使用docker来搭建吧,我们需要启动两个MySQL的容器,且这两个容器可以互相访问,因为从库要去主库复制数据。
我们使用docker-compose来搭建。下面是完整的mariadb-dc-ms.yml
内容。值得注意的是我们创建了一个自定义的网络db-network
,使得这两个容器位于同一个网络中。
version: '3'
services:
mariadb-master:
image: mariadb:10.6.5
container_name: mariadb-master
ports:
- 3001:3306
volumes:
- ~/software/database/master-db/config:/etc/mysql/conf.d
- ~/software/database/master-db/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
networks:
db-network:
ipv4_address: 172.172.0.10
mariadb-slave:
image: mariadb:10.6.5
container_name: mariadb-slave
ports:
- 3002:3306
volumes:
- ~/software/database/slave-db/config:/etc/mysql/conf.d
- ~/software/database/slave-db/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
networks:
db-network:
ipv4_address: 172.172.0.11
networks:
db-network:
driver: bridge
ipam:
config:
- subnet: 172.172.0.0/24
进入mariadb-dc-ms.yml
的目录下,使用如下命令来创建两个mysql容器
docker-compose -f mariadb-dc-ms.yml up -d
创建后我们可以进入从库的容器中ping一下主库的容器,看它们是否可以正常通信
# 进入从库容器内部
docker exec -it mariadb-slave /bin/bash
# ping一下主库ip
root@f1893254ec84:/# ping -c 3 172.172.0.10
# 说明网络连通正常
PING 172.172.0.10 (172.172.0.10) 56(84) bytes of data.
64 bytes from 172.172.0.10: icmp_seq=1 ttl=64 time=0.186 ms
64 bytes from 172.172.0.10: icmp_seq=2 ttl=64 time=0.321 ms
64 bytes from 172.172.0.10: icmp_seq=3 ttl=64 time=0.365 ms
如果容器内找不到ping命令,先安装ping
apt-get update
apt-get install iputils-ping
现在这两个数据库之间完全没有关系,所以还需要一些配置让他们联系起来。
因为主从复制是基于binlog的,所以首先要确保binlog正常记录的。
进入mysql客户端
mysql -uroot -proot
查看binlog日志状态:
MariaDB [(none)]> show variables like '%log_bin%';
输出:
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin | OFF |
| log_bin_basename | |
| log_bin_compress | OFF |
| log_bin_compress_min_len | 256 |
| log_bin_index | |
| log_bin_trust_function_creators | OFF |
| sql_log_bin | ON |
+---------------------------------+-------+
可见log_bin是OFF的,所以需要打开。
我们也可以使用下面的命令来看binlog目前采用的类型,这块是binlog的知识,暂时不懂也没关系。
MariaDB [(none)]> show variables like '%binlog_format%'
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| binlog_format | MIXED |
| wsrep_forced_binlog_format | NONE |
+----------------------------+-------+
如何打开呢?通过修改配置文件
我们在安装mysql的时候将配置文件夹映射到了本机
~/software/database/master-db/config:/etc/mysql/conf.d
所以只要在~/software/database/master-db/config
加个配置文件myconf.cnf
即可,内容如下
~
是我mac的home目录符号,window的小伙伴不要懵逼,这块在window你就当它对应你的C盘好了
[client]
# Default is Latin1, if you need UTF-8 set this (also in server section)
default-character-set=utf8
[mysqld]
[mariadbd]
#打开binlog
log_bin=ON
#binlog保存位置
log-bin=/var/lib/mysql/binlog
#binlog格式
binlog_format=mixed
配置完后,重启mariadb-master
容器
进入容器查看结果:
docker exec -u 0 -it mariadb-master /bin/bash
mysql -uroot -proot
MariaDB [(none)]> show variables like '%log_bin%';
+---------------------------------+-----------------------------+
| Variable_name | Value |
+---------------------------------+-----------------------------+
| log_bin | ON |
| log_bin_basename | /var/lib/mysql/binlog |
| log_bin_compress | OFF |
| log_bin_compress_min_len | 256 |
| log_bin_index | /var/lib/mysql/binlog.index |
| log_bin_trust_function_creators | OFF |
| sql_log_bin | ON |
+---------------------------------+-----------------------------+
可见binlog已经开启了。
将下面的配置加到myconf.cnf
中,重启容器。
#mysql 服务ID, 保证整个集群中唯一,范围:1到2的32次方-1
server-id=1
#0读写,1只读
read-only=0
#忽略的数据库
#binlog-ignore-db=mysql
#只同步下面的数据库
#binlog-do-db=xxxx
打开mysql客户端,执行下面的语句
#创建ss007用户
#CREATE USER 'ss007'@'%' IDENTIFIED WITH mysql_native_password BY 'Ss007@123456';
CREATE USER 'ss007'@'%' IDENTIFIED BY 'Ss007@123456';
#授予'ss007'@'%' 主从复制的权限
GRANT REPLICATION SLAVE ON *.* TO 'ss007'@'%';
@'%'
表示该用户可以从任意主机来访问。
*.*
表示此用户可以复制主库的所有数据,包括数据库,表等
show master status;
输出:
+---------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| binlog.000001 | 647 | | |
+---------------+----------+--------------+------------------+
上面展示了当前binlog文件(binlog.000001
)以及其当前行数(647),我们的从库就是从这个点开始复制。
至此,主库就配置好了。
在从库的配置文件中添加下面的配置,后重启容器
[mariadbd]
#配置serverid
server-id=2
#只允许读 0:读写,1:只读
read-only=1
进去mysql客户端执行如下语句
CHANGE MASTER TO MASTER_HOST='172.172.0.10',MASTER_USER='ss007',MASTER_PASSWORD='Ss007@123456', MASTER_LOG_FILE='binlog.000001',MASTER_LOG_POS=647;
MASTER_LOG_FILE : 从主库查询到的那个当前的binlog文件
MASTER_LOG_POS:从主库查询到的那个当前的binlog具体的位置
进去mysql客户端执行如下语句
start slave;
使用如下命令查看是否成功
show slave status;
结果:
MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.172.0.10
Master_User: ss007
Master_Port: 3306
Master_Log_File: binlog.000001
Read_Master_Log_Pos: 647
Relay_Log_File: mysqld-relay-bin.000002
Relay_Log_Pos: 552
Relay_Master_Log_File: binlog.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Exec_Master_Log_Pos: 647
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
...
上面我摘了一些状态,一看就明白了。我们关键是看下面这两个线程是不是正常运行着就ok。
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
至此从库也配置好了。
我们来验证一下我们的主从架构是否正常工作。
在主库里面来修改数据,看下从库会不会同步。
MariaDB [(none)]> show DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
ss007_01
并创建一张表student
CREATE DATABASE ss007_01;
USE ss007_01;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '',
`age` int(11) NOT NULL DEFAULT 18 ,
`create_time` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp() ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4
进入从库的mysql客户端:
MariaDB [(none)]> show DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| ss007_01 |
| sys |
+--------------------+
可见ss001_01
已经同步过来了,我们再看下它里面是否存在主库建立的表student
MariaDB [(none)]> use ss007_01;
MariaDB [ss007_01]> show tables;
+--------------------+
| Tables_in_ss007_01 |
+--------------------+
| student |
+--------------------+
可见表也同步过来了。
我们还可以在主库的student表里面插入一条数据,看看是否可同步过来:
MariaDB [ss007_01]> select * from student;
+----+----------+-----+---------------------+
| id | name | age | create_time |
+----+----------+-----+---------------------+
| 1 | Dog2Wang | 30 | 2022-08-06 14:32:31 |
+----+----------+-----+---------------------+
弄懂了一主一从,那么一主多从,多主多从都是一样的做法。
至此mysql的主从搭建就完成了,你跟着做绝对可以成功,因为每一步都是作者经过实际验证的。小伙子们注意点赞收藏,心中不慌…