(9) MySQL主主複製架構使用方法

一. 回憶主從複製的一些缺點

上節說到主從複製的一些問題
咱們再來回憶一下
主從複製,增長了一個數據庫副本,從數據庫和主數據庫的數據最終會是一致的
之因此說是最終一致,由於mysql複製是異步的,正常狀況下主從複製數據之間會有一個微小的延遲
經過這個數據庫副本看似解決了數據庫單點問題,但並不完美
由於這種架構下,若是主服務器宕機,須要手動切換從服務器,業務中斷不能忍受,不能知足應用高可用的要求html

若是才能解決當master服務器宕機後,前端應用自動切換連接呢?前端

二. 引入vip後的數據庫架構

最簡單的方式就是給數據庫複製集羣上增長一個虛擬ipmysql

虛擬IP(vip):redis

就是一個未分配給真實主機的ip,也就是說對外提供服務器的主機除了有一個真實IP外還有一個虛擬IPsql

而前端應用程序使用虛擬ip來連接數據庫服務器,當master宕機後,虛擬ip由masterDB遷移到slaveDB上,這樣就不用人爲的修改前端應用的配置了數據庫

設置虛擬IP有不少種方法緩存

除了腳原本實現這些功能,還能夠經過MHA,MMM這樣的集羣管理工具來實現服務器

此處採用keepalived來配置虛擬ip網絡

首先,keepalived能夠提供vip,並對主從數據庫的健康狀態進行監控
當主DB宕機時,遷移VIP到主備數據庫服務器上,這樣就解決了當masterDB宕機時,要手動修改應用服務器的配置,重新鏈接到主備服務器上的問題架構

可是目前還存在一個問題,當master恢復後,因爲當前的寫操做遷移到了從上,因此若是要使用到老的master對新的master(也就是老的slave)進行同步,就不得不從新配置主從複製了,特別是在基於日誌點的複製狀況下,這時候若是咱們數據庫的數據量很是大,在這種狀況下,從新初始化數據也是比較耗時的
因此咱們要對主從複製的架構進行一些更改,改變原來的主從複製爲主主複製,但必定要保證同一個時間只有一個主提供服務,而另外一個主(也就是主備)是處於只讀狀態的,只對外提供讀服務,而不提供寫服務

之前說過InnoDB表的主鍵最好採用自增ID的列,而在主主複製中,爲了不兩個主中同時寫帶來的主鍵衝突,咱們須要修改自增主鍵的一些配置,使兩個主上的自增主鍵按照不一樣的步長進行增加 ,這只是爲了以防萬一採起的一個配置,當咱們使用主主複製時,仍是要保證在任意時間,均只有一個主能夠對外提供服務 ,而另外一個主只提供只讀的服務

三. 主主複製配置調整

master 數據庫配置修改

auto_increment_increment = 2    # 控制自增ID增加的步長,默認爲1
auto_increment_offset = 1 # 控制自增ID從哪一個值開始

這樣修改後,id將會變成1,3,7,9...的形式

主備數據庫配置修改

auto_increment_increment = 2    # 控制自增ID增加的步長,默認爲1
auto_increment_offset = 2  # 控制自增ID從哪一個值開始

這樣修改後,id將會變成2,4,6,8...的形式

Keepalived簡介

Keepalived基於ARRP網絡協議,ARRP能夠將2臺設備虛擬成一個設備,可對外提供一個虛擬IP,也就是咱們架構中的vip,在服務器內部其實是擁有虛擬IP的設備若是正常工做的話就是MASTER設備,同一組內其餘服務器不能用這個虛擬IP,狀態是屬於BACKUP狀態,處於BACKUP狀態的設備,除了接收MASTER的ARRP狀態通告以外,不執行任何對外的服務,當主機失效時,backup將接管原先的master的虛擬IP以及對外提供的各項服務

安裝

yum install keepalived -y

keepalived配置

在主和主備服務器上都要安裝和配置keepalived

配置文件所在位置
/etc/keepalived/keepalived.conf

配置文件中是按模塊劃分的

! Configuration File for keepalived

global_defs {
   router_id mysql_ha
}
vrrp_script check_run {
    script "/etc/keepalived/check_mysql.sh"
    interval 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 200
    priority 99
    advert_int 1
    nopreempt
    authentication {
        auth_type PASS
        auth_pass 1200
    }
   
  track_script {
         check_run
     }

   virtual_ipaddress {
      192.168.3.99/24
    }
}

vrrp_script模塊中:
定義用於檢查mysql是否運行正常的腳本,以及檢查的時間間隔
vrrp_instance 模塊中:
定義了keepalived服務所處的狀態,這個狀態只有BACKUP和MASTER兩個值
interface :定義了綁定 虛擬ip的網絡接口,必定要是服務器上可用的網絡接口
virtual_router_id :定義了虛擬服務的id,要取0到255之間的數字
priority :定義了優先級,值越高,優先級越大,備份的備設備的值要比主設備低
nopreempt:此值表明不搶佔資源,意思是原來的主宕機後,即便再恢復後也不會把虛擬IP搶回來,對於數據庫來講,這樣能夠避免主從切換的二次傷害的可能
authentication :配置驗證信息,這個在兩個節點必須是一致的
virtual_ipaddress :定義了使用的虛擬ip信息

