手動搭建Redis集群和MySQL主從同步(非Docker)

前言

一直都想自己動手搭建一個Redis集群和MySQL的主從同步,當然不是依靠Docker的一鍵部署(雖然現(xiàn)在企業(yè)開發(fā)用的最多的是這種方式),所以本文就算是一個教程類文章吧,但在動手搭建之前,會先聊聊理論的東西,以便于大家有一個集群主從同步的概念,如果有同學不了解Redis和MySQL,可以看一下我之前的兩篇文章。

Redis由淺入深深深深深剖析

【從入門到入土】令人脫發(fā)的數(shù)據(jù)庫底層設(shè)計

什么是Redis集群

  • 簡介

    Redis是一個快速高效的NoSQL型數(shù)據(jù)庫,由于其基于內(nèi)存存儲、單線程、多路IO復(fù)用的特性,其QPS可以達到驚人的100000+(官方數(shù)據(jù)),但是即使有這么高的速度,在中國這么大的網(wǎng)民基數(shù)環(huán)境下,也存在著性能瓶頸。首先拋開服務(wù)器故障不談,Redis集群首先可以使Redis性能得到線性提高,這是毋庸置疑的,其次Redis集群除了解決了效率問題,還可以解決服務(wù)器宕機造成的數(shù)據(jù)丟失問題,當某個Redis節(jié)點宕機,剩下的節(jié)點會繼續(xù)工作,并不會影響整體集群的使用,從而實現(xiàn)高可用

  • Redis單機模式有什么問題

    • 單機故障

      在單機模式下的Redis,我們的應(yīng)用中所有需要緩存的數(shù)據(jù)都依賴一臺Redis服務(wù)器,應(yīng)用的流量小可能看不出什么問題,但是隨著應(yīng)用越來越大,流量越來越大,如果出現(xiàn)服務(wù)器宕機或者斷電的狀況,那么我們的應(yīng)用整個一個緩存層在一段時間內(nèi)(重啟)都將不復(fù)存在,先不談基于Redis的分布式Session可能造成的問題,如果恰好遇上流量高峰,這些流量直接打在數(shù)據(jù)庫上,我們知道數(shù)據(jù)庫的IO效率遠不及Redis,這將大大提高應(yīng)用負載,容易出現(xiàn)數(shù)據(jù)庫服務(wù)器的宕機,從而造成應(yīng)用的宕機。由此看來,單機版Redis如果出現(xiàn)故障,將有可能引起一系列的連鎖反應(yīng),造成不可逆的損失。

    • 容量瓶頸

      我們知道Redis是基于內(nèi)存存儲的一個NoSQL數(shù)據(jù)庫,基于內(nèi)存也是其高速高效的原因之一。雖然容量瓶頸在實際生產(chǎn)中并不常見(通常有意識地將搭載Redis的機器內(nèi)存容量加高),但是不排除在某些極端條件下Redis會將一臺機器的內(nèi)存耗盡,造成數(shù)據(jù)丟失,甚至服務(wù)器宕機。

    • 性能瓶頸

      簡介中提到,雖然Redis在官方文檔中提到可以達到約100000+QPS,但是首先在日常環(huán)境的測試中,我們可能并達不到文檔中宣稱的QPS,換言之,這可能也就是一種理論值,就像是4G的理論網(wǎng)速在10-100Mbps,折合下載速度1.5M/s-10M/s,但在日常生活中我們極少甚至從來沒有達到過這個速度過,一樣的道理。其次,在中國巨大的網(wǎng)民基數(shù)下,單機Redis滿足日常需求尚且捉襟見肘,如果碰上像雙十一、雙十二、春運這些特殊的環(huán)境,單臺Redis顯然會有性能不足的現(xiàn)象發(fā)生。

  • Redis集群的三種模式

    • 主從模式

      主從模式是最簡單的一種Redis集群模式,首先其思想就是一臺Redis服務(wù)器作為主服務(wù)器(Master),一臺或多臺服務(wù)器作為從服務(wù)器(Slave)。當以此種方式部署集群時,集群有如下特點:

      1. Master可以進行讀寫操作,當寫操作導致數(shù)據(jù)發(fā)生變化時,將自動同步給Slave,Slave通常是只讀的,并且接受從Master同步過來的數(shù)據(jù)。
      2. 一臺Master可以有多臺Slave,但每臺Slave只能有一個Master。
      3. 某臺Slave宕機不影響其他Slave和Master的讀寫,重新啟動后會將數(shù)據(jù)重新從Master同步過來。
      4. Master宕機后不影響Slave的讀,但該集群不再提供對Redis的寫入功能
      5. Master宕機后不會從Slave中選舉主節(jié)點。

      在此種模式下,我們可以對Redis集群做容災(zāi)備份讀寫分離,但是要注意,容災(zāi)備份并不能拯救你的誤操作,因為無論增刪改,Redis都將其作為寫,同步到每個Slave節(jié)點上,所以容災(zāi),是指不可預(yù)知的錯誤導致數(shù)據(jù)丟失,這種情況下可以從Slave節(jié)點中找到原數(shù)據(jù)的備份,從而進行數(shù)據(jù)恢復(fù)。而讀寫分離就比較好理解了,上文中提到,Master節(jié)點可以讀寫,而Slave節(jié)點通常只進行讀操作,索性直接將所有的讀操作都轉(zhuǎn)移到Slave節(jié)點上,這樣可以減輕Master節(jié)點的IO壓力。

      Redis主從

      主從模式的工作原理(全量同步):

      Redis全量同步一般發(fā)生在Slave初始化階段,但其實在任何時候Slave都可以向Master發(fā)起全量同步的請求,這時Slave需要將Master上的所有數(shù)據(jù)都復(fù)制一份。

      1. Slave連接主服務(wù)器,發(fā)送SYNC命令。
      2. Master接收到SYNC命令后,開始執(zhí)行BGSAVE命令生成RDB文件并使用緩沖區(qū)記錄此后執(zhí)行的所有寫命令。
      3. Master執(zhí)行完BGSAVE后,向所有從服務(wù)器發(fā)送RDB文件,并在發(fā)送期間繼續(xù)記錄被執(zhí)行的寫命令。
      4. Slave收到RDB文件后丟棄所有舊數(shù)據(jù),載入收到的RDB。
      5. Master快照發(fā)送完畢后開始向Slave發(fā)送緩沖區(qū)中的寫命令。
      6. Slave完成對RDB的載入,開始接收命令請求,并執(zhí)行來自Master緩沖區(qū)的寫命令。

      主從模式的工作原理(增量同步):

      Redis增量同步一般發(fā)生在Slave已經(jīng)初始化完成,開始正常連接Master的階段

      1. Master接收到寫請求,將寫命令發(fā)送到Slave。
      2. Slave執(zhí)行接收到的些命令。

      :如果多個Slave同時宕機重啟,那么就會同時向Master發(fā)送SYNC命令,那么有可能會造成Master節(jié)點的IO劇增,有可能會引起宕機。

    • 哨兵(Sentinel)模式

      上文中介紹了Redis主從復(fù)制模式下的集群策略,當Master宕機后,不會從Slave節(jié)點中選舉出Master,所以該集群喪失了寫的能力,我們只能人工去將Slave節(jié)點晉升為Master節(jié)點,同時要通知應(yīng)用方更新Master節(jié)點的IP地址,對于這種故障處理的方式在現(xiàn)在的環(huán)境下通常是不可接受的。所以從Redis2.8開始,Redis正式提供了哨兵模式的架構(gòu)(故障轉(zhuǎn)移),來解決這個問題。

      哨兵模式的工作特點

      1. 哨兵模式是建立在主從模式的基礎(chǔ)上,當Master節(jié)點宕機之后,哨兵會從Slave節(jié)點中選擇一個節(jié)點作為Master,并修改它們的配置文件,使其他的Slave指向新的Master。
      2. 當原先宕機的Master節(jié)點重新啟動時,他將不再是Master,而是作為新Master的一個Slave節(jié)點存在。
      3. 哨兵節(jié)點是一個特殊的Redis節(jié)點(不存儲數(shù)據(jù)),本質(zhì)上也是一個進程,所以也有掛掉的可能,所以哨兵也存在集群模式。

      哨兵模式工作原理

      1. 每隔10秒,每個哨兵節(jié)點會向Master和Slave節(jié)點發(fā)送info命令獲取最新的拓撲結(jié)構(gòu)。
      2. 每隔1秒,每個哨兵節(jié)點會向Master和Slave節(jié)點還有其它哨兵節(jié)點發(fā)送ping命令做心跳檢測,看看是否存在不可達的節(jié)點。
      3. 主觀下線,如果某個哨兵向一個節(jié)點發(fā)出的心跳檢測沒有得到響應(yīng),那么該哨兵認為該節(jié)點已經(jīng)下線。
      4. 客觀下線,當哨兵主觀下線的節(jié)點是主節(jié)點時,哨兵會向其他的哨兵詢問對主節(jié)點的判斷,當下線判斷超過一定個數(shù)時,那么哨兵會認為主節(jié)點確實已經(jīng)下線,那么會對主節(jié)點進行客觀下線的判定。
      5. 故障轉(zhuǎn)移,當Master節(jié)點客觀下線時,哨兵會從Slave節(jié)點中選擇一個節(jié)點作為Master節(jié)點,選擇規(guī)則是選擇與主節(jié)點復(fù)制相似度最高的節(jié)點,選擇完成后會將其余的Slave節(jié)點指向新的Master節(jié)點,并監(jiān)控原來的Master節(jié)點,當它回復(fù)后作為新Master節(jié)點的Slave存在,并且同步新Master節(jié)點的數(shù)據(jù)。
      6. 選舉領(lǐng)導者哨兵節(jié)點:當主節(jié)點被判斷客觀下線以后,各個哨兵節(jié)點會進行協(xié)商,選舉出一個領(lǐng)導者哨兵節(jié)點,并由該領(lǐng)導者節(jié)點對其進行故障轉(zhuǎn)移操作。
      7. 當使用sentinel模式的時候,客戶端不用直接連接Redis,而是連接哨兵的ip和port,由哨兵來提供具體的可提供服務(wù)的Redis實現(xiàn),這樣當master節(jié)點掛掉以后,哨兵就會感知并將新的master節(jié)點提供給使用者。
      Redis哨兵
    • Cluster模式

      在上文的哨兵模式中,哨兵引入了主節(jié)點的自動故障轉(zhuǎn)移,進一步提高了Redis的高可用性。但是哨兵的缺陷同樣很明顯:哨兵無法對Slave進行自動故障轉(zhuǎn)移,在讀寫分離場景下,Slave故障會導致讀服務(wù)不可用,需要我們對Slave做額外的監(jiān)控、切換操作。此外,哨兵仍然沒有解決寫操作無法負載均衡、及存儲能力受到單機限制的問題。

      Redis Cluster模式是Redis3.0之后推薦的一種解決方案,其是由多個主節(jié)點群組成的分布式服務(wù)器群,它具有復(fù)制、高可用和分片的特性。另外,Redis Cluster集群不需要哨兵也能完成節(jié)點移除和故障轉(zhuǎn)移的功能。需要將每個節(jié)點設(shè)置為集群模式,這種集群模式?jīng)]有中心節(jié)點,可水平擴展,且集群配置非常簡單。

      Cluster集群模式工作特點

      1. 多個Redis節(jié)點互聯(lián),數(shù)據(jù)共享。
      2. 所有的節(jié)點都是主從模式,其中Slave不提供服務(wù),只提供備用。
      3. 不支持同時處理多個Key,因為需要分發(fā)到多個節(jié)點上。
      4. 支持在線增加、刪除節(jié)點。
      5. 客戶端可以連接任何一個Master節(jié)點進行讀寫。

      Cluster集群模式工作原理

      1. Redis Cluster有固定的16384個hash slot(),對每個key計算CRC16值,然后對16384取模,可以獲取key對應(yīng)的hash slot。每個master都會持有部分slot,比如有3個master,那么可能每個master持有5000多個hash slot,在redis cluster寫入數(shù)據(jù)的時候,其實是你可以將請求發(fā)送到任意一個master上去執(zhí)行。但是,每個master都會計算這個key對應(yīng)的CRC16值,然后對16384個hashslot取模,找到key對應(yīng)的hashslot,找到hashslot對應(yīng)的master。
      2. 主觀下線(pfail):集群中的每個節(jié)點都會定期向其他節(jié)點發(fā)送ping消息,如果在一段時間內(nèi)一直通信失敗,則發(fā)送節(jié)點方認為接收節(jié)點存在故障,把接收節(jié)點標為主觀下線(pfail)狀態(tài)。
      3. 客觀下線(fail):當某個節(jié)點判斷另一個節(jié)點主觀下線后,相應(yīng)的節(jié)點狀態(tài)就會在集群中進行傳播,如果集群中所有節(jié)點都將它標為主觀下線,那么該節(jié)點為客觀下線,并通知該節(jié)點的Slave進行故障轉(zhuǎn)移操作。
      4. 故障轉(zhuǎn)移:在某個節(jié)點客觀下線后,該節(jié)點的從節(jié)點開始故障轉(zhuǎn)移流程,首先進行資格檢查,每個從節(jié)點檢查與主節(jié)點的斷開時間,超過一定時間的取消選舉資格,然后同樣在所有從節(jié)點中尋找復(fù)制偏移量最大的節(jié)點先開始進行選舉,只有持有槽的主節(jié)點才有投票權(quán),當從節(jié)點收集到過半的票數(shù)時,即晉升為Master,隨即通知Slave當前Master變?yōu)樽约骸?/li>
      RedisCluster

