1. 擴容方案剖析
1.1 擴容問題
在項目初期,我們部署了三個數據庫 A、B、C,此時數據庫的規??梢詽M足我們的業務需求。為了將數據做到平均分配,我們在 Service 服務層使用 uid%3 進行取模分片,從而將數據平均分配到三個數據庫中。
如圖所示:
后期隨著用戶量的增加,用戶產生的數據信息被源源不斷的添加到數據庫中,最終達到數據庫的最佳存儲容量。如果此時繼續向數據庫中新增數據,會導致數據庫的 CRUD 等基本操作變慢,進而影響整個服務的響應速度。
這時,我們需要增加新的節點,對數據庫進行水平擴容,那么加入新的數據庫 D 后,數據庫的規模由原來的 3 個變為 4 個。
如圖所示:
此時由于分片規則發生了變化(uid%3 變為 uid%4),導致大部分的數據,無法命中原有的數據,需要重新進行分配,要做大量的數據遷移處理。
比如之前 uid 如果是 uid=3 取模 3%3=0, 是分配在 A 庫上,新加入 D 庫后, uid=3 取模 3%4=3,分配在 D 庫上;
新增一個節點, 大概會有 90% 的數據需要遷移, 這樣會面臨大量的數據壓力,并且對服務造成極大的不穩定性。
1.2 停機方案
發布公告
為了進行數據的重新拆分,在停止服務之前,我們需要提前通知用戶,比如:我們的服務會在 yyyy-MM-dd 進行升級,給您帶來的不便敬請諒解。
停止服務
關閉 Service
離線數據遷移(拆分,重新分配數據)
將舊庫中的數據按照 Service 層的算法,將數據拆分,重新分配數據
數據校驗
開發定制一個程序對舊庫和新庫中的數據進行校驗,比對
更改配置
修改 Service 層的配置算法,也就是將原來的 uid%3 變為 uid%4
恢復服務
重啟 Service 服務
回滾預案
針對上述的每個步驟都要有數據回滾預案,一旦某個環節(如:數據遷移,恢復服務等)執行失敗,立刻進行回滾,重新再來
停止服務之后, 能夠保證遷移工作的正常進行, 但是服務停止,傷害用戶體驗, 并造成了時間壓力, 必須在指定的時間內完成遷移。
1.3 停寫方案
支持讀寫分離
數據庫支持讀寫分離,在擴容之前,每個數據庫都提供了讀寫功能,數據重新分配的過程中,將每個數據庫設置為只讀狀態,關閉寫的功能
升級公告
為了進行數據的重新拆分,在停寫之前,我們需要提前通知用戶,比如:我們的服務會在 yyyy-MM-dd 進行升級,給您帶來的不便敬請諒解。
中斷寫操作,隔離寫數據源(或攔截返回統一提示)
在 Service 層對所有的寫請求進行攔截,統一返回提示信息,如:服務正在升級中,只對外提供讀服務
數據同步處理
將舊庫中的數據按照 Service 層的算法,將數據重新分配,遷移(復制數據)
數據校驗
開發定制一個程序對舊庫中的數據進行備份,使用備份的數據和重新分配后的數據進行校驗,比對
更改配置
通過配置中心,修改 Service 層的配置算法,也就是將原來的 uid%3 變為 uid%4,這個過程不需要重啟服務
恢復寫操作
設置數據庫恢復讀寫功能,去除 Service 層的攔截提示
數據清理
使用 delete 語句對冗余數據進行刪除
回滾預案
針對上述的每個步驟都要有數據回滾預案,一旦某個環節(如:數據遷移等)執行失敗,立刻進行回滾,重新再來
缺點:在數據的復制過程需要消耗大量的時間,停寫時間太長,數據需要先復制,再清理冗余數據
1.4 日志方案
核心是通過日志進行數據庫的同步遷移, 主要操作步驟如下:
數據遷移之前, 業務應用訪問舊的數據庫節點。
日志記錄
在升級之前, 記錄 “對舊數據庫上的數據修改” 的日志(這里修改包括增、刪、改),這個日志不需要記錄詳細的數據信息,主要記錄:
(1)修改的庫;
(2)修改的表;
(3)修改的唯一主鍵;
(4)修改操作類型。
日志記錄不用關注新增了哪些信息,修改的數據格式,只需要記錄以上數據信息,這樣日志格式是固定的, 這樣能保證方案的通用性。
服務升級日志記錄功能風險較?。?/p>
寫和修改接口是少數, 改動點少;
升級只是增加了一些日志,采用異步方式實現, 對業務功能沒有太多影響。
數據遷移:
研發定制數據遷移工具, 作用是把舊庫中的數據遷移至新庫中。
整個過程仍然采用舊庫進行對外服務。
數據同步工具實現復雜度不高。
只對舊庫進行讀取操作, 如果同步出現問題, 都可以對新庫進行回滾操作。
可以限速或分批遷移執行, 不會有時間壓力。
數據遷移完成之后, 并不能切換至新庫提供服務。
因為舊庫依然對線上提供服務, 庫中的數據隨時會發生變化, 但這些變化的數據并沒有同步到新庫中, 舊庫和新庫數據不一致, 所以不能直接進行切換, 需要將數據同步完整。
日志增量遷移
研發一個日志遷移工具,把上面遷移數據過程中的差異數據追平,處理步驟:
讀取 log 日志,獲取具體是哪個庫、表和主鍵發生了變化修改;
把舊庫中的主鍵記錄讀取出來
根據主鍵 ID,把新庫中的記錄替換掉
這樣可以最大程度的保障數據的一致性。風險分析:
整個過程, 仍然是舊庫對線上提供服務;
日志遷移工具實現的復雜度較低;
任何時間發現問題, 可以重新再來,有充分的容錯空間;
可以限速重放處理日志, 處理過程不會因為對線上影響造成時間壓力。
但是, 日志增量同步完成之后, 還不能切換到新的數據庫。
因為日志增量同步過程中,舊庫中可能有數據發生變化, 導致數據不一致,所以需要進一步讀取日志, 追平數據記錄;日志增量同步過程隨時可能會產生新的數據, 新庫與舊庫的數據追平也會是一個無限逼近的過程。
數據校驗
準備好數據校驗工具,將舊庫和新庫中的數據進行比對,直到數據完全一致。
切換新庫
數據比對完成之后, 將流量轉移切換至新庫, 至此新庫提供服務, 完成遷移。
但是在極限情況下, 即便通過上面的數據校驗處理, 也有可能出現 99.99% 數據一致, 不能保障完全一致,這個時候可以在舊庫做一個 readonly 只讀功能, 或者將流量屏蔽降級,等待日志增量同步工具完全追平后, 再進行新庫的切換。
至此,完成日志方案的遷移擴容處理, 整個過程能夠持續對線上提供服務, 只會短暫的影響服務的可用性。
這種方案的弊端,是操作繁瑣,需要適配多個同步處理工具,成本較高, 需要制定個性化業務的同步處理, 不具備普遍性,耗費的時間周期也較長。
1.5 雙寫方案(中小型數據)
雙寫方案可通過 canal 或 mq 做實現。
增加新庫,按照現有節點, 增加對應的數量。
數據遷移:避免增量影響, 先斷開主從,再導入(耗時較長), 同步完成并做校驗
增量同步:開啟 Canal 同步服務, 監聽從節點數據庫, 再開啟主從同步,從節點收到數據后會通過 Canal 服務, 傳遞至新的 DB 節點。
切換新庫:通過 Nginx,切換訪問流量至新的服務。
修復切換異常數據:在切換過程中, 如果出現,Canal 未同步,但已切換至新庫的請求(比如下單,修改了資金, 但還未同步 ), 可以通過定制程序, 讀取檢測異常日志,做自動修復或人工處理。
針對此種情況, 最好是在凌晨用戶量小的時候, 或專門停止外網訪問,進行切換,減少異常數據的產生。
數據校驗:為保障數據的完全一致, 有必要對數據的數量完整性做校驗。
1.6 平滑 2N 方案(大數據量)
線上數據庫,為了保障其高可用,一般每臺主庫會配置一臺從庫,主庫負責讀寫,從庫負責讀取。下圖所示,A,B 是主庫,A0 和 B0 是從庫。
當需要擴容的時候,我們把 A0 和 B0 升級為新的主庫節點,如此由 2 個分庫變為 4 個分庫。同時在上層的分片配置,做好映射,規則如下:
把 uid%4=0 和 uid%4=2 的數據分別分配到 A 和 A0 主庫中
把 uid%4=1 和 uid%4=3 的數據分配到 B 和 B0 主庫中
因為 A 和 A0 庫的數據相同,B 和 B0 數據相同,此時無需做數據遷移。只需調整變更一下分片配置即可,通過配置中心更新,不需要重啟。
由于之前 uid%2 的數據是分配在 2 個庫里面,擴容之后需要分布到 4 個庫中,但由于舊數據仍存在(uid%4=0 的節點,還有一半 uid%4=2 的數據),所以需要對冗余數據做一次清理。
這個清理,并不會影響線上數據的一致性,可以隨時隨地進行。
處理完成之后,為保證數據的高可用,以及將來下一步的擴容需求。
可以為現有的主庫再次分配一個從庫。
2. 平滑 2N 擴容方案實踐
2.1 實現應用服務級別的動態擴容
擴容前部署架構:
2.1.1 MariaDB 服務安裝
切換阿里云鏡像服務(YUM 安裝過慢可以切換)
yum -y install wget ## 備份CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo wget -P /etc/yum.repos.d/ http://mirrors.aliyun.com/repo/epel-7.repo yum clean all yum makecache
配置 YUM 源
vi /etc/yum.repos.d/mariadb-10.2.repo
增加以下內容:
[mariadb] name = MariaDB baseurl = https://mirrors.ustc.edu.cn/mariadb/yum/10.2/centos7-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1
執行安裝
yum -y install mariadb mariadb-server MariaDB-client MariaDB-common
如果之前已經安裝, 需要先刪除(如果之前沒有安裝, 可以忽略此步驟)
停止 Mariadb 服務
[root@localhost yum.repos.d]# ps -ef | grep mysql root 1954 1 0 Oct04 ? 0043 /usr/sbin/mysqld --wsrep-new-cluster --user=root root 89521 81403 0 07:40 pts/0 0000 grep --color=auto mysql [root@localhost yum.repos.d]# kill 1954
卸載 Mariadb 服務
yum -y remove Maria*
刪除數據與配置:
rm -rf /var/lib/mysql/* rm -rf /etc/my.cnf.d/ rm -rf /etc/my.cnf
啟動 MariaDB 后,執行安全配置向導命令,可根據安全配置向導提高數據庫的安全性
systemctl start mariadb mysql_secure_installation
開啟用戶遠程連接權限
將連接用戶 root 開啟遠程連接權限;
mysql -uroot -p654321
進入 MySQL 服務, 執行以下操作:
use mysql; delete from user; ## 配置root用戶使用密碼654321從任何主機都可以連接到mysql服務器 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '654321' WITH GRANT OPTION; FLUSH PRIVILEGES;
2.1.2 MariaDB 雙主同步
在 Server1 增加配置:
在 /etc/my.cnf 中添加以下配置:
[mysqld] server-id = 1 log-bin=mysql-bin relay-log = mysql-relay-bin ## 忽略mysql、information_schema庫下對表的操作 replicate-wild-ignore-table=mysql.% replicate-wild-ignore-table=information_schema.% ## 默認的情況下mysql是關閉的; log-slave-updates=on ## 復制過程中,有任何錯誤,直接跳過 slave-skip-errors=all auto-increment-offset=1 auto-increment-increment=2 ## binlog的格式:STATEMENT,ROW,MIXED binlog_format=mixed ## 自動過期清理binlog,默認0天,即不自動清理 expire_logs_days=10
注意, Server1 自增為奇數位:
auto-increment-offset=1 主鍵自增基數,從 1 開始。
auto-increment-increment=2 主鍵自增偏移量,每次為 2。
在 Server2 增加配置:
修改 /etc/my.cnf:
[mysqld] server-id = 2 log-bin=mysql-bin relay-log = mysql-relay-bin replicate-wild-ignore-table=mysql.% replicate-wild-ignore-table=information_schema.% log-slave-updates=on slave-skip-errors=all auto-increment-offset=2 auto-increment-increment=2 binlog_format=mixed expire_logs_days=10
Server2 自增為偶數位:
auto-increment-offset=2 主鍵自增基數,從 2 開始。
auto-increment-increment=2 主鍵自增偏移量,每次為 2。
配置修改完成后, 重啟數據庫。
同步授權配置
在 Server1 創建 replica 用于主從同步的用戶:
MariaDB [(none)]> grant replication slave, replication client on *.* to 'replica'@'%' identified by 'replica'; mysql> flush privileges;
查詢日志文件與偏移量,開啟同步時需使用:
MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000001 | 663 | | | +------------------+----------+--------------+------------------+
同樣, 在 Server2 創建 replica 用于主從同步的用戶:
MariaDB [(none)]> grant replication slave, replication client on *.* to 'replica'@'%' identified by 'replica'; mysql> flush privileges;
查詢日志文件與偏移量:
MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000001 | 663 | | | +------------------+----------+--------------+------------------+
配置主從同步信息
在 Server1 中執行:
MariaDB [(none)]> change master to master_host='192.168.116.141',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000007', master_log_pos=374, master_connect_retry=30;
在 Server2 中執行:
MariaDB [(none)]> change master to master_host='192.168.116.140',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000015', master_log_pos=374, master_connect_retry=30;
開啟雙主同步
在 Server1 和 Server2 中分別執行:
MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.00 sec)
在 Server1 查詢同步信息:
MariaDB [(none)]> show slave statusG; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.10.20.126 Master_User: replica Master_Port: 3306 Connect_Retry: 30 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 663 Relay_Log_File: mysql-relay-bin.000002 Relay_Log_Pos: 555 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes ...
在 Server2 查詢同步信息:
MariaDB [(none)]> show slave statusG; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.10.20.125 Master_User: replica Master_Port: 3306 Connect_Retry: 30 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 663 Relay_Log_File: mysql-relay-bin.000002 Relay_Log_Pos: 555 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes ...
Slave_IO_Running 和 Slave_SQL_Running 都是 Yes,說明雙主同步配置成功。
2.1.3 KeepAlived 安裝與高可用配置
在 Server1 與 Server2 兩臺節點安裝 keepalived:
yum -y install keepalived
關閉防火墻
systemctl stop firewalld systemctl disable firewalld
設置主機名稱:
Server1 節點:
hostnamectl set-hostname vip1
Server2 節點:
hostnamectl set-hostname vip2
Server1 節點配置
/etc/keepalived/keepalived.conf:
global_defs { router_id vip1 # 機器標識,和主機名保持一致,運行keepalived服務器的一個標識 } vrrp_instance VI_1 { #vrrp實例定義 state BACKUP #lvs的狀態模式,MASTER代表主, BACKUP代表備份節點 interface ens33 #綁定對外訪問的網卡,vrrp實例綁定的網卡 virtual_router_id 111 #虛擬路由標示,同一個vrrp實例采用唯一標示 priority 100 #優先級,100代表最大優先級, 數字越大優先級越高 advert_int 1 #master與backup節點同步檢查的時間間隔,單位是秒 authentication { #設置驗證信息 auth_type PASS #有PASS和AH兩種 auth_pass 6666 #驗證密碼,BACKUP密碼須相同 } virtual_ipaddress { #KeepAlived虛擬的IP地址 192.168.116.150 } } virtual_server 192.168.116.150 3306 { #配置虛擬服務器IP與訪問端口 delay_loop 6 #健康檢查時間 lb_algo rr #負載均衡調度算法, rr代表輪詢 lb_kind DR #負載均衡轉發規則 DR/NAT/ persistence_timeout 0 #會話保持時間,這里要做測試, 所以設為0, 實際可根據session有效時間配置 protocol TCP #轉發協議類型,支持TCP和UDP real_server 192.168.116.140 3306 { #配置服務器節點VIP1 notify_down /usr/local/shell/mariadb.sh #當服務掛掉時, 會執行此腳本,結束keepalived進程 weight 1 #設置權重,越大權重越高 TCP_CHECK { #狀態監測設置 connect_timeout 10 #超時配置, 單位秒 retry 3 #重試次數 delay_before_retry 3 #重試間隔 connect_port 3306 #連接端口, 和上面保持一致 } } }
創建關閉腳本 mariadb.sh
/usr/local/shell/mariadb.sh:
pkill keepalived
加入執行權限:
chmod a+x mariadb.sh
Server2 節點配置:
global_defs { router_id vip2 # 機器標識,和主機名保持一致,運行keepalived服務器的一個標識 } vrrp_instance VI_1 { #vrrp實例定義 state BACKUP #lvs的狀態模式,MASTER代表主, BACKUP代表備份節點 interface ens33 #綁定對外訪問的網卡 virtual_router_id 111 #虛擬路由標示,同一個vrrp實例采用唯一標示 priority 98 #優先級,100代表最大優先級, 數字越大優先級越高 advert_int 1 #master與backup節點同步檢查的時間間隔,單位是秒 authentication { #設置驗證信息 auth_type PASS #有PASS和AH兩種 auth_pass 6666 #驗證密碼,BACKUP密碼須相同 } virtual_ipaddress { #KeepAlived虛擬的IP地址 192.168.116.150 } } virtual_server 192.168.116.150 3306 { #配置虛擬服務器IP與訪問端口 delay_loop 6 #健康檢查時間 lb_algo rr #負載均衡調度算法, rr代表輪詢, 可以關閉 lb_kind DR #負載均衡轉發規則, 可以關閉 persistence_timeout 0 #會話保持時間,這里要做測試, 所以設為0, 實際可根據session有效時間配置 protocol TCP #轉發協議類型,支持TCP和UDP real_server 192.168.116.141 3306{ #配置服務器節點VIP2 notify_down /usr/local/shell/mariadb.sh #當服務掛掉時, 會執行此腳本,結束keepalived進程 weight 1 #設置權重,越大權重越高 TCP_CHECK { #r狀態監測設置 connect_timeout 10 #超時配置, 單位秒 retry 3 #重試次數 delay_before_retry 3 #重試間隔 connect_port 3306 #連接端口, 和上面保持一致 } } }
和 Server1 的差異項:
router_id vip2 # 機器標識,和主機名保持一致 priority 98 #優先級,100代表最大優先級, 數字越大優先級越高 real_server 10.10.20.126 3306 #配置服務器節點VIP2
注意, 兩臺節點都設為 BACKUP
virtual_router_id 111 #同一個vrrp實例采用唯一標示 state BACKUP
如果不想重啟后, 爭奪備用節點的 VIP, 可以設置此項
nopreempt #不主動搶占資源
注意:這個配置只能設置在 backup 主機上,而且這個主機優先級要比另外一臺高
驗證高可用
停止主節點 MariaDB 服務, 驗證是否自動切換。
2.1.4 搭建應用服務工程
ShardingJDBC 的介紹
是 ShardingSphere 下的一個產品
定位為輕量級 Java 框架,在 Java 的 JDBC 層提供的額外服務。它使用客戶端直連數據庫,以 jar 包形式提供服務,無需額外部署和依賴,可理解為增強版的 JDBC 驅動,完全兼容 JDBC 和各種 ORM 框架。
適用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。
支持任何第三方的數據庫連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP 等。
支持任意實現 JDBC 規范的數據庫,目前支持 MySQL,Oracle,SQLServer,PostgreSQL 以及任何遵循 SQL92 標準的數據庫
ShardingJDBC 初始化流程
1)配置 ShardingRuleConfiguration 對象
2)配置表分片規則 TableRuleConfiguration 對象,設置分庫、分表策略
3)通過 Factory 對象將 Rule 對象與 DataSource 對象裝配
4)ShardingJDBC 使用 DataSource 對象進行分庫
ShardingJDBC 集成配置
1)maven 依賴
2)規則配置 application.yml
3)創建 DataSource
驗證應用服務動態擴容
// 動態數據源配置實現擴容 Properties properties = loadPropertiesFile("datasource1.properties"); try { log.info("load datasource config url: " + properties.get("url")); DruidDataSource druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties); druidDataSource.setRemoveAbandoned(true); druidDataSource.setRemoveAbandonedTimeout(600); druidDataSource.setLogAbandoned(true); // 設置數據源錯誤重連時間 druidDataSource.setTimeBetweenConnectErrorMillis(60000); druidDataSource.init(); OrchestrationShardingDataSource dataSource = SpringContextUtil.getBean("tradeSystemDataSource", OrchestrationShardingDataSource.class); MapdataSourceMap = dataSource.getDataSource().getDataSourceMap(); dataSourceMap.put(DatasourceEnum.DATASOURCE_2.getValue(), druidDataSource); Map dataSourceConfigMap = new HashMap (); for(String key : dataSourceMap.keySet()) { dataSourceConfigMap.put(key, DataSourceConfiguration.getDataSourceConfiguration(dataSourceMap.get(key))); } String result = SHARDING_RULE_TABLE_ORDER.replace(SHARDING_RULE_DATASOURCE, newRule); replaceActualDataNodes(result); SHARDING_RULE_DATASOURCE = newRule; dataSource.renew(new DataSourceChangedEvent( "/" + DruidSystemDataSourceConfiguration.DYNAMIC_SHARDING + "/config/schema/logic_db/datasource", dataSourceConfigMap)); return; } catch (Exception e) { log.error(e.getMessage(), e); }
配置兩個數據源,分別指向 Server1 和 Server2
分片只配置一個數據源
動態增加另一個數據源
注意事項
Sharding JDBC, Mycat, Drds 等產品都是分布式數據庫中間件,相比直接的數據源操作,會存在一些限制,Sharding JDBC 在使用時,要注意以下問題:
有限支持子查詢
不支持 HAVING
不支持 OR,UNION 和 UNION ALL
不支持特殊 INSERT
每條 INSERT 語句只能插入一條數據,不支持 VALUES 后有多行數據的語句
不支持 DISTINCT 聚合
不支持 dual 虛擬表查詢
不支持 SELECT LAST_INSERT_ID (), 不支持自增序列
不支持 CASE WHEN
2.2 實現數據庫的秒級平滑 2N 擴容
** 擴容部署架構:**
2.2.1 新增數據庫 VIP
在 Server2 節點, 增加 VIP
修改 /etc/keepalived/keepalived.conf
global_defs { router_id vip2 } vrrp_instance VI_1 { #vrrp實例定義 state BACKUP #lvs的狀態模式,MASTER代表主, BACKUP代表備份節點 interface ens33 #綁定對外訪問的網卡 virtual_router_id 112 #虛擬路由標示,同一個vrrp實例采用唯一標示 priority 100 #優先級,100代表最大優先級, 數字越大優先級越高 advert_int 1 #master與backup節點同步檢查的時間間隔,單位是秒 authentication { #設置驗證信息 auth_type PASS #有PASS和AH兩種 auth_pass 6666 #驗證密碼,BACKUP密碼須相同 } virtual_ipaddress { #KeepAlived虛擬的IP地址 192.168.116.151 } } virtual_server 192.168.116.151 3306 { #配置虛擬服務器IP與訪問端口 delay_loop 6 #健康檢查時間 persistence_timeout 0 #會話保持時間,這里要做測試, 所以設為0, 實際可根據session有效時間配置 protocol TCP #轉發協議類型,支持TCP和UDP real_server 192.168.116.141 3306{ #配置服務器節點VIP1 notify_down /usr/local/shell/mariadb.sh weight 1 #設置權重,越大權重越高 TCP_CHECK { #r狀態監測設置 connect_timeout 10 #超時配置, 單位秒 retry 3 #重試次數 delay_before_retry 3 #重試間隔 connect_port 3306 #連接端口, 和上面保持一致 } } }
注意配置項:
virtual_router_id 112 #虛擬路由標示,同一個vrrp實例采用唯一標示 priority 100 #優先級,100代表最大優先級, 數字越大優先級越高
2.2.2 應用服務增加動態數據源
修改應用服務配置, 增加新的數據源, 指向新設置的 VIP:192.168.116.151
通過應用服務接口, 動態擴容調整
2.2.3 解除原雙主同步
mysql -uroot -p654321
進入 Server1:
MariaDB [(none)]> stop slave;
進入 Server2:
MariaDB [(none)]> stop slave;
通過應用服務接口驗證數據是否解除同步
2.2.4 安裝 MariaDB 擴容服務器
新建兩臺虛擬機, 分別為 Server3 和 Server4。
在 Server3 和 Server4 兩臺節點上安裝 MariaDB 服務
參考 2.1.1 MariaDB 服務安裝
配置 Server3 與 Server1,實現新的雙主同步
[mysqld] server-id = 3 log-bin=mysql-bin relay-log = mysql-relay-bin replicate-wild-ignore-table=mysql.% replicate-wild-ignore-table=information_schema.% log-slave-updates=on slave-skip-errors=all auto-increment-offset=2 auto-increment-increment=2 binlog_format=mixed expire_logs_days=10
service mariadb restart
MariaDB [(none)]> grant replication slave, replication client on *.* to 'replica'@'%' identified by 'replica'; mysql> flush privileges;
mysqldump -uroot -p654321 --routines --single_transaction --master-data=2 --databases smooth > server1.sql
... -- -- Position to start replication or point-in-time recovery from -- -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=17748; ...
scp server1.sql root@192.168.116.142:/usr/local/
mysql -uroot -p654321 < /usr/local/server1.sql
根據上面的 master status 信息, 在 Server3 中執行:
MariaDB [(none)]> change master to master_host='192.168.116.140',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000016', master_log_pos=1754, master_connect_retry=30; Query OK, 0 rows affected (0.01 sec)
MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.00 sec)
如果出現問題, 復原主從同步信息:
MariaDB [(none)]> reset slave; Query OK, 0 rows affected (0.01 sec)
MariaDB [(none)]> show slave status G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.10.20.125 Master_User: replica Master_Port: 3306 Connect_Retry: 30 Master_Log_File: mysql-bin.000004 Read_Master_Log_Pos: 11174 Relay_Log_File: mysql-relay-bin.000002 Relay_Log_Pos: 1746 Relay_Master_Log_File: mysql-bin.000004 Slave_IO_Running: Yes Slave_SQL_Running: Yes
查看 Server3 的日志信息:
MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000001 | 4781 | | | +------------------+----------+--------------+------------------+
在 Server1 節點, 配置同步信息:
MariaDB [(none)]> reset slave; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> change master to master_host='192.168.116.142',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000005', master_log_pos=6931, master_connect_retry=30; MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.00 sec)
配置 Server1 與 Server3 節點的同步
檢查同步狀態信息:
開啟主從同步:
配置主從同步信息
將數據還原至 Server3 節點:
將備份的 server1.sql 通過 scp 命令拷貝至 Server3 節點。
查看并記錄 master status 信息:
在 Server1 節點,進行數據全量備份:
創建 replica 用于主從同步的用戶:
重啟 Server3 數據庫
Server3 節點, 修改 /etc/my.cnf:
配置 Server4 與 Server2 的雙主同步
[mysqld] server-id = 4 log-bin=mysql-bin relay-log = mysql-relay-bin replicate-wild-ignore-table=mysql.% replicate-wild-ignore-table=information_schema.% log-slave-updates=on slave-skip-errors=all auto-increment-offset=2 auto-increment-increment=2 binlog_format=mixed expire_logs_days=10
service mariadb restart
MariaDB [(none)]> grant replication slave, replication client on *.* to 'replica'@'%' identified by 'replica'; mysql> flush privileges;
mysqldump -uroot -p654321 --routines --single_transaction --master-data=2 --databases smooth > server2.sql
... -- -- Position to start replication or point-in-time recovery from -- -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=4208; ...
scp server2.sql root@192.168.116.143:/usr/local/
mysql -uroot -p654321 < /usr/local/server2.sql
根據上面的 master status 信息, 在 Server4 中執行:
MariaDB [(none)]> change master to master_host='192.168.116.141',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000007', master_log_pos=3006, master_connect_retry=30; Query OK, 0 rows affected (0.01 sec)
MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.00 sec)
注意, 如果出現問題, 復原主從同步信息:
MariaDB [(none)]> reset slave; Query OK, 0 rows affected (0.01 sec)
MariaDB [(none)]> show slave status G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.10.20.125 Master_User: replica Master_Port: 3306 Connect_Retry: 30 Master_Log_File: mysql-bin.000004 Read_Master_Log_Pos: 11174 Relay_Log_File: mysql-relay-bin.000002 Relay_Log_Pos: 1746 Relay_Master_Log_File: mysql-bin.000004 Slave_IO_Running: Yes Slave_SQL_Running: Yes
查看 Server4 的日志信息:
MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000001 | 3696 | | | +------------------+----------+--------------+------------------+
在 Server2 節點, 配置同步信息:
MariaDB [(none)]> reset slave; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> change master to master_host='192.168.116.143',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000005', master_log_pos=5787, master_connect_retry=30; MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.00 sec)
配置 Server2 與 Server4 節點的同步
檢查同步狀態信息:
開啟主從同步:
配置主從同步信息
將數據還原至 Server4 節點:
將備份的 server2.sql 通過 scp 命令拷貝至 Server4 節點。
查看并記錄 master status 信息:
在 Server2 節點,進行數據全量備份:
創建 replica 用于主從同步的用戶:
重啟 Server4 數據庫
Server4 節點, 修改 /etc/my.cnf:
2.2.5 增加 KeepAlived 服務實現高可用
確保新增的 Server3 和 Server4 節點安裝 Keepalived 服務。
修改 Server3 節點配置
global_defs { router_id vip3 # 機器標識,一般設為hostname,故障發生時,郵件通知會使用到。 } vrrp_instance VI_1 { #vrrp實例定義 state BACKUP #lvs的狀態模式,MASTER代表主, BACKUP代表備份節點 interface ens33 #綁定對外訪問的網卡 virtual_router_id 111 #虛擬路由標示,同一個vrrp實例采用唯一標示 priority 98 #優先級,100代表最大優先級, 數字越大優先級越高 advert_int 1 #master與backup節點同步檢查的時間間隔,單位是秒 authentication { #設置驗證信息 auth_type PASS #有PASS和AH兩種 auth_pass 6666 #驗證密碼,BACKUP密碼須相同 } virtual_ipaddress { #KeepAlived虛擬的IP地址 192.168.116.150 } } virtual_server 192.168.116.150 3306 { #配置虛擬服務器IP與訪問端口 delay_loop 6 #健康檢查時間 persistence_timeout 0 #會話保持時間,這里要做測試, 所以設為0, 實際可根據session有效時間配置 protocol TCP #轉發協議類型,支持TCP和UDP real_server 192.168.116.142 3306{ #配置服務器節點VIP3 notify_down /usr/local/shell/mariadb.sh weight 1 #設置權重,越大權重越高 TCP_CHECK { #r狀態監測設置 connect_timeout 10 #超時配置, 單位秒 retry 3 #重試次數 delay_before_retry 3 #重試間隔 connect_port 3306 #連接端口, 和上面保持一致 } } }
注意里面 IP 配置正確, 修改完成后重啟服務。
創建關閉腳本 mariadb.sh
/usr/local/shell/mariadb.sh:
pkill keepalived
加入執行權限:
chmod a+x mariadb.sh
修改 Server4 節點配置
global_defs { router_id vip4 # 機器標識,一般設為hostname,故障發生時,郵件通知會使用到。 } vrrp_instance VI_1 { #vrrp實例定義 state BACKUP #lvs的狀態模式,MASTER代表主, BACKUP代表備份節點 interface ens33 #綁定對外訪問的網卡 virtual_router_id 112 #虛擬路由標示,同一個vrrp實例采用唯一標示 priority 98 #優先級,100代表最大優先級, 數字越大優先級越高 advert_int 1 #master與backup節點同步檢查的時間間隔,單位是秒 authentication { #設置驗證信息 auth_type PASS #有PASS和AH兩種 auth_pass 6666 #驗證密碼,BACKUP密碼須相同 } virtual_ipaddress { #KeepAlived虛擬的IP地址 192.168.116.151 } } virtual_server 192.168.116.151 3306 { #配置虛擬服務器IP與訪問端口 delay_loop 6 #健康檢查時間 persistence_timeout 0 #會話保持時間,這里要做測試, 所以設為0, 實際可根據session有效時間配置 protocol TCP #轉發協議類型,支持TCP和UDP real_server 192.168.116.143 3306{ #配置服務器節點VIP4 notify_down /usr/local/shell/mariadb.sh weight 1 #設置權重,越大權重越高 TCP_CHECK { #r狀態監測設置 connect_timeout 10 #超時配置, 單位秒 retry 3 #重試次數 delay_before_retry 3 #重試間隔 connect_port 3306 #連接端口, 和上面保持一致 } } }
創建關閉腳本 mariadb.sh
/usr/local/shell/mariadb.sh:
pkill keepalived
給所有的用戶組加入執行權限:
chmod a+x mariadb.sh
修改完后重啟 Keepalived 服務。
2.2.6 清理數據并驗證
通過應用服務動態擴容接口做調整和驗證
在 Server1 節點清理數據
根據取模規則, 保留 accountNo 為偶數的數據
delete from t_trade_order where accountNo % 2 != 0
在 Server2 節點清理數據
根據取模規則, 保留 accountNo 為奇數的數據
delete from t_trade_order where accountNo % 2 != 1
3.keepalived 高可用配置大全
在 Server1(192.168.116.140)中執行:
MariaDB [(none)]> change master to master_host='192.168.116.141',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000005', master_log_pos=3207, master_connect_retry=30;
在 Server2(192.168.116.141)中執行:
MariaDB [(none)]> change master to master_host='192.168.116.140',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000012', master_log_pos=1951, master_connect_retry=30;
在 Server3(192.168.116.142)中執行:
MariaDB [(none)]> change master to master_host='192.168.116.140',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000013', master_log_pos=2781, master_connect_retry=30; Query OK, 0 rows affected (0.01 sec)
在 Server4(192.168.116.143)中執行:
MariaDB [(none)]> change master to master_host='192.168.116.141',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000005', master_log_pos=7358, master_connect_retry=30; Query OK, 0 rows affected (0.01 sec)
Server1 和 Server2 雙主關系
Server1: keepalived.conf
vi /etc/keepalived/keepalived.conf
global_defs { router_id vip1 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 111 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 6666 } virtual_ipaddress { 192.168.116.150 } } virtual_server 192.168.116.150 3306 { delay_loop 6 lb_algo rr lb_kind DR // NAT|DR|TUN persistence_timeout 0 protocol TCP real_server 192.168.116.140 3306 { notify_down /usr/local/shell/mariadb.sh weight 1 TCP_CHECK { connect_timeout 10 retry 3 delay_before_retry 3 connect_port 3306 } } }
Server2:keepalived.conf
vi /etc/keepalived/keepalived.conf
global_defs { router_id vip2 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 111 priority 98 advert_int 1 authentication { auth_type PASS auth_pass 6666 } virtual_ipaddress { 192.168.116.150 } } virtual_server 192.168.116.150 3306 { delay_loop 6 lb_algo rr lb_kind DR persistence_timeout 0 protocol TCP real_server 192.168.116.141 3306{ notify_down /usr/local/shell/mariadb.sh weight 1 TCP_CHECK { connect_timeout 10 retry 3 delay_before_retry 3 connect_port 3306 } } }
新增數據庫 VIP
Server2:keepalived.conf
vi /etc/keepalived/keepalived.conf
global_defs { router_id vip2 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 112 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 6666 } virtual_ipaddress { 192.168.116.151 } } virtual_server 192.168.116.151 3306 { delay_loop 6 persistence_timeout 0 protocol TCP real_server 192.168.116.141 3306{ notify_down /usr/local/shell/mariadb.sh weight 1 TCP_CHECK { connect_timeout 10 retry 3 delay_before_retry 3 connect_port 3306 } } }
Server1 和 Server3 雙主關系
Server3: keepalived.conf
vi /etc/keepalived/keepalived.conf
global_defs { router_id vip3 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 111 priority 98 advert_int 1 authentication { auth_type PASS auth_pass 6666 } virtual_ipaddress { 192.168.116.150 } } virtual_server 192.168.116.150 3306 { delay_loop 6 lb_algo rr lb_kind DR persistence_timeout 0 protocol TCP real_server 192.168.116.142 3306 { notify_down /usr/local/shell/mariadb.sh weight 1 TCP_CHECK { connect_timeout 10 retry 3 delay_before_retry 3 connect_port 3306 } } }
Server2 和 Server4 雙主關系
Server4: keepalived.conf
vi /etc/keepalived/keepalived.conf
global_defs { router_id vip4 } vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 112 priority 98 advert_int 1 authentication { auth_type PASS auth_pass 6666 } virtual_ipaddress { 192.168.116.151 } } virtual_server 192.168.116.151 3306 { delay_loop 6 lb_algo rr lb_kind DR persistence_timeout 0 protocol TCP real_server 192.168.116.143 3306{ notify_down /usr/local/shell/mariadb.sh weight 1 TCP_CHECK { connect_timeout 10 retry 3 delay_before_retry 3 connect_port 3306 } } }
審核編輯:劉清
-
TCP
+關注
關注
8文章
1397瀏覽量
80319 -
UDP
+關注
關注
0文章
330瀏覽量
34459 -
虛擬機
+關注
關注
1文章
962瀏覽量
28996 -
MYSQL數據庫
+關注
關注
0文章
96瀏覽量
9751
原文標題:6種MySQL數據庫平滑擴容方案剖析
文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
labview有調用mysql數據庫問題????
MySQL數據庫如何安裝和使用說明
華為云數據庫-RDS for MySQL數據庫
有哪些不同的MySQL數據庫引擎?
mysql是一個什么類型的數據庫
mysql數據庫基礎命令
數據庫數據恢復—未開啟binlog的Mysql數據庫數據恢復案例

MySQL數據庫的安裝

評論