四. 演示使用

1. 修改主、主備服務器配置

[client]
port  = 3306     # 客戶端端口號爲3306
socket = /home/mysql/data/mysql.sock

[mysqld]

# skip #
skip_name_resolve = 1
skip-external-locking =1

# GENERAL #
user = mysql   # MySQL啓動用戶
default_storage_engine = InnoDB  # 新數據表的默認數據表類型
character-set-server = utf8      #     #服務端默認編碼(數據庫級別)
socket = /home/mysql/data/mysql.sock
pid_file =  /home/mysql/data/mysqld.pid
basedir = /home/mysql    #使用該目錄做爲根目錄(Mysql安裝目錄);

port = 3306
bind-address = 0.0.0.0
log_error_verbosity = 3
explicit_defaults_for_timestamp = off
#sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
#sql_mode = NO_ENGINE_SUBSTITUTION

# undo log
# innodb_undo_directory = /home.mysql/undo
# innodb_undo_tablespaces = 32

# MyISAM #
key_buffer_size =32M

# SAFETY #
max_allowed_packet    = 100M
max_connect_errors    = 1000000
sysdate_is_now    =1
#innodb = FORCE
#innodb_strict_mode = 1  

# Replice #
server-id = 100
relay_log =  /home/mysql/sql_log/mysqld-relay-bin 

#plugin-load = semisync_master.so
log_slave_updates = on
master_info_repository = TABLE
relay_log_info_repository =TABLE

#######主主複製新增的配置###########
auto_increment_increment = 2    # 控制自增ID增加的步長,默認爲1
auto_increment_offset = 1 # 控制自增ID從哪一個值開始
#####################

# gtid_mode = on
# enforce_gtid_consistency =on
# skip-slave-start =1
#rpl_semi_sync_master_enabled = 1
#rpl_semi_sync_master_timeout=200    # 0.2 second
master_info_respository = TABLE
# gtid_mode= on
# enforce_gtid_consistency = on
# skip-slave-start = 1

# DATA STORAGE #

datadir = /home/mysql/data     #mysql 數據文件存放的目錄
tmpdir = /tmp    # MySQL存放臨時文件的目錄

# BINARY LOGGING #

log_bin = /home/mysql/sql_log/mysql-bin
max_binlog_size  = 1000M
binlog_format = row
expire_log_days = 7
sync_binlog = 1

# CACHES AND LIMITS #

tmp_table_size = 32M
max_heap_table_size = 32M
query_cache_type = 0

auto_increment_increment ,auto_increment_offset 這兩個參數是動態參數,咱們能夠直接經過命令進行修改,不須要重啓

查看並修改
命令以下

mysql> show variables like 'auto%';
mysql> set global auto_increment_increment=2;
mysql> set global auto_increment_offset =1;

從服務器配置進行相似修改便可

從服務器配置

[client]
port  = 3306     # 客戶端端口號爲3306
socket = /home/mysql/data/mysql.sock

[mysqld]

# skip #
skip_name_resolve = 1
skip-external-locking =1

# GENERAL #
user = mysql   # MySQL啓動用戶
default_storage_engine = InnoDB  # 新數據表的默認數據表類型
character-set-server = utf8      #     #服務端默認編碼(數據庫級別)
socket = /home/mysql/data/mysql.sock
pid_file =  /home/mysql/data/mysqld.pid
basedir = /home/mysql    #使用該目錄做爲根目錄(Mysql安裝目錄);

port = 3306
bind-address = 0.0.0.0
log_error_verbosity = 3
explicit_defaults_for_timestamp = off
#sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
#sql_mode = NO_ENGINE_SUBSTITUTION
read_only = on

# undo log
# innodb_undo_directory = /home.mysql/undo
# innodb_undo_tablespaces = 32

# MyISAM #
key_buffer_size =32M

# SAFETY #
max_allowed_packet    = 100M
max_connect_errors    = 1000000
sysdate_is_now    =1
#innodb = FORCE
#innodb_strict_mode = 1  

# Replice #
server-id = 101
relay_log =  /home/mysql/sql_log/mysqld-relay-bin 

#plugin-load = semisync_master.so
log_slave_updates = on
master_info_repository = TABLE
relay_log_info_repository =TABLE

#######主主複製新增的配置###########
auto_increment_increment = 2    # 控制自增ID增加的步長,默認爲1
auto_increment_offset = 2 # 控制自增ID從哪一個值開始
#####################

# gtid_mode = on
# enforce_gtid_consistency =on
# skip-slave-start =1
#rpl_semi_sync_master_enabled = 1
#rpl_semi_sync_master_timeout=200    # 0.2 second
master_info_respository = TABLE
# gtid_mode= on
# enforce_gtid_consistency = on
# skip-slave-start = 1