搭建Redis集群

上文中說了三種Redis搭建的模式,分別是主從模式、哨兵模式、Cluster模式,關(guān)于前兩種網(wǎng)上有著非常多的教程,這里就不再重新演示了,這里著重演示一下如何去搭建一個Redis Cluster集群。

  • 環(huán)境準備

    CentOS 7,Redis5.0.4

  • 場景描述

    本次會啟動三臺CentOS 7服務(wù)器,每臺服務(wù)器上搭載三個Redis實例,一主二從,一共三個Master實例,六個Slave實例。

    清單如下:

    Master 1:IP:192.168.43.101 Port:7001

    Master 2:IP:192.168.43.102 Port:7002

    Master 3:IP:192.168.43.103 Port:7003

    Slave 1:IP:192.168.43.101 Port:6001

    Slave 2:IP:192.168.43.102 Port:6002

    Slave 3:IP:192.168.43.103 Port:6003

    Slave 4:IP:192.168.43.101 Port:6004

    Slave 5:IP:192.168.43.102 Port:6005

    Slave 6:IP:192.168.43.103 Port:6006

  • 修改配置文件

    熟悉Redis的應(yīng)該明白,所謂Redis實例,實際上就是一個又一個的配置文件。要在服務(wù)器上啟動多臺不同Redis,實際上就是使用不同的配置文件來啟動Redis,所以第一步我們要先對集群中的每一個Redis實例配置不一樣的配置文件。

    • 綁定Redis地址

      下列三臺主機上的配置文件均為Master節(jié)點配置文件(修改bind屬性)

      RedisCluster實操1
    • 修改端口號

      將端口號修改為自定義的端口號,默認為6379,修改為我們自定義的端口號。

      RedisCluster實操2
    • 開啟集群模式并設(shè)置集群配置文件

      將cluster-enabled 設(shè)置為yes,并將cluster-config-file設(shè)置為自定義的文件。

      這里定義為nodes-端口號.conf

      RedisCluster實操3
    • 修改集群RDB快照和AOF文件的存放位置

      修改dir屬性,這里定義為/home/redis-cluster/redis-master/

      RedisCluster實操4
    • 修改集群密碼

      修改masterauth屬性為Redis(RequirePass)密碼。

      RedisCluster實操5
    • 開啟AOF持久化

      修改appendonly屬性

      appendonly yes

    • 對六臺Slave節(jié)點進行同樣的修改配置操作

      注意:上述指定的文件夾和文件名原則上對于每個redis實例都應(yīng)該是唯一的,便于區(qū)分。

  • 啟動Redis實例

    運行命令:

    #第一臺主機
    /usr/local/bin/redis-server /home/redis-cluster/redis-master/redis-master-7001.conf
    /usr/local/bin/redis-server /home/redis-cluster/redis-slave/redis-slave-6001.conf
    /usr/local/bin/redis-server /home/redis-cluster/redis-slave/redis-slave-6004.conf
    
    #第二臺主機
    /usr/local/bin/redis-server /home/redis-cluster/redis-master/redis-master-7002.conf
    /usr/local/bin/redis-server /home/redis-cluster/redis-slave/redis-slave-6002.conf
    /usr/local/bin/redis-server /home/redis-cluster/redis-slave/redis-slave-6005.conf
    
    #第三臺主機
    /usr/local/bin/redis-server /home/redis-cluster/redis-master/redis-master-7003.conf
    /usr/local/bin/redis-server /home/redis-cluster/redis-slave/redis-slave-6003.conf
    /usr/local/bin/redis-server /home/redis-cluster/redis-slave/redis-slave-6006.conf
    
    
    

    查看進程 ps -ef | grep redis:

    RedisCluster實操6

    可以看到現(xiàn)在啟動的redis實例已經(jīng)是集群模式的了。

  • 搭建集群

    輸入命令:

    /usr/local/bin/redis-cli -a Object --cluster create --cluster-replicas 2 192.168.43.101:7001 192.168.43.102:7002 192.168.43.103:7003 192.168.43.101:6001 192.168.43.102:6002 192.168.43.103:6003 192.168.43.101:6004 192.168.43.102:6005 192.168.43.103:6006
    

    其中 --cluster-replicas 2代表每個Master攜帶2個Slave,那么就是三個Master,每個Master攜帶兩個Slave。

    示意圖如下:

    RedisCluster實操7

    我們可以看到,Redis將三臺機器連成了一個整體,Master7001的Slave指向了其它兩臺服務(wù)器上的Slave,而其它兩臺服務(wù)器的Master也同樣跨服務(wù)器指向了,這就是RedisCluster高可用的策略,假設(shè)有一臺服務(wù)器完整地宕機了,由于自己的Slave節(jié)點存在于別的服務(wù)器上,數(shù)據(jù)也能重新通過選舉選舉的方式恢復(fù),不易引起數(shù)據(jù)的丟失。

    RedisCluster實操9

    另外我們可以看到,我們在上文說過,Cluster集群模式將集群分為16384個槽,這里體現(xiàn)為0-16383,分布到了每一個Master節(jié)點上,這對我們之前的理論部分做了驗證。

  • 測試

    測試環(huán)節(jié)通過客戶端測試和Java程序測試,來模擬集群模式下Redis的存儲策略。

    • 客戶端測試

      開啟客戶端,隨意連接一個master節(jié)點

      /usr/local/bin/redis-cli -c -a 密碼 -h IP -p 端口

      RedisCluster實操8

      我們可以看到,當我們set一個鍵值對的時候,Redis會自動為我們的key計算CRC16值,然后對16384取模,獲取key對應(yīng)的hash slot,然后通過判斷該槽被那個Master所占用,幫我們重定向到那個Master節(jié)點,將鍵值對存入。

    • 程序測試

      在測試之前先把Redis中的數(shù)據(jù)清空。

      對三個Master節(jié)點分別執(zhí)行flushall命令。

      啟動程序:

      1. 正常存入數(shù)據(jù)時關(guān)閉某Master節(jié)點(模擬宕機):

        RedisCluster實操10

        程序打印正在選舉...

        RedisCluster實操11
      2. 選舉結(jié)束后繼續(xù)IO

        RedisCluster實操12

      代碼:

      public class JedisDemo {
          public static void main(String[] args) {
              
               JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); 
               Set<HostAndPort> nodes = new HashSet<>();
               nodes.add(new HostAndPort("192.168.43.101",7001));
               nodes.add(new HostAndPort("192.168.43.102",7002)); 
               nodes.add(new HostAndPort("192.168.43.103",7003)); 
               nodes.add(new HostAndPort("192.168.43.101",6001)); 
               nodes.add(new HostAndPort("192.168.43.102",6002)); 
               nodes.add(new HostAndPort("192.168.43.103",6003)); 
               nodes.add(new HostAndPort("192.168.43.101",6004)); 
               nodes.add(new HostAndPort("192.168.43.102",6005)); 
               nodes.add(new HostAndPort("192.168.43.103",6006)); 
               JedisCluster jedisCluster = new JedisCluster(nodes,100,1000,100,"Object","rediscluster",jedisPoolConfig,false);
               for(int i = 0;i<2000;i++) {
                   try {
                  System.out.println("存入數(shù)據(jù):"+i);
                   jedisCluster.set(String.valueOf(i),String.valueOf(i));
                       try {
                          Thread.sleep(300);
                      } catch (InterruptedException e) {
                          // TODO Auto-generated catch block
                  e.printStackTrace();
                      }
                       String res = jedisCluster.get(String.valueOf(i)); 
                       System.out.println("取出數(shù)據(jù):"+res);
                   }catch(Exception e) {
                       //出現(xiàn)節(jié)點宕機
                       System.out.println("正在選舉...");
                       System.out.println(new Date());
                       continue;
                   }
               }
                       
               jedisCluster.close();
          }
      }
      
    • 注意事項

      1. 在搭建集群的過程中有可能會遇到一直等待連接,但是集群無法連接成功的狀況,這是因為我們在搭建集群的時候防火墻沒有開啟對應(yīng)的端口號導致的,我們不光要開啟我們對外連接的端口號,如7001、7002、7003,還要開啟對外連接端口號+10000的端口,用于集群內(nèi)部相互通信,如節(jié)點端口為7001、7002、7003,那么我們還應(yīng)該開啟17001、17002、17003這些端口。
      2. 如果遇到搭建失敗的情況,重新搭建的時候一定要到dir指向的文件夾中將快照和AOF還有node.conf文件刪干凈,否則無法重新搭建。
  • 搭建完畢

    至此我們已經(jīng)完成了Redis集群的搭建,在私下實踐的時候可以試試使用Redis客戶端直接操作集群時手動關(guān)閉某個Master,會出現(xiàn)什么樣的狀況,這個是文章中沒有提到的內(nèi)容。

