MySQL5.7安裝+基于GTID主從復制+并行復制+增強半同步復制+讀寫分離+M-S-S架構(聯級復制)
實驗環境:
Centos7.2
角色
主機IP
server_id
數據狀態
Proxysql
192.168.148.62
null
無
Master
192.168.148.62
1
剛安裝的全新MySQL實例
Slave1
192.168.148.61
2
剛安裝的全新MySQL實例
Slave2
192.168.148.64
3
剛安裝的全新MySQL實例
一、安裝最新版本Mysql5.7
-
下載并安裝MySQL官方的 Yum Repository,并啟動mysql
[root@localhost ~]# wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
[root@localhost ~]# yum -y install mysql57-community-release-el7-10.noarch.rpm
[root@localhost ~]# yum -y install mysql-community-server
[root@localhost ~]# systemctl start mysqld.service
[root@localhost ~]# systemctl status mysqld.service
-
查看yum安裝后的初始root密碼
[root@localhost ~]# grep "password" /var/log/mysqld.log
2018-07-09T06:57:12.533269Z 1 [Note] A temporary password is generated for root@localhost: H9VtyDlad!T;
-
如下命令首次進入數據庫并修改密碼:
[root@localhost ~]# mysql -uroot -pH9VtyDlad!T
mysql> ALTER USER 'root'@'%' IDENTIFIED BY '123456';
說明:MySQL默認必須修改密碼之后才能操作數據庫,并滿足密碼復雜度要求
%' 所有情況都能訪問
‘localhost’ 本機才能訪問
’111.222.33.44‘ 指定 ip 才能訪問
至此mysql已安裝完成。
二、基于GTID主從同步
-
gtid基本概念
傳統的基于binlog position復制的方式有個嚴重的缺點:如果slave連接master時指定的binlog文件錯誤或者position錯誤,會造成遺漏或者重復,很多時候前后數據是有依賴性的,這樣就會出錯而導致數據不一致。
從MYSQL5.6開始,mysql開始支持GTID復制。GTID的全稱是global transaction id,表示的是全局事務ID。GTID的分配方式為uuid:trans_id,其中:
- uuid是每個mysql服務器都唯一的,記錄在$datadir/auto.cnf中。如果復制結構中,任意兩臺服務器uuid重復的話(比如直接冷備份時,auto.conf中的內容是一致的),在啟動復制功能的時候會報錯。這時可以刪除auto.conf文件再重啟mysqld。
基于gtid復制的好處
從上面可以看出,gtid復制的優點大致有:
保證同一個事務在某slave上絕對只執行一次,沒有執行過的gtid事務總是會被執行。
不用像傳統復制那樣保證binlog的坐標準確,因為根本不需要binlog以及坐標。
故障轉移到新的master的時候很方便,簡化了很多任務。
很容易判斷master和slave的數據是否一致。只要master上提交的事務在slave上也提交了,那么一定是一致的。
當然,MySQL提供了選項可以控制跳過某些gtid事務,防止slave第一次啟動復制時執行master上的所有事務而導致耗時過久。
雖然對于row-based和statement-based的格式都能進行gtid復制,但建議采用row-based格式。
-
master配置
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
server-id=1 ##服務器標識
binlog_format=row
log-bin=mysql-bin ##開啟二進制日志
gtid_mode=ON ## 開啟gtid模式
enforce-gtid-consistency=true ## 強制gtid復制
-
保存退出后重啟mysql。
[root@localhost ~]# systemctl restart mysqld
-
進入數據庫并查看Master狀態
[root@localhost ~]# mysql -uroot -p
Enter password:
mysql>
mysql> show master status ; ##查看master狀態
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
-
授權slave用戶,并刷新權限
mysql> grant REPLICATION SLAVE ON *.* to otter@'192.168.148.%' identified by ' yourpasswd ' ;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql>flush privileges;
-
再次查看master狀態
mysql> show master status;
+------------------+----------+--------------+------------------+----------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+----------------------------------------+
| mysql-bin.000003 | 442 | | | 4e552c02-8345-11e8-b571-000c294897b5:1 |
+------------------+----------+--------------+------------------+----------------------------------------+
1 row in set (0.00 sec)
-
slave1配置
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
server-id=2 ##服務器標識
binlog_format=row
gtid_mode=ON ## 開啟gtid模式
enforce-gtid-consistency=true ## 強制gtid復制
-
保存退出并重啟mysql
[root@localhost mysql]# systemctl restart mysqld
-
進入數據庫
[root@localhost ~]# mysql -uroot -p
mysql>change master to master_host='192.168.148.62', master_user='otter', master_password='yourpasswd', master_auto_position=1; mysql> start slave; ##開啟slave mysql> show slave status\G; ##查看狀態
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.148.62
Master_User: otter
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 1373
Relay_Log_File: localhost-relay-bin.000004
Relay_Log_Pos: 360
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
三、測試:
-
master新建個數據庫test, slave會自動同步
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> use test;
Database changed
mysql> create table usertable (
-> username varchar(10) not null,
-> password varchar(16) not null);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into usertable values('mark','westos');
Query OK, 1 row affected (0.06 sec)
mysql> insert into usertable values('harry','redhat');
Query OK, 1 row affected (0.00 sec)
mysql> select * from usertable;
+----------+----------+
| username | password |
+----------+----------+
| mark | westos |
| harry | redhat |
+----------+----------+
2 rows in set (0.00 sec)
-
slave1自動同步
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
| xuehui |
+--------------------+
6 rows in set (0.00 sec)
mysql> use test;
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| usertable |
+----------------+
1 row in set (0.00 sec)
mysql> select * from usertable;
+----------+----------+
| username | password |
+----------+----------+
| mark | westos |
| harry | redhat |
+----------+----------+
2 rows in set (0.00 sec)
四、slave1并行復制
編輯slave1配置文件
[root@localhost mysql]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
server-id=2 ##服務器標識
binlog_format=row
gtid_mode=ON ## 開啟gtid模式
enforce-gtid-consistency=true ## 強制gtid復制
slave-parallel-type=LOGICAL_CLOCK ##開啟邏輯時鐘的復制
slave-parallel-workers=4 ##最大線程16
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON
-
保存退出并重啟mysql
[root@localhost mysql]# systemctl restart mysqld
-
主庫master配置binlog_group_commit
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
server-id=1 ##服務器標識
binlog_format=row
log-bin=mysql-bin ##開啟二進制日志
gtid_mode=ON ## 開啟gtid模式
enforce-gtid-consistency=true ## 強制gtid復制
rpl_semi_sync_master_enabled = 1
plugin-load=rpl_semi_sync_master=semisync_master.so
rpl_semi_sync_master_timeout = 1000 # 1s
##不配置binlog_group_commit從庫無法做到基于事物的并行復制。
binlog_group_commit_sync_delay = 100
binlog_group_commit_sync_no_delay_count = 10
##為了數據安全再配置
sync_binlog=1
innodb_flush_log_at_trx_commit=1
-
保存退出并重啟mysql
[root@localhost mysql]# systemctl restart mysqld
-
進入slave1數據庫,查看優化項
mysql> use mysql;
Database changed
mysql> show tables;
|....................................|
| slave_worker_info |
-
查看4個線程
mysql> select * from slave_worker_info;
+----+----------------+---------------+-----------------+----------------+---------------------------+--------------------------+----------------------------+---------------------------+------------------+-----------------------+------------------------------------------------------------------+--------------+
| Id | Relay_log_name | Relay_log_pos | Master_log_name | Master_log_pos | Checkpoint_relay_log_name | Checkpoint_relay_log_pos | Checkpoint_master_log_name | Checkpoint_master_log_pos | Checkpoint_seqno | Checkpoint_group_size | Checkpoint_group_bitmap | Channel_name |
+----+----------------+---------------+-----------------+----------------+---------------------------+--------------------------+----------------------------+---------------------------+------------------+-----------------------+------------------------------------------------------------------+--------------+
| 1 | | 0 | | 0 | | 0 | | 0 | 0 | 64 | | |
| 2 | | 0 | | 0 | | 0 | | 0 | 0 | 64 | | |
| 3 | | 0 | | 0 | | 0 | | 0 | 0 | 64 | | |
| 4 | | 0 | | 0 | | 0 | | 0 | 0 | 64 | | |
+----+----------------+---------------+-----------------+----------------+---------------------------+--------------------------+----------------------------+---------------------------+------------------+-----------------------+------------------------------------------------------------------+--------------+
4 rows in set (0.00 sec)
五、增強半同步
半同步復制
默認情況下,MySQL的復制是異步的,master將新生成的binlog發送給各slave后,無需等待slave的ack回復(slave將接收到的binlog寫進relay log后才會回復ack),直接就認為這次DDL/DML成功了。半同步復制(semi-synchronous replication)是指master在將新生成的binlog發送給各slave時,只需等待一個(默認)slave返回的ack信息就返回成功。
MySQL 5.7對半同步復制作了大改進,新增了一個master線程。在MySQL 5.7以前,master上的binlog dump線程負責兩件事:dump日志給slave的io_thread;接收來自slave的ack消息。它們是串行方式工作的。在MySQL 5.7中,新增了一個專門負責接受ack消息的線程ack collector thread。這樣master上有兩個線程獨立工作,可以同時發送binlog到slave和接收slave的ack。還新增了幾個變量,其中最重要的是 rpl_semi_sync_master_wait_point ,它使得MySQL半同步復制有兩種工作模型。解釋如下。
半同步復制的兩種類型
從MySQL 5.7.2開始,MySQL支持兩種類型的半同步復制。這兩種類型由變量 rpl_semi_sync_master_wait_point (MySQL 5.7.2之前沒有該變量)控制,它有兩種值:AFTER_SYNC和AFTER_COMMIT。在MySQL 5.7.2之后,默認值為AFTER_SYNC,在此版本之前,等價的類型為AFTER_COMMIT。這個變量控制的是master何時提交、何時接收ack以及何時回復成功信息給客戶端的時間點。
- AFTER_SYNC模式:master將新的事務寫進binlog(buffer),然后發送給slave,再sync到自己的binlog file(disk)。之后才允許接收slave的ack回復,接收到ack之后才會提交事務,并返回成功信息給客戶端。
- AFTER_COMMIT模式:master將新的事務寫進binlog(buffer),然后發送給slave,再sync到自己的binlog file(disk),然后直接提交事務。之后才允許接收slave的ack回復,然后再返回成功信息給客戶端。
畫圖理解就很清晰。(前提:已經設置了sync_binlog=1,否則binlog刷盤時間由操作系統決定)
再來分析下這兩種模式的優缺點。
- AFTER_SYNC:
-
- 對于所有客戶端來說,它們看到的數據是一樣的,因為它們看到的數據都是在接收到slave的ack后提交后的數據。
- 這種模式下,如果master突然故障,不會丟失數據,因為所有成功的事務都已經寫進slave的relay log中了,slave的數據是最新的。
- AFTER_COMMIT:
-
- 不同客戶端看到的數據可能是不一樣的。對于發起事務請求的那個客戶端,它只有在master提交事務且收到slave的ack后才能看到提交的數據。但對于那些非本次事務的請求客戶端,它們在master提交后就能看到提交后的數據,這時候master可能還沒收到slave的ack。
- 如果master收到ack回復前,slave和master都故障了,那么將丟失這個事務中的數據。
在MySQL 5.7.2之前,等價的模式是 AFTER_COMMIT ,在此版本之后,默認的模式為 AFTER_SYNC ,該模式能最大程度地保證數據安全性,且性能上并不比 AFTER_COMMIT 差。
-
master與Slave命令行加載模塊
master加載
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.05 sec)
mysql> show plugins;
+----------------------------+----------+--------------------+----------------------+---------+
| Name | Status | Type | Library | License |
+----------------------------+----------+--------------------+----------------------+---------+
| binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |
| mysql_native_password | ACTIVE | AUTHENTICATION | NULL | GPL |
|。。。。。。。。。。。。。。。。。。。。。。。。。。。。。|
| validate_password | ACTIVE | VALIDATE PASSWORD | validate_password.so | GPL |
| rpl_semi_sync_master | ACTIVE | REPLICATION | semisync_master.so | GPL |
+----------------------------+----------+--------------------+----------------------+---------+
46 rows in set (0.00 sec)
查看加載模塊信息
mysql> show variables like '%rpl_semi%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | OFF |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.01 sec)
mysql> set global rpl_semi_sync_master_enabled=1; ##global全局 啟動半同步
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like '%rpl_semi%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.01 sec)
修改半同步默認超時時間
mysql> set global rpl_semi_sync_master_timeout = 1000;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like '%rpl_semi%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 1000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.01 sec)
########################## 以上的啟動方式是在命令行操作 ########################################
slave1加載模塊
mysql> install plugin rpl_semi_sync_slave SONAME 'semisync_slave.so'; ##加載slave模塊
mysql> set global rpl_semi_sync_slave_enabled=1; ##開啟slave模塊
mysql> show variables like '%rpl_semi%'; ##查看信息
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | ON |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
2 rows in set (0.01 sec)
mysql> STOP SLAVE IO_THREAD; ##關閉slaveIO線程
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 8
Current database: *** NONE ***
Query OK, 0 rows affected (0.01 sec)
mysql> START SLAVE IO_THREAD; ##開啟slaveIO線程
Query OK, 0 rows affected (0.00 sec)
mysql> show status like 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
1 row in set (0.00 sec)
########################## 以上的啟動方式是在命令行操作 ########################################
-
配置文件中加載。
主Master:配置文件里加載semisync_master.so
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
server-id=1 ##服務器標識
binlog_format=row
log-bin=mysql-bin ##開啟二進制日志
gtid_mode=ON
enforce-gtid-consistency=true
plugin-load=rpl_semi_sync_master=semisync_master.so
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_master_timeout = 1000 # 1s
保存退出并重啟mysql
[root@localhost mysql]# systemctl restart mysqld
Slave1: 配置文件里加載semisync_slave.so,并開啟bin-log日志
[root@localhost mysql]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
server-id=2 ##服務器標識
binlog_format=row
gtid_mode=ON ## 開啟gtid模式
log-bin=mysql-bin-slave1 ##開啟bin-log日志
log-slave-updates=ON
enforce-gtid-consistency=true ## 強制gtid復制
slave-parallel-type=LOGICAL_CLOCK ##開啟邏輯時鐘的復制
slave-parallel-workers=4 ##最大線程16
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON
plugin-load=rpl_semi_sync_slave=semisync_slave.so
rpl_semi_sync_slave_enabled=1
保存退出并重啟mysql
[root@localhost mysql]# systemctl restart mysqld
授權:
mysql> grant REPLICATION SLAVE ON *.* to otter@'192.168.148.%' identified by '!tp!gNp667aPT';
Query OK, 0 rows affected, 1 warning (0.00 sec)
刷新權限
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
再加一臺slave2
slave2:配置server-id,開啟gtid
在slave2上配置server-id,開啟gtid
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
server-id=3 ##服務器標識
binlog_format=row
gtid_mode=ON ## 開啟gtid模式
enforce-gtid-consistency=true ## 強制gtid復制
保存并退出,重啟mysql。
-
slave1使用mysqldump全備份數據庫傳給slave2
-
在slave2上指定master為slave1
mysql>change master to master_host='192.168.148.61',
master_user='otter',
master_password='!tp!gNp667aPT',
master_auto_position=1;
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 192.168.148.61
Master_User: otter
Master_Port: 3306
Connect_Retry: 60
Master_Log_File:
Read_Master_Log_Pos: 4
Relay_Log_File: localhost-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File:
Slave_IO_Running: No
Slave_SQL_Running: Yes
##查看狀態發現有報錯:Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'
-
解決方法:
- 在slave1上進行mysqldump整庫全備份,mysqldump -uroot -p密碼 -A >all.sql
- 然后打開all.sql我們可以看到如下語句:
[root@localhost ~]# more all.sql
-- MySQL dump 10.13 Distrib 5.7.22, for Linux (x86_64)
--
-- Host: localhost Database:
-- ------------------------------------------------------
-- Server version 5.7.22-log
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET @@SESSION.SQL_LOG_BIN= 0;
--
-- GTID state at the beginning of the backup
--
SET @@GLOBAL.GTID_PURGED='4cfd948e-88c8-11e8-a94a-000c29da1af6:1-2,
4e552c02-8345-11e8-b571-000c294897b5:1-487';
--
-- Current Database: `mysql`
--
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysql` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `mysql`;
--
-- Table structure for table `columns_priv`
--
DROP TABLE IF EXISTS `columns_priv`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
SET @@GLOBAL.GTID_PURGED='4cfd948e-88c8-11e8-a94a-000c29da1af6:1-2,
4e552c02-8345-11e8-b571-000c294897b5:1-487';
此值即為slave1上gtid_executed的值。
- 在slave2上恢復slave1的備份。
mysql> source all.sql
mysql> reset master; ##在slave上做一下reset master來清除gtid的一些信息。
Query OK, 0 rows affected (0.01 sec)
mysql> set global gtid_purged='4cfd948e-88c8-11e8-a94a-000c29da1af6:1-2,4e552c02-8345-11e8-b571-000c294897b5:1-487'; Query OK, 0 rows affected (0.00 sec)
mysql> show master status\G;
*************************** 1. row ***************************
File: mysql-bini-slave2.000001
Position: 154
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 4cfd948e-88c8-11e8-a94a-000c29da1af6:1-2,
4e552c02-8345-11e8-b571-000c294897b5:1-487
1 row in set (0.00 sec)
ERROR:
No query specified
mysql> start slave; ##啟動slave。
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G; ##查看狀態恢復正常。雙YES表示恢復正常。
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.148.61
Master_User: otter
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin-slave1.000001
Read_Master_Log_Pos: 1071
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 435
Relay_Master_Log_File: mysql-bin-slave1.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
master進行一條事務,slave1和slave2同步
master創建個數據庫 aaa
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| kkk |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> create database aaa;
Query OK, 1 row affected (0.01 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| aaa |
| kkk |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.00 sec)
slave1查看是否同步。
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| aaa |
| kkk |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.01 sec)
slave2查看是否同步。
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| aaa |
| kkk |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.00 sec)
七、讀寫分離
安裝MySQL中間件ProxySQL。
ProxySQL是用C++語言開發的,雖然也是一個輕量級產品,但性能很好(據測試,能處理千億級的數據),功能也足夠,能滿足中間件所需的絕大多數功能,包括:
- 最基本的讀/寫分離,且方式有多種。
- 可定制基于用戶、基于schema、基于語句的規則對SQL語句進行路由。換句話說,規則很靈活。基于schema和與語句級的規則,可以實現簡單的sharding。
- 可緩存查詢結果。雖然ProxySQL的緩存策略比較簡陋,但實現了基本的緩存功能,絕大多數時候也夠用了。此外,作者已經打算實現更豐富的緩存策略。
- 監控后端節點。ProxySQL可以監控后端節點的多個指標,包括:ProxySQL和后端的心跳信息,后端節點的read-only/read-write,slave和master的數據同步延遲性(replication lag)。
-
注意點:slave節點需要設置read_only=1。
# 以下是slave1的配置文件
server-id=2 ##服務器標識
binlog_format=row
log-bin=mysql-bin-slave1
log-slave-updates=ON
gtid_mode=ON ## 開啟gtid模式
enforce-gtid-consistency=true ## 強制gtid復制
slave-parallel-type=LOGICAL_CLOCK ##開啟邏輯時鐘的復制
slave-parallel-workers=4 ##最大線程16
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON
plugin-load=rpl_semi_sync_slave=semisync_slave.so
rpl_semi_sync_slave_enabled=1
read_only=1
# 以下是slave2的配置文件
server-id=3 ##服務器標識
log-bin=mysql-bini-slave2
binlog_format=row
gtid_mode=ON ## 開啟gtid模式
enforce-gtid-consistency=true ## 強制gtid復制
read_only=1
-
安裝ProxySQL
-
以 CentOS 7 的 rpm 包為例。
cat <<EOF | tee /etc/yum.repos.d/proxysql.repo
[proxysql_repo] name= ProxySQL
baseurl=http://repo.proxysql.com/ProxySQL/proxysql-1.4.x/centos/\$releasever
gpgcheck=1 gpgkey=http://repo.proxysql.com/ProxySQL/repo_pub_key
EOF
-
然后直接安裝即可。
yum -y install proxysql
[root@localhost ~]# systemctl start proxysql ##啟動 proxysql
[root@localhost ~]# systemctl status proxysql ##查看 proxysql狀態
Active: active (running) since 四 2018-07-19 18:04:48 CST; 40min ago
-
啟動后會監聽兩個端口,
默認為6032和6033。6032端口是ProxySQL的管理端口,6033是ProxySQL對外提供服務的端口。
[root@localhost ~]# netstat -tnlp
tcp 0 0 0.0.0.0:6032 0.0.0.0:* LISTEN 977/proxysql
tcp 0 0 0.0.0.0:6033 0.0.0.0:* LISTEN 977/proxysql
-
向ProxySQL中添加MySQL節點
然后使用mysql客戶端連接到ProxySQL的管理接口(admin interface),該接口的默認管理員用戶和密碼都是admin。
[root@localhost ~]# mysql -uadmin -padmin -P6032 -h127.0.0.1 --prompt 'admin> '
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 16
Server version: 5.5.30 (ProxySQL Admin Module)
admin> show databases;
+-----+---------------+-------------------------------------+
| seq | name | file |
+-----+---------------+-------------------------------------+
| 0 | main | |
| 2 | disk | /var/lib/proxysql/proxysql.db |
| 3 | stats | |
| 4 | monitor | |
| 5 | stats_history | /var/lib/proxysql/proxysql_stats.db |
+-----+---------------+-------------------------------------+
5 rows in set (0.00 sec)
ProxySQL提供了幾個庫,每個庫都有各自的意義。主要修改main和monitor數據庫中的表。
admin> show tables from main;
+--------------------------------------------+
| tables |
+--------------------------------------------+
| global_variables |
| mysql_collations |
| mysql_group_replication_hostgroups |
| mysql_query_rules |
| mysql_query_rules_fast_routing |
| mysql_replication_hostgroups |
| mysql_servers |
| mysql_users |
| proxysql_servers |
| runtime_checksums_values |
| runtime_global_variables |
| runtime_mysql_group_replication_hostgroups |
| runtime_mysql_query_rules |
| runtime_mysql_query_rules_fast_routing |
| runtime_mysql_replication_hostgroups |
| runtime_mysql_servers |
| runtime_mysql_users |
| runtime_proxysql_servers |
| runtime_scheduler |
| scheduler |
+--------------------------------------------+
20 rows in set (0.00 sec)
admin> show tables from monitor;
+------------------------------------+
| tables |
+------------------------------------+
| mysql_server_connect_log |
| mysql_server_group_replication_log |
| mysql_server_ping_log |
| mysql_server_read_only_log |
| mysql_server_replication_lag_log |
+------------------------------------+
5 rows in set (0.00 sec)
runtime_開頭的是運行時的配置,這些是不能修改的。要修改ProxySQL的配置,需要修改了非runtime_表,修改后必須執行LOAD ... TO RUNTIME才能加載到RUNTIME生效,執行save ... to disk才能將配置持久化保存到磁盤。
admin> insert into mysql_servers(hostgroup_id,hostname,port) values(10,'192.168.148.62',3306);
admin> insert into mysql_servers(hostgroup_id,hostname,port) values(10,'192.168.148.61',3306);
admin> insert into mysql_servers(hostgroup_id,hostname,port) values(10,'192.168.148.64',3306);
#使用insert語句添加主機到mysql_servers表中,其中:hostgroup_id 10 表示寫組,20表示讀組。
查看這3個節點是否插入成功,以及它們的狀態。
admin> select * from mysql_servers\G
*************************** 1. row ***************************
hostgroup_id: 10
hostname: 192.168.148.62
port: 3306
status: ONLINE
weight: 1
compression: 0
max_connections: 1000
max_replication_lag: 0
use_ssl: 0
max_latency_ms: 0
comment:
*************************** 2. row ***************************
hostgroup_id: 20
hostname: 192.168.148.61
port: 3306
status: ONLINE
weight: 1
compression: 0
max_connections: 1000
max_replication_lag: 0
use_ssl: 0
max_latency_ms: 0
comment:
*************************** 3. row ***************************
hostgroup_id: 20
hostname: 192.168.148.64
port: 3306
status: ONLINE
weight: 1
compression: 0
max_connections: 1000
max_replication_lag: 0
use_ssl: 0
max_latency_ms: 0
comment:
3 rows in set (0.00 sec)
修改后,加載到RUNTIME,并保存到disk。
admin> load mysql servers to runtime; admin> save mysql servers to disk;
-
監控后端MySQL節點
添加節點之后,還需要監控后端節點。對于后端是主從復制的環境來說,這是必須的,因為ProxySQL需要通過每個節點的read_only值來自動調整它們是屬于讀組還是寫組。
首先在后端master節點上創建一個用于監控的用戶名(只需在master上創建即可,因為會復制到slave上),這個用戶名只需具有USAGE權限即可。如果還需要監控復制結構中slave是否嚴重延遲于master(這個俗語叫做"拖后腿",術語叫做"replication lag"),則還需具備replication client權限。這里直接賦予這個權限。
# 在master上執行:
mysql> create user monitor@'192.168.148.%' identified by 'P@ssword1!'; mysql> grant replication client on *.* to monitor@'192.168.148.%';
#然后回到ProxySQL上配置監控。
admin> set mysql-monitor_username='monitor'; admin> set mysql-monitor_password='P@ssword1!';
#修改后,加載到RUNTIME,并保存到disk。
admin> load mysql variables to runtime; admin> save mysql variables to disk;
#驗證監控結果:ProxySQL監控模塊的指標都保存在monitor庫的log表中。
以下是連接是否正常的監控(對connect指標的監控):(在前面可能會有很多connect_error,這是因為沒有配置監控信息時的錯誤,配置后如果connect_error的結果為NULL則表示正常)
admin> select * from mysql_server_connect_log;
+----------------+------+------------------+-------------------------+---------------+
| hostname | port | time_start_us | connect_success_time_us | connect_error |
+----------------+------+------------------+-------------------------+---------------+
| 192.168.148.61 | 3306 | 1532003209576812 | 1113 | NULL |
| 192.168.148.62 | 3306 | 1532003209587641 | 428 | NULL |
| 192.168.148.64 | 3306 | 1532003209598596 | 6290 | NULL |
| 192.168.148.62 | 3306 | 1532003749593625 | 676 | NULL |
| 192.168.148.64 | 3306 | 1532003749604600 | 1459 | NULL |
+----------------+------+------------------+-------------------------+---------------+
30 rows in set (0.00 sec)
#以下是對心跳信息的監控(對ping指標的監控):
admin> select * from mysql_server_ping_log;
+----------------+------+------------------+----------------------+------------+
| hostname | port | time_start_us | ping_success_time_us | ping_error |
+----------------+------+------------------+----------------------+------------+
| 192.168.148.61 | 3306 | 1532003210786402 | 717 | NULL |
| 192.168.148.64 | 3306 | 1532003610811775 | 382 | NULL |
| 192.168.148.61 | 3306 | 1532003620807891 | 408 | NULL |
| 192.168.148.62 | 3306 | 1532003620809610 | 140 | NULL |
| 192.168.148.64 | 3306 | 1532003800821971 | 420 | NULL |
+----------------+------+------------------+----------------------+------------+
180 rows in set (0.00 sec)
#但是,read_only和replication_lag的監控日志都為空。
admin> select * from mysql_server_read_only_log;
Empty set (0.00 sec)
admin> select * from mysql_server_replication_lag_log;
Empty set (0.00 sec)
#例如,指定寫組的id為10,讀組的id為20。
admin> insert into mysql_replication_hostgroups values(10,20,1);
在該配置加載到RUNTIME生效之前,先查看下各mysql server所在的組。
admin> select hostgroup_id,hostname,port,status,weight from mysql_servers;
+--------------+----------------+------+--------+--------+
| hostgroup_id | hostname | port | status | weight |
+--------------+----------------+------+--------+--------+
| 10 | 192.168.148.62 | 3306 | ONLINE | 1 |
| 10 | 192.168.148.61 | 3306 | ONLINE | 1 |
| 10 | 192.168.148.64 | 3306 | ONLINE | 1 |
+--------------+----------------+------+--------+--------+
3 rows in set (0.00 sec)
#3個節點都在hostgroup_id=10的組中。
現在,將剛才mysql_replication_hostgroups表的修改加載到RUNTIME生效。
admin> load mysql servers to runtime;
admin> save mysql servers to disk;
一加載,Monitor模塊就會開始監控后端的read_only值,當監控到read_only值后,就會按照read_only的值將某些節點自動移動到讀/寫組。
例如,此處所有節點都在id=10的寫組,slave1和slave2都是slave,它們的read_only=1,這兩個節點將會移動到id=20的組。如果一開始這3節點都在id=20的讀組,那么移動的將是Master節點,會移動到id=10的寫組。
#看結果:
admin> select hostgroup_id,hostname,port,status,weight from mysql_servers;
+--------------+----------------+------+--------+--------+
| hostgroup_id | hostname | port | status | weight |
+--------------+----------------+------+--------+--------+
| 10 | 192.168.148.62 | 3306 | ONLINE | 1 |
| 20 | 192.168.148.61 | 3306 | ONLINE | 1 |
| 20 | 192.168.148.64 | 3306 | ONLINE | 1 |
+--------------+----------------+------+--------+--------+
3 rows in set (0.00 sec)
admin> select * from mysql_server_read_only_log;
+----------------+------+------------------+-----------------+-----------+--------+
| hostname | port | time_start_us | success_time_us | read_only | error |
+----------------+------+------------------+-----------------+-----------+--------+ |
192.168.148.64 | 3306 | 1532003708480193 | 1218 | 1 | NULL |
| 192.168.148.62 | 3306 | 1532003709979095 | 2369 | 0 | NULL |
| 192.168.148.61 | 3306 | 1532003709978587 | 3464 | 1 | NULL |
| 192.168.148.64 | 3306 | 1532003709981780 | 2562 | 1 | NULL |
| 192.168.148.61 | 3306 | 1532003711479179 | 2449 | 1 | NULL |
| 192.168.148.62 | 3306 | 1532003711479965 | 1918 | 0 | NULL |
+----------------+------+------------------+-----------------+-----------+--------+ |
-
配置mysql_users
上面的所有配置都是關于后端MySQL節點的,現在可以配置關于SQL語句的,包括:發送SQL語句的用戶、SQL語句的路由規則、SQL查詢的緩存、SQL語句的重寫等等。本小節是SQL請求所使用的用戶配置,例如root用戶。這要求我們需要先在后端MySQL節點添加好相關用戶。這里以root和sqlsender兩個用戶名為例。
#首先,在master節點上執行:(只需master執行即可,會復制給兩個slave)
mysql> grant all on *.* to root@'192.168.148.%' identified by 'passwd';
mysql> grant all on *.* to sqlsender@'192.168.148.%' identified by 'P@ssword1!';
#然后回到ProxySQL,配置mysql_users表,將剛才的兩個用戶添加到該表中。
admin> insert into mysql_users(username,password,default_hostgroup) values('root','passwd',10);
admin> insert into mysql_users(username,password,default_hostgroup) values('sqlsender','P@ssword1!',10);
admin> load mysql users to runtime; admin> save mysql users to disk;
mysql_users表有不少字段,最主要的三個字段為username、password和default_hostgroup:
- username:前端連接ProxySQL,以及ProxySQL將SQL語句路由給MySQL所使用的用戶名。
- password:用戶名對應的密碼。可以是明文密碼,也可以是hash密碼。如果想使用hash密碼,可以先在某個MySQL節點上執行select password(PASSWORD),然后將加密結果復制到該字段。
- default_hostgroup:該用戶名默認的路由目標。例如,指定root用戶的該字段值為10時,則使用root用戶發送的SQL語句默認情況下將路由到hostgroup_id=10組中的某個節點。
admin> select * from mysql_users\G
*************************** 1. row ***************************
username: root
password: passwd
active: 1
use_ssl: 0
default_hostgroup: 10
default_schema: NULL
schema_locked: 0
transaction_persistent: 1
fast_forward: 0
backend: 1
frontend: 1
max_connections: 10000
*************************** 2. row ***************************
username: sqlsender
password: P@ssword1!
active: 1
use_ssl: 0
default_hostgroup: 10
default_schema: NULL
schema_locked: 0
transaction_persistent: 1
fast_forward: 0
backend: 1
frontend: 1
max_connections: 10000
2 rows in set (0.00 sec)
雖然本文不詳細介紹mysql_users表,但上面標注了"注意本行"的兩個字段必須要引起注意。只有active=1的用戶才是有效的用戶。至于transaction_persistent字段,當它的值為1時,表示事務持久化:當某連接使用該用戶開啟了一個事務后,那么在事務提交/回滾之前,所有的語句都路由到同一個組中,避免語句分散到不同組。在以前的版本中,默認值為0,不知道從哪個版本開始,它的默認值為1。我們期望的值為1,所以在繼續下面的步驟之前,先查看下這個值,如果為0,則執行下面的語句修改為1。
admin> update mysql_users set transaction_persistent=1 where username='root';
admin> update mysql_users set transaction_persistent=1 where username='sqlsender';
admin> load mysql users to runtime;
admin> save mysql users to disk;
然后,另開一個終端,分別使用root用戶和sqlsender用戶測試下它們是否能路由到默認的hostgroup_id=10(它是一個寫組)讀、寫數據。
[root@s1 ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@server_id"
+-------------+
| @@server_id | +-------------+ | 110 |
+-------------+
[root@s1 ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "create database proxy_test"
[root@s1 ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "show databases;"
+--------------------+
| Database |
+--------------------+
| information_schema | | mysql | | performance_schema | | proxy_test | | sys |
+--------------------+
[root@s1 ~]# mysql -usqlsender -pP@ssword1! -P6033 -h127.0.0.1 -e '\ use proxy_test;\ create table t(id int);'
[root@s1 ~]# mysql -usqlsender -pP@ssword1! -P6033 -h127.0.0.1 -e 'show tables from proxy_test;'
+-------------------------+ |
Tables_in_proxy_test | +-------------------------+ | t |
+-------------------------+
-
5讀寫分離:配置路由規則
ProxySQL的路由規則非常靈活,可以基于用戶、基于schema以及基于每個語句實現路由規則的定制。本文作為入門文章,實現一個最簡單的語句級路由規則,從而實現讀寫分離。必須注意,這只是實驗,實際的路由規則絕不應該僅根據所謂的讀、寫操作進行分離,而是從各項指標中找出壓力大、執行頻繁的語句單獨寫規則、做緩存等等。和查詢規則有關的表有兩個:mysql_query_rules和mysql_query_rules_fast_routing,后者是前者的擴展表,1.4.7之后才支持該快速路由表。本文只介紹第一個表。插入兩個規則,目的是將select語句分離到hostgroup_id=20的讀組,但由于select語句中有一個特殊語句SELECT...FOR UPDATE它會申請寫鎖,所以應該路由到hostgroup_id=10的寫組。
admin>insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply) VALUES (1,1,'^SELECT.*FOR UPDATE$',10,1), (2,1,'^SELECT',20,1);
admin> load mysql query rules to runtime;
admin> save mysql query rules to disk;
select ... for update規則的rule_id必須要小于普通的select規則的rule_id,因為ProxySQL是根據rule_id的順序進行規則匹配的。
#再來測試下,讀操作是否路由給了hostgroup_id=20的讀組。
[root@s1 ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'select @@server_id' mysql:
[Warning] Using a password on the command line interface can be insecure.
+-------------+ | @@server_id | +-------------+ | 120 |
+-------------+
[root@s1 ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'select @@server_id' mysql:
[Warning] Using a password on the command line interface can be insecure.
+-------------+ | @@server_id | +-------------+ | 130 |
+-------------+
#讀操作已經路由給讀組,再看看寫操作。這里以事務持久化進行測試。
[root@s1 ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e '\ start transaction;\ select @@server_id;\ commit;\ select @@server_id;'
+-------------+ | @@server_id | +-------------+ | 110 | +-------------+ +-------------+ | @@server_id | +-------------+ | 120 |
+-------------+
顯然,一切都按照預期進行。最后,如果想查看路由的信息,可查詢stats庫中的stats_mysql_query_digest表。以下是該表的一個輸出格式示例(和本文無關)。
admin> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC;
+----+----------+------------+-------------------------------------------------------------+ | hg | sum_time | count_star | digest_text | +----+----------+------------+-------------------------------------------------------------+ | 2 | 14520738 | 50041 | SELECT c FROM sbtest1 WHERE id=? | | 1 | 3142041 | 5001 | COMMIT | | 1 | 2270931 | 5001 | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?+? ORDER BY c | | 1 | 2021320 | 5003 | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?+? | | 1 | 1768748 | 5001 | UPDATE sbtest1 SET k=k+? WHERE id=? | | 1 | 1697175 | 5003 | SELECT SUM(K) FROM sbtest1 WHERE id BETWEEN ? AND ?+? | | 1 | 1346791 | 5001 | UPDATE sbtest1 SET c=? WHERE id=? | | 1 | 1263259 | 5001 | DELETE FROM sbtest1 WHERE id=? | | 1 | 1191760 | 5001 | INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?) | | 1 | 875343 | 5005 | BEGIN | +----+----------+------------+-------------------------------------------------------------+
至此,MySQL5.7基于GTID主從復制+并行復制+增強半同步復制+讀寫分離結束。
智能推薦
mysql主從復制、半同步復制、并行復制、多組復制
一、主從復制 redhat6.5 master:server1 172.25.35.52 slave:server3 172.25.35.53 master: slave: 測試: master:添加數據庫 slave:查看到同步過來 二、Gtid主從復制 測試: master:給數據庫插入內容 slave:可以同步過來 三、半同步復制 master: timeout 10s,超過該時間會轉為異步...
企業級 ##MySQL 5.7 數據庫多臺主從復制 基于GTID主從復制 半同步##
主從復制的基本概念: 1.主從復制的條件: 實時災備,用于故障切換讀寫分離,提供查詢服務備份,避免影響業務 2.主從復制原理: 從庫生成兩個線程,一個i/o線程,一個SQL線程;i/o線程去請求主庫的binlog,并且得到的binlog日志寫道relay log(中繼日志)文件中,主庫會生成一個log dump線程,用來給從庫的i/o線程傳binlog;SQL線程,會讀取中繼日志文件,并解析成具體...
mysql的主從復制,基于gtid的主從復制,半同步復制,組復制
主從復制原理: 1.傳統的實現數據庫同步 # [root@server1 mysql5.7]# grep password /var/log/mysqld.log #獲取初始密碼 2018-08-07T14:06:55.029406Z 1 [Note] A temporary password is generated for root@localhost: aG!a*sUs>3#) #初始...
mysql的主從復制、基于gtid的主從復制和半同步復制
主從復制 在官網上下載mysql的安裝包mysql-5.7.17-1.el6.x86_64.rpm-bundle.tar 在server1,2中均做以下動作 主節點上: mysql -p mysql> grant replication slave on . to repl@’172.25.11.%’ identified by ‘WDd12345.&rs...
mysql的主從復制、基于Gtid的主從復制、半同步復制
1.mysql主從復制的作用: (1)實時災備,用于故障切換 (2) 讀寫分離,提供查詢服務 (3) 備份,避免影響業務 2.主從部署必要條件: (1) 主庫開啟binlog日志(設置log-bin參數) (2) 主從server-id不同 (3)從庫服務器能連通主庫 3.主從復制實驗: 實驗環境:mysql-5.7.17-1.el6.x86_64.rpm-bundle.tar server2:主...
猜你喜歡
mysql主從復制、基于GTID的主從、半同步
使用的mysql版本5.7.17 一、主從復制 原理: 主從復制一共有三個進程,從庫生成兩個線程,一個I/O線程,一個SQL線程; i/o線程去請求主庫的binlog,并將得到的binlog日志寫到relay log(中繼日志) 文件中; 主庫會生成一個 log dump 線程,用來給從庫 i/o線程傳binlog; SQL 線程,會讀取relay log文件中的日志,并解析成具體操作,來實現主從...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...