# DATA STORAGE #

datadir = /home/mysql/data     #mysql 數據文件存放的目錄
tmpdir = /tmp    # MySQL存放臨時文件的目錄

# BINARY LOGGING #

log_bin = /home/mysql/sql_log/mysql-bin
max_binlog_size  = 1000M
binlog_format = row
expire_log_days = 7
sync_binlog = 1

# CACHES AND LIMITS #

tmp_table_size = 32M
max_heap_table_size = 32M
query_cache_type = 0
mysql> show variables like 'auto%';
mysql> set global auto_increment_increment=2;
mysql> set global auto_increment_offset =2;

從服務器查看二進制日誌信息
命令

mysql> show master status \G

能夠查看當前使用的日誌文件
File:mysql-bin:000003
和日誌點
Position:25423894

而後去主服務器上使用change master命令

因爲從到主的複製鏈路以前已開啓過,如今只須要配置主到從的

2. 配置啓動主到從的複製鏈路

因爲是主主複製 是把當前的主看成從,把當前的從看成主,在主上配置的master_host的值是從的ip,

命令以下:

mysql> change master to master_host='192.168.2.100',
        -> master_user='dba_repl',
        -> master_password='123456',
        ->MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=25423894;

mysql> start slave;

3. 在主DB、主備DB的服務器上分別安裝keepalived

yum install keepalived -y
[root@localhost ~]# cd /etc/keepalived/
[root@localhost keepalived]# ls
check_mysql.sh  keepalived.bak    keepalived.conf

check_mysql.sh 必定要有執行權限

chmod a+x check_mysql.sh

4. 主從服務器分別啓動keepalived

[root@localhost keepalived]#  /etc/init.d/keepalived start

啓動成功後,能夠經過ip addr命令查看虛擬ip
能夠經過手動關閉mysql模式宕機,查看主的ip addr中的虛擬Ip已不存在,此時已虛擬Ip在從服務器上

五. 目前架構存在的問題

目前架構:

一臺主服務器,一臺從服務器,加入了keepalived服務來監控主從服務器的運行健康狀態,並經過keepalived服務器生成了一個虛擬IP,前端應用是經過虛擬IP來進行數據庫的訪問,而且爲了使主庫宕機後能儘快恢復,把原來的主從複製改成了主主複製

存在的問題:

可是目前的讀寫操做還只是所有經過虛擬IP使用同一臺數據庫服務器(主服務器或主備服務器)來進行訪問的,因此這個架構也沒有解決單臺數據庫服務器讀寫壓力大的問題

對於數據庫服務器來講,讀負載和寫負載是兩個不一樣的問題

  1. 寫操做只能在Master數據庫上執行
  2. 讀操做既能夠在Master庫上執行,也能夠在Slave庫上執行

相對於寫負載,解決讀負載要更容易,由於咱們能夠很容易的獲得多個slave服務器,而且在正常的業務環境中數據庫所執行的讀操做次數要遠遠高於寫操做的次數
同時那些有性能問題的慢查詢,也都是讀操做產生的

六. 如何解決讀壓力大的問題?

  1. 進行讀寫分離,主服務器主要執行寫操做
  2. 讀操做的壓力平均分攤到不一樣的SLAVE服務器上
  3. 增長前端緩存服務器如Redis,memcache等
    推薦使用redis緩存服務器,redis優勢:可持久化,可主從複製,可集羣

解決方式見:如何解決MySQL讀壓力大的問題

七. 如何解決寫壓力大的問題

MySQL複製沒法緩解寫壓力

利用緩存,合併屢次寫爲一次寫
緩解寫壓力須要對MasterDB進行拆分

前面數據庫操做規範中說過,程序所使用的數據庫帳號只能在同一個數據庫下進行操做,不容許跨庫查詢數據庫

對MasterDB進行拆分的步驟

MasterDB中有mc_userdb、mc_productdb、mc_orderdb三個數據庫

步驟1:按需求創建新的DB集羣

創建好新的數據庫集羣后,就能夠在新老集羣之間創建主從同步關係,把要拆分的DB同步到新的集羣中
即 把mc_productdb同步到商品集羣中 ,mc_orderdb同步到訂單集羣中

步驟2:同步要拆分的DB到新的集羣中

當數據庫同步成功後,找一個業務的低峯時間段,好比凌晨三、4點時,把老集羣上數據庫的帳號,遷移到新的數據庫集羣中

步驟3:遷移數據庫帳號到對應的新集羣

遷移成功後,修改老集羣的應用在老集羣數據庫上的連接,把
對mc_productdb和mc_orderdb上的連接修改到新的集羣上

步驟4:修改前臺應用的數據庫連接

步驟5:刪除以前創建的老數據庫集羣到新數據庫集羣的數據庫同步連接,將老集羣上的mc_productdb和mc_orderdb備份後進行刪除

相關文章
相關標籤/搜索