什么是MySQL主從同步

數(shù)據(jù)是一個應(yīng)用至關(guān)重要的一部分。從目的出發(fā),主從同步有那么點備份的意思,主庫(Master)將自己庫中的寫入同時同步給自己的從庫(Slave),當主庫發(fā)生某些不可預(yù)知的狀況,導致整個服務(wù)器無法使用時,由于從庫中也有一份數(shù)據(jù),所以數(shù)據(jù)可以做到快速恢復(fù),不造成或者減少造成數(shù)據(jù)的損失。當然,這只是第一個層面,如果主從庫的作用僅限于此,那么我個人認為沒有必要分為兩個數(shù)據(jù)庫,只需要定期將數(shù)據(jù)庫內(nèi)容作為快照發(fā)送到另一臺服務(wù)器,或者每次寫入時將寫入內(nèi)容實時發(fā)送到另一臺服務(wù)器不就好了嗎,這樣不但可以節(jié)約資源,也可以起到容災(zāi)備份的目的。當然主從同步的作用絕不可能僅限于此,一旦我們配置了主從結(jié)構(gòu),我們通常不會讓從節(jié)點僅僅只作為備份數(shù)據(jù)庫,我們應(yīng)該還會相應(yīng)地配置上讀寫分離可以使用MyCat或者其它中間件,可以自己了解一下,關(guān)于MyCat我在下一篇博客中會說這個,篇幅可能會有點長,所以就再寫一篇吧),在實際環(huán)境下,對于數(shù)據(jù)庫的讀操作數(shù)目遠大于對數(shù)據(jù)庫的寫操作,所以我們可以讓Master只提供寫的功能,然后將所有的讀操作都移到從庫,這就是我們平時常說的讀寫分離,這樣可以不但可以減輕Master的壓力,還可以做容災(zāi)備份,一舉兩得。

