秒懂MySql之从零搭建主从架构

Posted ShuSheng007

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了秒懂MySql之从零搭建主从架构相关的知识,希望对你有一定的参考价值。

[版权申明] 非商业目的注明出处可自由转载
出自:shusheng007

文章目录

概述

今天我们来聊一下软件系统架构中数据库侧的一些常用设计和具体搭建吧,小朋友如果是做软件开发的现在其实也应该对运维这块有一些了解的,软件开发方法论的发展,特别是敏捷开发的发展竟然不知不觉使得开发与运维都紧密的融为一起了,俗称DevOps(DevOps is a set of practices that combines software development (Dev) and IT operations (Ops))。近年来微服务的发展更使得DevOps成为不可获取的一个角色。

简介

数据库在一个软件系统的重要程度我们就不多说了。我们今天就简单聊聊为什么要搞主从架构?如何搞?

什么是主从架构

最开始的时候我们对软件系统的要求很低,但后来要求越来越高,对数据库的要求相应也就变的越来越多:兄弟我希望你7X24小时稳定运行50年,兄弟最近流量暴增了你的给抗住啊,兄弟机房断电你也不能给我丢数据啊,兄弟机房断电我还是想让你能正常工作,兄弟… 数据库兄弟怒了:我R你LL…

你看就是由于要求越来越多,单机数据库根本就不能满足这些要求,所以就出来很多架构方式来解决这些问题,今天说的主从架构就是非常经典和有效的一种。

软件架构的思想其实非常朴素:你一个人是不是搞不定?那就再给你加几个! 特别是在解决系统高可用上,在单机可用性已经无法提高了的情况下,就剩下冗余一招。

主从架构的意思就是多个数据库在一起干活,但是被人为的分了个主次,他们之间的数据结构以及存储的数据完全一样。主从架构有很多种,一主一从,一主多从,多主多从,都差不多,只要理解了一主一从就可以了,其他的都是变种。

主从的优势

  • 提高了系统的可用性

现在有两份一模一样的数据,主库出问题,从库就可以顶上。

  • 提供了系统的性能

现在有两份一模一样的数据,主库负责写,从库就负责读
在备份数据的时候可以从从库备份,这样就不需需要锁主库的表,那么系统的性能会提升

mysql主从复制原理


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的,所以首先要确保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'@'%';

@'%' 表示该用户可以从任意主机来访问。
*.* 表示此用户可以复制主库的所有数据,包括数据库,表等

  • 查看binlog坐标
show master status;

输出:

+---------------+----------+--------------+------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| binlog.000001 |      647 |              |                  |
+---------------+----------+--------------+------------------+

上面展示了当前binlog文件(binlog.000001)以及其当前行数(647),我们的从库就是从这个点开始复制。

至此,主库就配置好了。

从库配置

  • 配置服务器id以及读写状态

在从库的配置文件中添加下面的配置,后重启容器

[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

至此从库也配置好了。

验证

我们来验证一下我们的主从架构是否正常工作。

在主库里面来修改数据,看下从库会不会同步。

  1. 查看一下从库当前的数据库
MariaDB [(none)]> show DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
  1. 在主库中添加一个数据库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 
  1. 查看一下从库是否已经同步了刚才创建数据库和表

进入从库的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 |
+----+----------+-----+---------------------+

技术要点总结

  • 开binlog
  • 配置服务器id及读写属性
  • 创建从库连接的用户并授予复制权限
  • 记录当前binlog日志坐标

  • 配置服务器id及读写属性
  • 连接主库
  • 启动复制

弄懂了一主一从,那么一主多从,多主多从都是一样的做法。

总结

至此mysql的主从搭建就完成了,你跟着做绝对可以成功,因为每一步都是作者经过实际验证的。小伙子们注意点赞收藏,心中不慌…

以上是关于秒懂MySql之从零搭建主从架构的主要内容,如果未能解决你的问题,请参考以下文章

vue项目级路由架构带你从零搭建 [新手秒懂]

MySQL主从复制原理和使用

从零搭建mysql的主从复制

随手记:mysql集群搭建之主从配置

Android游戏编程之从零开始pdf

Android游戏编程之从零开始pdf