利用 Docker 快速實現 MySQL binlog 主從備份

Intro

主從備份是容災的一種手段, 模擬主從備份可以有下面幾種方式:

  • 不差錢方式, 買幾臺主機測試, 這種方式也比較接近線上環境.
  • 通過創建幾臺虛擬機來模擬. 這種方式對本機性能要求相對較高. 相對不差錢可以選這種方式, 但安裝幾臺虛擬機也不是一件效率高的事.
  • 在一臺主機上創建多個數據庫實例. 缺點是環境無法隔離, 需要額外加多一些配置
  • 通過 Docker-compose 直接創建多個數據庫容器, 暴露端口訪問即可.

binlog 是MySQL數據庫的二進制日誌,用於記錄用戶對數據庫操作的SQL語句(不包括 SELECT),可以在配置文件開啓,也可以在 MySQL 客戶端開啓. 可以在客戶端鍵入show plugins; 查看 binlog 是否已安裝開啓( Active )

+----------------------------+----------+--------------------+---------+---------+
| Name                       | Status   | Type               | Library | License |
+----------------------------+----------+--------------------+---------+---------+
| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL    | GPL     |
| sha256_password            | ACTIVE   | AUTHENTICATION     | NULL    | GPL     |
| PERFORMANCE_SCHEMA         | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| CSV                        | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |

環境準備

0.1 測試環境

必須安裝有 dockerdocker-compose 用於構建容器環境, 本測試在 Ubuntu 16.04 及下列版本下進行, 使用其他版本可能會有使用差異.

docker-compose 1.25.4
docker 19.03.6

有關安裝的細節, 請搜索相關關鍵詞, 或者直接根據 Docker 官方文檔 進行安裝

0.2 Docker 加速

由於衆所周知的原因, 拉取鏡像時可能會很慢, 推薦設置國內的鏡像源進行加速
Ubuntu/Centos/Debian 下修改或創建此文件 /etc/docker/daemon.json
示例文件內容如下, 可以自由添加鏡像源. 鏡像源有可能會宕機, 鏡像源測試請參閱docker-registry-cn-mirror-test

{
    "registry-mirrors":[
        "https://dockerhub.azk8s.cn",
        "https://docker.mirrors.ustc.edu.cn",
        "https://reg-mirror.qiniu.com"
    ]
  }

一. Docker 文件準備

1.1 文件目錄

  • Dockerfile 是一個文本文件, 只需要 touch Dockerfile 創建即可.
  • docker-compose.yml 是用於運行多個 Docker 容器的配置文件, 使用 yaml 語言.

如只准備測試一主一從, 那麼移除 slave02 目錄, 添加多個從服務器則相應增加文件夾.

├── docker-compose.yml
├── master
│   ├── Dockerfile
│   └── my.cnf
├── slave01
│   ├── Dockerfile
│   └── my.cnf
└── slave02
    ├── Dockerfile
    └── my.cnf

1.2 docker-compose 文件及解釋

  • environment
    在創建 MySQL 密碼時, 測試用途用 root 沒問題, 其他時候記得創建複雜密碼, 至少可以使用 uuidgen 命令生成.
    支持在創建時同時創建一個數據庫, 創建多個或進行其他數據初始化, 建議依靠外部 SQL 文件.
  • links
    這個不是推薦的配置方式, 不利於擴展, 但在此處我們只是用於測試. 可以自由添加你要的從服務器名稱, 用於容器間的連接. 更推薦配置 networks
  • ports
    冒號左邊爲暴露的端口, 右邊爲容器內部的端口號, 在不配置網絡的情況下(此時默認爲 127.0.0.1), 爲了避免端口衝突, 必須使暴露的端口號不一致.
version: '2' 
services:
  mysql-master: 
    build:
      context: ./                      # 聲明構建的文件夾
      dockerfile: master/Dockerfile    # 聲明 Docker 文件目錄
    environment: # 環境變量, 支持數組或列表方式
      - "MYSQL_ROOT_PASSWORD=root"
      - "MYSQL_DATABASE=db0" # 初始創建的數據庫
    links:
      - mysql-slave01
      - mysql-slave02
    ports:
      - "33065:3306" 
    restart: always
    hostname: mysql-master

  mysql-slave01:
    build:
      context: ./
      dockerfile: slave/Dockerfile
    environment:
      - "MYSQL_ROOT_PASSWORD=6954D5F0"
      - "MYSQL_DATABASE=db0"
    ports:
      - "33066:3306"
    restart: always
    hostname: mysql-slave01

  mysql-slave02:
    build:
      context: ./
      dockerfile: slave02/Dockerfile
    environment:
      - "MYSQL_ROOT_PASSWORD=6954D5F0"
      - "MYSQL_DATABASE=db0"
    ports:
      - "33067:3306"
    restart: always
    hostname: mysql-slave02

1.3 Dockerfile 文件及解釋

  • FROM指定了基礎鏡像, 可以根據需求更改 MySQL 鏡像版本
  • COPY
    將源文件複製到目標容器, 從服務器相應地創建 Dockerfile, 修改源文件位置. 也可以使用 ADD 這個更高級的複製命令, 但沒必要.