MySQL主從同步的原理

說完了主從同步的概念,下面來說說主從同步的原理,其實原理也非常簡單,沒有Redis集群那么多的概念。

實際上當我們在MySQL中配置了主從之后,只要我們對Master節(jié)點進行了寫操作,這個操作將會被保存到MySQL的binary-log(bin-log)日志當中,當slave連接到master的時候,master機器會為slave開啟binlog dump線程。當master 的 binlog發(fā)生變化的時候,Master的dump線程會通知slave,并將相應(yīng)的binlog內(nèi)容發(fā)送給Slave。而Slave節(jié)點在主從同步開啟的時候,會創(chuàng)建兩個線程,一個I/O線程,一個SQL線程,這在我們后面的搭建中可以親眼看到。

I/0線程:該線程鏈接到master機器,master機器的binlog發(fā)送到slave的時候,IO線程會將該日志內(nèi)容寫在本地的中繼日志(Relay log)中。

SQL線程:該線程讀取中繼日志中的內(nèi)容,并且根據(jù)中繼日志中的內(nèi)容對Slave數(shù)據(jù)庫做相應(yīng)的操作。

可能造成的問題:在寫請求相當多的情況下,可能會造成Slave數(shù)據(jù)和Master數(shù)據(jù)不一致的情況,這是因為日志傳輸過程中的短暫延遲、或者寫命令較多,系統(tǒng)速度不匹配造成的。

