掃二維碼與項(xiàng)目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
業(yè)界流傳一句話:沒有做過運(yùn)維的程序員不是好架構(gòu)師。

創(chuàng)新互聯(lián)長期為近1000家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為冊亨企業(yè)提供專業(yè)的成都網(wǎng)站制作、成都做網(wǎng)站,冊亨網(wǎng)站改版等技術(shù)服務(wù)。擁有十余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
不知是真是假。
對于 MySQL 數(shù)據(jù)庫作為各個業(yè)務(wù)系統(tǒng)的存儲介質(zhì),在系統(tǒng)中承擔(dān)著非常重要的職責(zé),如果數(shù)據(jù)庫崩了,那么對于讀和寫數(shù)據(jù)庫的操作都會受到影響。如果不能迅速恢復(fù),對業(yè)務(wù)的影響是非常大的。之前 B 站不是出過一次事故么,2 小時才恢復(fù)過來,詳細(xì)可以看之前寫的文章。
B 站崩了,總結(jié)下「高可用」和「異地多活」
上次折騰完 ELK 日志檢索平臺后,開發(fā)環(huán)境可以正常查詢?nèi)罩玖?。最近在做系統(tǒng)高可用相關(guān)的工作,這次我來分享下 MySQL 雙主 + Keepalived 的高可用落地和踩坑之路。
一文帶你搭建一套 ELK Stack 日志平臺
對于 MySQL 的高可用,主要分為兩步,配置 MySQL 主主模式和 keepalived 軟件。拓?fù)鋱D如下所示:
兩個數(shù)據(jù)庫分別部署在兩臺服務(wù)器上,相互同步數(shù)據(jù),但是只有一個提供給外部訪問,當(dāng)一個宕機(jī)后,另外一個可以繼續(xù)提供服務(wù),在沒有 keepalived 軟件的幫助下,只能手動切換
檢測和重啟的原理如下所示:
需要配置的內(nèi)容如下:
對于 MySQL 的主主架構(gòu),其實(shí)原理就是兩臺服務(wù)器互為主從,雙向復(fù)制。而復(fù)制的原理如下:
主從復(fù)制主要有以下流程:
大白話就是:
從庫會生成兩個線程,一個 I/O 線程,一個 SQL 線程;
I/O 線程會去請求主庫的 binlog,并將得到的 binlog 寫到本地的 relay-log (中繼日志)文件中;
主庫會生成一個 dump 線程,用來給從庫 I/O 線程傳 binlog;
SQL 線程,會讀取 relay log 文件中的日志,并解析成 SQL 語句逐一執(zhí)行;
接下來我們先把 MySQL 的基礎(chǔ)環(huán)境在兩臺 Ubuntu 服務(wù)器上搭建好,后續(xù)操作都是基于這個來做的。
作為演示,我在本機(jī)啟動了兩臺 Ubuntu 虛擬機(jī),安裝有 docker。因?yàn)槲覀兊臏y試和生產(chǎn)環(huán)境是用 Docker 跑的,所以我將環(huán)境的鏡像打包后,還原到我的虛擬機(jī)上面。
保存測試環(huán)境的 mysql 鏡像
sudo docker save -o mysql.tar hcr:5000/hschub/hscmysql:0.0.2
sudo chmod 777 mysql.tar
兩臺機(jī)器導(dǎo)入鏡像
sudo docker load -i mysql.tar
啟動容器,需要注意的是需要映射本地文件夾。
sudo docker run -p 3306:3306 --name mysql \
-v /home/hss/mysql/data:/var/lib/mysql \
-v /home/hss/mysql/etc/mysql:/etc/mysql \
-e MYSQL_ROOT_PASSWORD='123456' \
-d 46b
-v 代表映射的文件夾,-d 表示后臺運(yùn)行,46b 代表鏡像 id。
進(jìn)入容器,連接 mysql,node1的mysql 密碼是 123456,node2 是 123456
# 查詢?nèi)萜?id
docker ps
# 進(jìn)入 mysql 容器
docker exec -it <容器 id> /bin/bash
# 連接 mysql
mysql -u root -p
接下來我們配置 MySQL 的主從架構(gòu),需要注意的是后續(xù)搭建的主主架構(gòu)是基于主從架構(gòu)來的,區(qū)別就是修改了一部分配置。
拓?fù)浣Y(jié)構(gòu):
修改 /home/hss/mysql/etc/mysql/my.cnf 文件
server_id = 11
log_bin = /var/lib/mysql/log/mysql-bin
binlog-ignore-db=mysql
binlog_format= mixed
sync_binlog=100
log_slave_updates = 1
binlog_cache_size=32m
max_binlog_cache_size=64m
max_binlog_size=512m
relay_log = /var/lib/mysql/log/relay-bin
relay_log_index = /var/lib/mysql/log/relay-bin.index
master_info_repository=TABLE
relay-log-info-repository=TABLE
relay-log-recovery
創(chuàng)建 /home/hss/mysql/data/log/mysql-bin 文件夾
創(chuàng)建 /home/hss/mysql/data/log/relay-bin 文件夾
給兩個文件夾加上 777 權(quán)限,然后重啟 MySQL 容器。
和主節(jié)點(diǎn)配置類似,需要修改 server_id = 12
CREATE USER 'vagrant'@'192.168.56.12' IDENTIFIED BY 'vagrant';
ALTER USER 'vagrant'@'192.168.56.12' IDENTIFIED WITH mysql_native_password BY 'vagrant';
GRANT REPLICATION SLAVE ON *.* TO 'vagrant'@'192.168.56.12';
FLUSH PRIVILEGES;
FLUSH TABLES WITH READ LOCK;
記住 File 和 Position,后面會用到。這里 File = mysql-bin.000008,Position = 1020。
cd /var/lib/mysql
mkdir backup
mysqldump -uroot -P3306 --all-databases --triggers --routines --events > /var/lib/mysql/backup/all_databases.sql
查看掛載目錄下是否有生成 all_databases.sql 文件,如下圖所示:
UNLOCK TABLES
mysql -uroot -p -hlocalhost -P3306 < /var/lib/mysql/backup/all_databases.sql
在 MySQL 命令行窗口中執(zhí)行以下命令設(shè)置同步信息。這里就是配置主數(shù)據(jù)庫的 IP 地址、Port、用戶名、密碼,二進(jìn)制文件名,偏移量。
CHANGE MASTER TO MASTER_HOST='192.168.56.11',
MASTER_PORT=3306,
MASTER_USER='vagrant',
MASTER_PASSWORD='vagrant',
MASTER_LOG_FILE='mysql-bin.000008',
MASTER_LOG_POS=1020;
在 MySQL 命令行窗口中執(zhí)行以下命令啟動從數(shù)據(jù)庫的復(fù)制線程。
START salve;
SHOW slave status \G
如果 Slave_IO_Running 和 Slave_SQL_Running 顯示 Yes,就表示啟動同步成功。如下圖所示:
在主庫上執(zhí)行以下命令顯示當(dāng)前連接過來的從庫線程。
SHOW PROCESSLIST
如下所示,Slave has read all relay log; wating for more updates,說明從庫已經(jīng)同步完了。
使用上面的兩個命令,我們可以判斷當(dāng)前的復(fù)制情況。
下面驗(yàn)證下主從節(jié)點(diǎn)之間是否能正常同步數(shù)據(jù)。
主節(jié)點(diǎn)創(chuàng)建 testdb 數(shù)據(jù)庫和 member 表。
刷新下從節(jié)點(diǎn),發(fā)現(xiàn)從節(jié)點(diǎn)自動創(chuàng)建了 member 表。如下圖所示。
然后在主節(jié)點(diǎn)插入一條數(shù)據(jù),刷新從節(jié)點(diǎn)后,發(fā)現(xiàn)從節(jié)點(diǎn)也自動創(chuàng)建了一條數(shù)據(jù)。
配置主主架構(gòu)就是在主從架構(gòu)中交換下配置信息。步驟如下:
STOP slave
CREATE USER 'vagrant'@'192.168.56.11' IDENTIFIED BY 'vagrant';
ALTER USER 'vagrant'@'192.168.56.11' IDENTIFIED WITH mysql_native_password BY 'vagrant';
GRANT REPLICATION SLAVE ON *.* TO 'vagrant'@'192.168.56.11';
FLUSH PRIVILEGES;
SHOW MASTER STATUS
start slave
CHANGE MASTER TO MASTER_HOST='192.168.56.12',
MASTER_PORT=3306,
MASTER_USER='vagrant',
MASTER_PASSWORD='vagrant',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=2453;
START salve
SHOW slave status \G
node2 的 member 表增加一條數(shù)據(jù) (2,zzz),node1 上同步成功
node 1 的 member 表增加一條數(shù)據(jù)(3,aaa),node2 上同步成功
Keepalived 軟件在主主架構(gòu)中,可以配置成兩種應(yīng)用場景:
這里我配置成第二種功能場景,保障 MySQL 服務(wù)的高可用。另外可以配置 MySQL 服務(wù)異常時,發(fā)送郵件給運(yùn)維或開發(fā)人員,由他們檢查服務(wù)器的狀態(tài)。
Keepalived 提供了一個虛擬 IP (簡稱 VIP),對外提供訪問。當(dāng)客戶端連接這個虛擬 IP 后,只會訪問其中一個 MySQL。MySQL 節(jié)點(diǎn)故障后,keepalived 執(zhí)行腳本進(jìn)行重啟,如果重啟失敗,腳本自動停掉 keepalived,備用節(jié)點(diǎn)自動切換為主節(jié)點(diǎn)。
keepalived 檢測和重啟的流程圖如下:
安裝依賴、獲取 keepalived 安裝包、解壓安裝包、刪除安裝包。
# 安裝依賴
sudo apt-get install -y libssl-dev
sudo apt-get install -y openssl
sudo apt-get install -y libpopt-dev
sudo apt-get install -y libnl-dev
sudo apt-get install -y libnl-3-dev
sudo apt-get install -y libnl-genl-3.dev
sudo apt-get install daemon
sudo apt-get install libc-dev
sudo apt-get install libnfnetlink-dev
sudo apt-get install gcc
# 獲取 keepalived 安裝包
cd /usr/local
sudo su
sudo wget https://www.keepalived.org/software/keepalived-2.2.2.tar.gz
# 解壓安裝包
sudo tar -zxvf keepalived-2.2.2.tar.gz
# 刪除安裝包
mv keepalived-2.2.2 keepalived
配置 keepalived 軟件
cd keepalived
./configure --prefix=/usr/local/keepalived --disable-dependency-tracking
執(zhí)行結(jié)果如下所示:
編譯 keepalived 軟件
sudo make && make install
執(zhí)行結(jié)果如下所示:
對于 Ubuntu ,需要做一點(diǎn)特別的改動,創(chuàng)建鏈接
mkdir -p /etc/rc.d/init.d
ln -s /lib/lsb/init-functions /etc/rc.d/init.d/functions
拷貝配置文件
sudo mkdir /etc/sysconfig
sudo cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
sudo cp /usr/local/keepalived/keepalived/etc/init.d/keepalived /etc/init.d/
sudo cp /usr/local/keepalived/sbin/keepalived /sbin/
sudo mkdir /etc/keepalived
sudo cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
修改配置文件 /etc/keepalived/keepalived.conf
daemon keepalived ${KEEPALIVED_OPTIONS}改為
daemon -- keepalived ${KEEPALIVED_OPTIONS}先用 ifconfig 查看當(dāng)前的網(wǎng)卡,比如我的服務(wù)器上是 enp0s8。
ip addr del 192.168.56.88 dev enp0s8:1
ifconfig enp0s8:1 192.168.56.88 broadcast 192.168.56.255 netmask 255.255.255.0 up
route add -host 192.168.56.88 dev enp0s8:1
將命令寫到 /usr/local/script/vip.sh文件中。最好將 /usr/local/script/vip.sh文件添加到服務(wù)器的開機(jī)啟動項(xiàng)中,將 Keepalived 服務(wù)設(shè)置為開機(jī)自啟動(未寫)。
備份配置文件
sudo mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.backup
修改配置文件
sudo vim /etc/keepalived/keepalived.conf
配置文件的內(nèi)容如下:
global_defs {
router_id MYSQL_HA #當(dāng)前節(jié)點(diǎn)名
}
vrrp_script restart_mysql {
script "/usr/local/keepalived/restart_mysql.sh" #重啟 mysql 容器
interval 2
weight 2
}
vrrp_instance VI_1 {
state BACKUP #兩臺配置節(jié)點(diǎn)均為BACKUP
interface enp0s8 #綁定虛擬IP的網(wǎng)絡(luò)接口
virtual_router_id 51 #VRRP組名,兩個節(jié)點(diǎn)的設(shè)置必須一樣,以指明各個節(jié)點(diǎn)屬于同一VRRP組
priority 101 #節(jié)點(diǎn)的優(yōu)先級,另一臺優(yōu)先級改低一點(diǎn)
advert_int 1 #組播信息發(fā)送間隔,兩個節(jié)點(diǎn)設(shè)置必須一樣
nopreempt #不搶占,只在優(yōu)先級高的機(jī)器上設(shè)置即可,優(yōu)先級低的機(jī)器不設(shè)置
authentication { #設(shè)置驗(yàn)證信息,兩個節(jié)點(diǎn)必須一致
auth_type PASS
auth_pass 123456
}
track_script {
restart_mysql #檢測 mysql 狀態(tài),如果失敗,則重啟 mysql 容器
}
virtual_ipaddress { #指定虛擬IP,兩個節(jié)點(diǎn)設(shè)置必須一樣
192.168.56.88
}
}
virtual_server 192.168.56.88 3306 { #linux虛擬服務(wù)器(LVS)配置
delay_loop 2 #每個2秒檢查一次real_server狀態(tài)
lb_algo wrr #LVS調(diào)度算法,rr|wrr|lc|wlc|lblc|sh|dh
lb_kind DR #LVS集群模式 ,NAT|DR|TUN
persistence_timeout 60 #會話保持時間
protocol TCP #使用的協(xié)議是TCP還是UDP
real_server 192.168.56.11 3306 {
weight 3 #權(quán)重
TCP_CHECK {
connect_timeout 10 #連接超時時間
nb_get_retry 3 #重連次數(shù)
delay_before_retry 3 #重連間隔時間
connect_port 3306 #健康檢查端口
}
}
}編寫異常處理腳本
sudo vim /usr/local/keepalived/restart_mysql.sh
內(nèi)容如下,
#!/bin/bash
# 定義變量,重啟 mysql 容器
START_MYSQL="docker restart mysql"
# 定義變量,停止 mysql 容器
STOP_MYSQL="docker stop mysql"
# 定義變量,日志文件路徑
LOG_FILE="/usr/local/keepalived/logs/mysql-check.log"
# 定義變量,檢查 mysql 服務(wù)是否正常的命令
HAPS=`ps -C mysqld --no-header |wc -l`
# 打印當(dāng)前時間到日志文件
date "+%Y-%m-%d %H:%M:%S" >> $LOG_FILE
# 打印提示信息到日志文件
echo "check mysql status" >> $LOG_FILE
# 檢查數(shù)據(jù)庫狀態(tài),如何返回 0,則重啟 mysql 容器,然后休眠 3s 后,再次檢測 mysql 狀態(tài),如果還是返回 0,則停止 keepalived。
if [ $HAPS -eq 0 ];then
echo $START_MYSQL >> $LOG_FILE
$START_MYSQL >> $LOG_FILE 2>&1
sleep 3
if [ `ps -C mysqld --no-header |wc -l` -eq 0 ];then
echo "start mysql failed, killall keepalived" >> $LOG_FILE
killall keepalived
fi
fi
給腳本分配權(quán)限
sudo chmod +x /usr/local/keepalived/restart_mysql.sh
創(chuàng)建 logs 文件夾,給 logs 文件夾分配權(quán)限
sudo mkdir /usr/local/keepalived/logs
sudo chmod +x /usr/local/keepalived/logs -r
重新加載配置文件
sudo systemctl daemon-reload
啟動 node2 節(jié)點(diǎn):
sudo pkill keepalived
sudo systemctl start keepalived
sudo systemctl status keepalived
啟動 node1 節(jié)點(diǎn):
pkilll keepalived
sudo systemctl status keepalived
我們可以通過這個命令查看 keepalived 進(jìn)程
ps -ef | grep keepalived
查看日志
sudo cat /var/log/syslog
停止 node2 上的 mysql 容器
docker stop 8cc
查看 keepalived 狀態(tài),提示移除了 mysql 服務(wù)。
因?yàn)?keepalived 會每 2s 檢查一次 MySQL 的狀態(tài),發(fā)現(xiàn) MySQL 異常后,就會重啟 mysql 容器。所以過幾秒后,重新查看容器狀態(tài),會看到 mysql 容器重新啟動了。
docker ps
查看 keepalived 狀態(tài),執(zhí)行 restart_mysql 成功
查看執(zhí)行日志
問題:每 2s 會打印一次,文件可能會很大。需要執(zhí)行定期刪除。
驗(yàn)證下當(dāng) MySQL 重啟失敗后,keepalived 自動停止后,客戶端連接的 MySQL 是否會自動切到另外一個 MySQL 節(jié)點(diǎn)上。
首先用 mysql 客戶端工具 navicat 連接虛擬 ip 地址,賬號和密碼就是 node 1 和 node2 的 mysql 賬號密碼(root/123456)
可以連接上,然后執(zhí)行以下命令,查看當(dāng)前虛擬 ip 連接的是哪個數(shù)據(jù)庫
SHOW VARIABLES LIKE '%hostname%'
可以看到連接的是 node2 的容器的 id,說明 keepalived 已經(jīng)通過虛擬 ip 連接到 node2 的 mysql 了,是正常工作的,node2 現(xiàn)在是作為主節(jié)點(diǎn),node1 作為備用節(jié)點(diǎn)。
由于本地環(huán)境重新啟動 MySQL 都是成功的,不會停掉 keepalived 服務(wù)。出于演示目的,我就直接停掉 keepalived 服務(wù)。
pkill keepalived
執(zhí)行下面這個命令可以查看 keepalived 進(jìn)程,發(fā)現(xiàn)已經(jīng)沒有了。(控制臺顯示的 grep --color=auto keepalived 表示是查找命令)
ps -ef | grep keepalived
重新查詢客戶端的連接信息,發(fā)現(xiàn)已經(jīng)切換到 92b (node1)機(jī)器上的 mysql 了。
SHOW VARIABLES LIKE '%hostname%'
再次查看 node1 上 keepalived 上的狀態(tài),再發(fā)送信息給
sudo systemctl status keepalived
密碼不正確,設(shè)置跳過密碼驗(yàn)證
apt-get update
apt install vim
修改 mysql 配置文件
vim /etc/mysql/my.cnf
添加一行配置,跳過 mysql 密碼驗(yàn)證
skip-grant-tables
重啟容器
docker restart 9e6
重新計(jì)入 mysql 容器,連接 mysql,不需要密碼就可以連接上 mysql。
mysql
修改登錄密碼
update mysql.user set authentication_string=PASSWORD('123456') where User='root'; 重啟容器
cd /home/hss/mysql/etc
sudo chmod 777 mysql -R
拷貝 mysql 文件夾
sudo chmod 777 /home/hss/mysql/data -R
sudo apt-get install -y libnl-dev libnl-
網(wǎng)站標(biāo)題:實(shí)戰(zhàn)MySQL高可用架構(gòu)
轉(zhuǎn)載源于:http://uogjgqi.cn/article/coeogps.html

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流