FROM mysql:5.7.17
COPY ./master/my.cnf /etc/mysql/my.cnf

二. MySQL 配置文件準備

2.1 Master 節點配置

# master/my.cnf
[mysqld]
## 設置server_id,注意要唯一
server_id=100  
## 複製過濾:也就是指定哪個數據庫不用同步(mysql庫一般不同步)
binlog-ignore-db=mysql  
## 開啓二進制日誌功能,可以隨便取,最好有含義
log-bin=replicas-mysql-bin  
## 爲每個session分配的內存,在事務過程中用來存儲二進制日誌的緩存
binlog_cache_size=1M  
## 主從複製的格式(mixed,statement,row,默認格式是statement)
binlog_format=mixed  
## 二進制日誌自動刪除/過期的天數。默認值爲0,表示不自動刪除。
expire_logs_days=7  
## 跳過主從複製中遇到的所有錯誤或指定類型的錯誤,避免slave端複製中斷。
## 如:1062錯誤是指一些主鍵重複,1032錯誤是因爲主從數據庫數據不一致
slave_skip_errors=1062

2.2 Slave 節點配置

Slave 節點的配置與 Master 相似, 但每個節點的 server_id 必須不同, 此外增加了 relay_log 中繼日誌的配置以及只讀的設置

[mysqld]
## 設置server_id,注意要唯一
server_id=101 
# ... 省略配置
## relay_log配置中繼日誌
relay_log=replicas-mysql-relay-bin  
## log_slave_updates表示slave將複製事件寫進自己的二進制日誌
log_slave_updates=1  
## 防止改變數據(除了特殊的線程)
read_only=1 

三. 構建容器並運行

進入有 docker-compose.yml 的目錄, 執行以下命令
該命令十分強大,它將嘗試自動完成包括構建鏡像,(重新)創建服務,啓動服務,並關聯服務相關容器的一系列操作, -d 表示後臺運行鏡像.

docker-compose up -d

之後執行docker ps 查看正在運行的鏡像, 如果是一主一從, 可以看到至少兩個正在運行的鏡像

$ docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                     NAMES
ef799b7d8cf8        mstest_mysql-master   "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes        0.0.0.0:33065->3306/tcp   mstest_mysql-master_1
9d7ea93b7a85        mstest_mysql-slave    "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes        0.0.0.0:33066->3306/tcp   mstest_mysql-slave_1

鍵入 docker exec -it [name/id] /bin/bash 進入容器, 可以是容器名稱也可以是容器 id, 如下方示例:

docker exec -it mysql-master_1 /bin/bash

四. 配置主從

可以直接進入容器再進入 mysql 配置, 也可以不進入, 直接在終端鍵入下方命令, port 就是 docker-compose.xml 設置的端口號, 例如前面 master33065

mysql -uroot -p -P[port] -h127.0.0.1

4.1 獲取主節點狀態

鍵入 show master status; 記住當前 File 的名稱和 Position, 這是從節點進行 binlog 複製找點用的.

mysql> show master status
    -> ;
+---------------------------+----------+--------------+------------------+-------------------+
| File                      | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------------------+----------+--------------+------------------+-------------------+
| replicas-mysql-bin.000003 |      154 |              | mysql            |                   |
+---------------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec

4.2 開啓從節點複製

這裏設置複製主節點的相關信息, 在前面文件用的是 root 密碼,因此這裏也是 root 用戶, 將MASTER_LOG_FILEMASTER_LOG_POS 填上相應信息

CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='root', MASTER_PASSWORD='root', MASTER_LOG_FILE='replicas-mysql-bin.000003', MASTER_LOG_POS=154;

接着啓動複製.

  • 鍵入start slave;
  • 鍵入show slave status\G;查看是否啓用成功, 關注Slave_IO_RunningSlave_SQL_Running 是否爲 Yes
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G;
            ...
            Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
            ...

同樣地, 如果有多個 Slave 節點, 就這一步多做幾次.

4.3 驗證是否成功

回到 Master 節點, 創建一個數據庫 或者 往已經創建好的 db0 寫入數據,

mysql> create database db1;

回到 Slave 節點, 查看兩邊是否同步.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db0                |
| db1                |

五. 後話——另一種主從複製 GTID

GTID 自 MySQL 5.6.MySQL 5.6.5 便引入了,中文叫全局事務 ID(Global Transaction ID)

在本文的基於二進制日誌複製中,從庫需要告知主庫要從哪個偏移量(就是 Log File 的 Position)進行增量同步,如果指定錯誤會造成數據的遺漏,從而造成數據的不一致。

但有了 GTID,發生主備切換時,MySQL 的其它從庫可以自動在新主庫上找到正確的複製位置,這大大簡化了複雜複製拓撲下集羣的維護,也減少了人爲設置複製位置發生誤操作的風險。另外,基於 GTID 的複製還可以忽略已經執行過的事務

參考

  1. Docker Compose搭建MySQL主從複製集羣
  2. GTID Concept - MySQL
  3. Docker 從入門到實踐 - Compose 命令說明

公衆號:程序員的碎碎念
Github:github.com/FesonX

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章