這大致就是MySQL主從同步的原理,真正在其中起到作用的實際上就是這兩個日志文件,binlog中繼日志。

MySQL主從同步原理

手動搭建MySQL主從同步

  • 環(huán)境準備

    本次搭建主從同步的環(huán)境:CentOS 7 ,MySQL 8.0.18(使用二進制包安裝)。

  • 場景介紹

    本次將會搭建MySQL的主從同步,其中一臺Master,兩臺Slave。

    Master:IP :192.168.43.201 Port:3306

    Slave1:IP:192.168.43.202 Port:3306

    Slave2:IP:192.168.43.203 Port:3306

  • 開始搭建

    • 修改配置文件

      當我們安裝好MySQL之后,在/etc/目錄下會有一個my.cnf文件,打開文件,加入如下內(nèi)容(別忘了修改之前做好備份):

      #該配置為Master的配置
      server-id=201 #Server id 每臺MySQL的必須不同
      log-bin=/var/lib/mysql/mysql-bin.log #代表開啟binlog日志
      expire_logs_days=10 #日志過期時間
      max_binlog_size=200M #日志最大容量
      binlog_ignore_db=mysql #忽略mysql庫,表示不同步此庫
      
      #該配置為Slave的配置,第二臺Slave也是這么配置,不過要修改一下server-id
      server-id=202
      expire_logs_days=10 #日志的緩存時間
      max_binlog_size=200M #日志的最大大小
      replicate_ignore_db=mysql #忽略同步的數(shù)據(jù)庫
      
    • 新增Slave用戶

      打開Master節(jié)點的客戶端 ,mysql -u root -p 密碼

      創(chuàng)建用戶 create user 'Slave'@'%' identified by '123456';

      給新創(chuàng)建的用戶賦權(quán):grant replication slave on '*.*' to 'Slave'@'%';

    • 查看Master節(jié)點狀態(tài)

      以上操作都沒有問題后,我們在客戶端中輸入show master status查看master的binlog日志。

      Redis主從2
    • 配置兩個Slave節(jié)點

      打開兩個Slave節(jié)點客戶端,在我們的另外兩個Slave節(jié)點中輸入如下命令:

      change master to master_user='Slave',master_password='123456',master_host='192.168.43.201',master_log_file='mysql-bin.000005',master_log_pos=155,get_master_public_key=1;
      #注意,這里的master_log_file,就是binlog的文件名,輸入上圖中的mysql-bin.000005,每個人的都可能不一樣。
      #注意,這里的master_log_pos是binlog偏移量,輸入上圖中的155,每個人的都可能不一樣。
      

      配置完成后,輸入start slave;開啟從節(jié)點,然后輸入show slave status\G;查看從節(jié)點狀態(tài)

      Redis主從3

      可以看到,在兩臺Slave的狀態(tài)中,我們能親眼看到IO線程和SQL線程的運行狀態(tài),這兩個線程必須都是yes,才算配置搭建完成。

  • 搭建完成

    通過上述步驟,就完成了MySQL主從同步的搭建,相對Redis而言MySQL配置相當簡單。下面我們可以進行測試。

    先看看三個MySQL的數(shù)據(jù)庫狀態(tài):SHOW DATABASES;

    Redis主從4

    可以看到現(xiàn)在數(shù)據(jù)庫都是初始默認狀態(tài),沒有任何額外的庫。

    在Master節(jié)點中創(chuàng)建一個數(shù)據(jù)庫,庫名可以自己設(shè)置。

    CREATE DATABASE testcluster;

    Redis主從5

    可以看到,在Slave中也出現(xiàn)了Master中創(chuàng)建的數(shù)據(jù)庫,說明我們的配置沒有問題,主從搭建成功。這里就不再創(chuàng)建表了,大家可以自己試試,創(chuàng)建表再往表中插入數(shù)據(jù),也是沒有任何問題的。

  • 注意事項

    1. 如果出現(xiàn)IO線程一直在Connecting狀態(tài),可以看看是不是三臺機器無法相互連接,如果可以相互連接,那么有可能是Slave賬號密碼寫錯了,重新關(guān)閉Slave然后輸入上面的配置命令再打開Slave即可。
    2. 如果出現(xiàn)SQL線程為NO狀態(tài),那么有可能是從數(shù)據(jù)庫和主數(shù)據(jù)庫的數(shù)據(jù)不一致造成的,或者事務(wù)回滾,如果是后者,先關(guān)閉Slave,然后先查看master的binlog和position,然后輸入配置命令,再輸入set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;,再重新start slave;即可,如通過是前者,那么就排查一下是不是存在哪張表沒有被同步,是否存在主庫存在而從庫不存在的表,自己同步一下再重新配置一遍即可。

結(jié)語

在寫這篇文章之前自己也被一些計算機領(lǐng)域的“名詞”嚇到過,相信有不少同學都有一樣的體會,碰上某些高大上的名詞總是先被嚇到,例如像“分布式”、“集群”等等等等,甚至在沒接觸過nginx之前,連”負載均衡“、”反向代理“這樣的詞都讓人覺得,這么高達上的詞,肯定很難吧,但其實自己了解了nginx、ribbon等之后才發(fā)現(xiàn),其實也就那么回事吧,沒有想象中的那么難。所以寫這篇文章的初衷是想讓大家對集群化或者分布式或者其他的一些技術(shù)或者解決方案不要有一種望而卻步的感覺(感覺計算機領(lǐng)域的詞都有這么一種特點,詞匯高大上,但是其實思想是比較好理解的),其實自己手動配置出一個簡單的集群并沒有那么難,如果學會docker之后再來配置就更加簡單了,但是更希望不要只局限于會配置,配置出來的東西只能說你會配置了,但是在這層配置底下是前人做了相當多的工作,才能使我們通過簡單配置就能實現(xiàn)一些功能,應(yīng)該要深入底層,了解配置下面的工作原理,這個才是最重要的,也是體現(xiàn)一個程序員水平的地方。

本文圖片來自網(wǎng)絡(luò),侵刪。

歡迎大家訪問我的個人博客:Object's Blog

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容