本發(fā)明涉及非關系型的數(shù)據(jù)庫技術領域,具體地說是一種基于Gossip通信協(xié)議和Raft選舉算法的優(yōu)化方法。
背景技術:
Redis集群是由N×(n+1)個Redis服務器節(jié)點構成的分布式集群,服務器節(jié)點分為N個主節(jié)點和N×n個從節(jié)點,一個主節(jié)點對應n個從節(jié)點,主節(jié)點負責對處理槽以及相應的客戶操作,從節(jié)點復制備份主節(jié)點的數(shù)據(jù)。在主節(jié)點故障后,Redis集群通過Gossip通信協(xié)議來判斷故障的主節(jié)點處于下線狀態(tài),并停止接收客戶端的請求;隨后加入相應的故障轉移過程,對應的從節(jié)點在通過Raft選舉算法獲得個主節(jié)點的支持票后,升為新的主節(jié)點,代替原先主節(jié)點的功能,使得集群恢復成功。
作為一種分布式集群,穩(wěn)定性和可靠性非常重要,但是目前的Redis集群在主節(jié)點故障后,恢復時間不穩(wěn)定且耗時較長,甚至無法成功恢復,并且隨著故障主節(jié)點數(shù)目的增加,Redis集群的恢復時間增長很快;當用戶執(zhí)行比較耗時的操作時,Redis集群會產(chǎn)生錯誤的主從切換。這些都與Redis集群現(xiàn)有的Gossip通信協(xié)議和Raft選舉算法的具體實現(xiàn)有關,其中Gossip通信協(xié)議是一種最終一致性算法,不能保證在某個時間點使整個集群的所有節(jié)點達到一致的狀態(tài);Raft選舉算法是一種基于日志副本同步的一致性算法,可分成主節(jié)點選舉,日志同步和安全提交。
技術實現(xiàn)要素:
本發(fā)明是為了克服現(xiàn)有技術存在的不足之處,提供一種基于Gossip通信協(xié)議和Raft選舉算法的優(yōu)化方法,以期能克服現(xiàn)有Redis集群的上述缺陷,從而能在不影響Redis集群的吞吐量和時延的基礎上,縮短Redis集群的恢復時間,提升Redis集群的可靠性和穩(wěn)定性。
本發(fā)明為達到上述發(fā)明目的,采用如下技術方案:
本發(fā)明一種基于Gossip通信協(xié)議和Raft選舉算法的優(yōu)化方法,是應用于由N×(n+1)個節(jié)點組成的Redis集群中,所述節(jié)點是運行在集群模式下的Redis服務器,并分為N個主節(jié)點和N×n個從節(jié)點,任意一個主節(jié)點分別對應于n個從節(jié)點,由一個主節(jié)點及其對應的n個從節(jié)點構成一個分片;其特點是,所述優(yōu)化方法按如下步驟進行:
步驟1、全局定義:
定義所述N個主節(jié)點構成的主節(jié)點集合為{M1,M2,…,Mi,…,MN},Mi表示第i個主節(jié)點;1≤i≤N;
定義所述第i個主節(jié)點Mi的從節(jié)點集合為{Si1,Si2,…,Sij,…,Sin},Sij表示第i個主節(jié)點Mi所對應的第j個從節(jié)點;1≤j≤n;
定義Redis集群中的所有節(jié)點集合為{N1,N2,…,Nk,…,NN×(n+1)},Nk表示第k個節(jié)點,1≤k≤N×(n+1);
定義保存所述第k個節(jié)點Nk詳細狀態(tài)信息的結構體為第k個狀態(tài)結構體CNk;
定義保存并維護所述第k個節(jié)點Nk對Redis集群認知的結構體為第k個認知結構體CSk,所述第k個認知結構體CSk中所保存的信息包括:當前紀元、上一次投票紀元和Redis集群中所有節(jié)點的狀態(tài)結構體;定義第k個認知結構體CSk中的當前紀元記為CEk、上一次投票紀元記為LEk、所有節(jié)點的狀態(tài)結構體所組成的鏈表為NOk;
定義任意第p個節(jié)點Np和第q個節(jié)點Nq之間周期性的通信消息為PING/PONG消息;1≤p,q≤N×(n+1);p≠q;
所述第p個節(jié)點Np發(fā)送的PING/PONG消息中攜帶自身的狀態(tài)信息和相應的Gossip單元;定義所述Gossip單元包含w條Gossip消息;每條Gossip消息對應一個其他節(jié)點的狀態(tài)信息,通過Redis集群中的PING/PONG消息傳播,所述第p個節(jié)點Np更新自身的認知結構體CSp;
定義節(jié)點間的通信超時時間為T;
定義所述Redis集群中的所有節(jié)點分為三種狀態(tài),包括:在線狀態(tài)、疑似下線狀態(tài)、下線狀態(tài);
在線狀態(tài)表示第p個節(jié)點Np在發(fā)送PING消息后,在通信超時時間T內收到接收第q個節(jié)點Nq的PONG消息,則第q個節(jié)點Nq認為第p個節(jié)點Np處于在線狀態(tài);
疑似下線狀態(tài)表示第p個節(jié)點Np在發(fā)送PING消息后,在通信超時時間T內沒有收到接收第q個節(jié)點Nq的PONG消息,則第p個節(jié)點Np認為第q個節(jié)點Nq處于疑似下線狀態(tài);
下線狀態(tài)表示第p個節(jié)點Np發(fā)現(xiàn)超過個主節(jié)點認為第q個節(jié)點Nq處于疑似下線狀態(tài),則第p個節(jié)點Np認為第q個節(jié)點Nq處于下線狀態(tài),并將第q個節(jié)點Nq的下線消息廣播給其他節(jié)點;
定義在Redis集群中第k個節(jié)點Nk的鏈表NOk中處于疑似下線狀態(tài)的節(jié)點數(shù)為uk;
定義選取次數(shù)為r,并初始化r=1;
步驟2、第k個節(jié)點Nk每秒鐘固定向其他m個接收節(jié)點發(fā)送PING消息;
步驟3、基于Gossip通信協(xié)議優(yōu)化方法對m的值和接收節(jié)點的選取方式進行更改:
步驟3.1、令
步驟3.2、第k個節(jié)點Nk在Redis集群中未選取的節(jié)點內第r次隨機選取一個預接收節(jié)點,判斷所述預接收節(jié)點與第k個節(jié)點Nk之間中斷PING/PONG通信的時間是否超過T/2,若超過,則將所述預接收節(jié)點作為接收節(jié)點;否則,丟棄所述預接收節(jié)點;
步驟3.3、將r+1賦值給r,并返回步驟3.2執(zhí)行,直到r=m+1為止,從而獲得m1個接收節(jié)點;
步驟3.4、判斷m1=m是否成立,若成立,則執(zhí)行步驟3.8,否則執(zhí)行步驟3.5;
步驟3.5、初始化r=1;
步驟3.6、第k個節(jié)點Nk在Redis集群中未選取的節(jié)點內第r次隨機選取一個接收節(jié)點;
步驟3.7、將r+1賦值給r,并返回步驟3.6執(zhí)行,直到r=m-m1+1為止,從而獲得m-m1個接收節(jié)點;
步驟3.8、第k個節(jié)點Nk向m個接收節(jié)點發(fā)送PING消息;
步驟4、主節(jié)點M′故障后,第k個節(jié)點Nk向主節(jié)點M′發(fā)送PING消息,并在通信超時時間T內未收到主節(jié)點M′的PONG消息,則第k個節(jié)點Nk認為主節(jié)點M′處于疑似下線狀態(tài),并將所述主節(jié)點M′的狀態(tài)信息作為一條Gossip消息添加到PING/PONG消息的Gossip單元中,并發(fā)送給其他節(jié)點,從而告知其他節(jié)點主節(jié)點M′處于疑似下線狀態(tài);
步驟5、通過PING/PONG消息的傳播,主節(jié)點M′的疑似下線消息會在Redis集群中擴散,基于Gossip通信協(xié)議的優(yōu)化方法對w的值和Gossip單元的選取方式進行更改:
步驟5.1、令wk=w+uk;
步驟5.2、第k個節(jié)點Nk標記uk個處于疑似下線狀態(tài)的節(jié)點,并將所述uk個節(jié)點的狀態(tài)信息優(yōu)先添加到自身PING/PONG消息的Gossip單元中;
步驟5.3、第k個節(jié)點Nk在未選取的節(jié)點中隨機選取w個節(jié)點,并將所述w個節(jié)點的狀態(tài)信息優(yōu)先添加到自身PING/PONG消息的Gossip單元中;從而共選取w+uk個節(jié)點作為wk個Gossip消息添加到Gossip單元中;
步驟6、通過PING/PONG消息的傳播,第p個節(jié)點Np發(fā)現(xiàn)超過個主節(jié)點認為主節(jié)點M′處于疑似下線狀態(tài),則第p個節(jié)點Np認為主節(jié)點M′處于下線狀態(tài),并將主節(jié)點M′的下線消息廣播給其他節(jié)點;從而使得主節(jié)點M′處于下線狀態(tài)的消息在Redis集群中傳播;
步驟7、假設發(fā)生故障的主節(jié)點M′所對應的主節(jié)點為第i個主節(jié)點Mi;則當從節(jié)點集合{Si1,Si2,…,Sij,…,Sin}接收到的PING/PONG消息中包含主節(jié)點M′處于下線狀態(tài)的信息時,第j個從節(jié)點Sij向所有節(jié)點發(fā)起投票請求;
步驟8、第k個節(jié)點Nk接收到所述第j個從節(jié)點Sij的投票請求,則基于Raft選舉算法對投票方式進行更改:
步驟8.1、第k個節(jié)點Nk將認知結構體CSk上的當前紀元CEk和上一次投票紀元LEk保存到鏈表NOk的所有狀態(tài)結構體中;從而使得所有狀態(tài)結構體中均保存各自的當前紀元和上一次投票紀元;
步驟8.2、若第k個節(jié)點Nk是主節(jié)點,則獲得發(fā)生故障的主節(jié)點M′在所有節(jié)點中所在的位置z后,第k個節(jié)點Nk通過認知結構體CSk保存的第z個狀態(tài)結構體CNz上的當前紀元和上一次投票紀元來判斷是否發(fā)送支持票給第j個從節(jié)點Sij;若第k個節(jié)點Nk是從節(jié)點,則第k個節(jié)點Nk對投票請求不做任何處理;
步驟9、當?shù)趈個從節(jié)點Sij接收到個主節(jié)點的支持票時,第j個從節(jié)點Sij升為新的主節(jié)點,代替原來主節(jié)點的功能,并通過廣播PING消息告知所有的其他節(jié)點,從而使得Redis集群中所有節(jié)點得知第j個從節(jié)點Sij升為主節(jié)點;
步驟10、Redis集群恢復成功。
與已有技術相比,本發(fā)明有益效果體現(xiàn)在:
1、本發(fā)明提出并實現(xiàn)一種基于Gossip通信協(xié)議的優(yōu)化方法,在不影響Redis集群性能的情況下,使Redis集群在較短時間內從故障中恢復,Redis集群恢復過程的效率提升了30%,有效降低了節(jié)點故障對Redis集群造成的損失;相對于現(xiàn)有的Redis集群,優(yōu)化后的Redis集群在穩(wěn)定性和可靠性上有顯著提升;
2、本發(fā)明提出并實現(xiàn)一種基于Raft選舉算法的優(yōu)化方法,將來自不同分片的投票請求進行單獨的投票,使得一個主節(jié)點可以對不同分片的節(jié)點進行投票,有效規(guī)避了重新投票的情況,從而提升了集群的穩(wěn)定性和可靠性。
附圖說明
圖1為節(jié)點之間PING/PONG消息通信過程示意圖;
圖2為Redis集群成功恢復的全過程示意圖;
圖3為恢復階段詳細示意圖;
圖4為現(xiàn)有Redis集群的結構體表示示意圖;
圖5為優(yōu)化后Redis集群的數(shù)據(jù)結構表示示意圖。
具體實施方式
下面結合附圖通過具體實施例對本發(fā)明基于Gossip通信協(xié)議和Raft選舉算法的優(yōu)化方法做進一步的詳細說明。
本實施例中,一種基于Gossip通信協(xié)議和Raft選舉算法的優(yōu)化方法,是應用于由N×(n+1)個節(jié)點組成的Redis集群中,節(jié)點是運行在集群模式下的Redis服務器,并分為N個主節(jié)點和N×n個從節(jié)點,任意一個主節(jié)點分別對應于n個從節(jié)點,由一個主節(jié)點及其對應的n個從節(jié)點構成一個分片;該優(yōu)化方法按如下步驟進行:
步驟1、全局定義:
定義N個主節(jié)點構成的主節(jié)點集合為{M1,M2,…,Mi,…,MN},Mi表示第i個主節(jié)點;1≤i≤N;
定義第i個主節(jié)點Mi的從節(jié)點集合為{Si1,Si2,…,Sij,…,Sin},Sij表示第i個主節(jié)點Mi所對應的第j個從節(jié)點;1≤j≤n;
定義Redis集群中的所有節(jié)點集合為{N1,N2,…,Nk,…,NN×(n+1)},Nk表示第k個節(jié)點,1≤k≤N×(n+1);
定義保存第k個節(jié)點Nk詳細狀態(tài)信息的結構體為第k個狀態(tài)結構體CNk,第k個狀態(tài)結構體CNk保存的信息包括節(jié)點的名稱、所管理的槽數(shù)量、所屬分片的主節(jié)點名稱和下線報告;定義在第k個狀態(tài)結構體CNk上節(jié)點的名稱為NAk;定義在第k個狀態(tài)結構體CNk上所管理的槽數(shù)量為SLk;定義在第k個狀態(tài)結構體CNk上所屬分片的主節(jié)點名稱為NSk;定義在第k個狀態(tài)結構體CNk上的下線報告為FRk;
定義保存并維護第k個節(jié)點Nk對Redis集群認知的結構體為第k個認知結構體CSk,第k個認知結構體CSk中所保存的信息包括:當前紀元、上一次投票紀元和Redis集群中所有節(jié)點的狀態(tài)結構體;定義第k個認知結構體CSk中的當前紀元記為CEk、上一次投票紀元記為LEk、所有節(jié)點的狀態(tài)結構體所組成的鏈表為NOk;
定義任意第p個節(jié)點Np和第q個節(jié)點Nq之間周期性的通信消息為PING/PONG消息;1≤p,q≤N×(n+1);p≠q;
第p個節(jié)點Np發(fā)送的PING/PONG消息中攜帶自身的狀態(tài)信息和相應的Gossip單元;定義Gossip單元包含w條Gossip消息;每條Gossip消息對應一個其他節(jié)點的狀態(tài)信息,通過Redis集群中的PING/PONG消息傳播,第p個節(jié)點Np更新自身的認知結構體CSp;
定義節(jié)點間的通信超時時間為T;
定義Redis集群中的所有節(jié)點分為三種狀態(tài),包括:在線狀態(tài)、疑似下線狀態(tài)、下線狀態(tài);
在線狀態(tài)表示第p個節(jié)點Np在發(fā)送PING消息后,在通信超時時間T內收到接收第q個節(jié)點Nq的PONG消息,則第q個節(jié)點Nq認為第p個節(jié)點Np處于在線狀態(tài);
疑似下線狀態(tài)表示第p個節(jié)點Np在發(fā)送PING消息后,在通信超時時間T內沒有收到接收第q個節(jié)點Nq的PONG消息,則第p個節(jié)點Np認為第q個節(jié)點Nq處于疑似下線狀態(tài);
下線狀態(tài)表示第p個節(jié)點Np發(fā)現(xiàn)超過個主節(jié)點認為第q個節(jié)點Nq處于疑似下線狀態(tài),則第p個節(jié)點Np認為第q個節(jié)點Nq處于下線狀態(tài),并將第q個節(jié)點Nq的下線消息廣播給其他節(jié)點;
定義在Redis集群中第k個節(jié)點Nk的鏈表NOk中處于疑似下線狀態(tài)的節(jié)點數(shù)為uk;
定義選取次數(shù)為r,并初始化r=1;
步驟2、圖1給出了Redis集群中PING/PONG消息通信的大致過程,此步驟中的發(fā)送節(jié)點為第k個節(jié)點Nk,第k個節(jié)點Nk每秒鐘固定向其他m個接收節(jié)點發(fā)送PING消息;
步驟3、基于Gossip通信協(xié)議優(yōu)化方法對m的值和接收節(jié)點的選取方式進行更改,是對圖1中發(fā)送節(jié)點的發(fā)送PING消息的實現(xiàn)過程進行更改:
步驟3.1、m的值與下線判斷的耗時成反比關系,并且為了適應不同的集群,優(yōu)化方法將參數(shù)m設置成和集群主節(jié)點數(shù)目相關的參數(shù);令即每秒鐘選取個接收節(jié)點發(fā)送PING消息:在的時間內節(jié)點可以與集群中所有的其他節(jié)點至少通信一次,將接收節(jié)點平均到每秒鐘去,這樣可以避免在最后時刻有較多的未通信節(jié)點;這種設置既能保證原來的通信量,又能對節(jié)點間的消息發(fā)送在時間分布上做一個均衡;
步驟3.2、對于m個接收節(jié)點的選取,最多在2×m次循環(huán)中選出,第k個節(jié)點Nk在Redis集群中未選取的節(jié)點內第r次隨機選取一個預接收節(jié)點,判斷預接收節(jié)點與第k個節(jié)點Nk之間中斷PING/PONG通信的時間是否超過T/2,若超過,則將預接收節(jié)點作為接收節(jié)點;否則,丟棄預接收節(jié)點;
步驟3.3、將r+1賦值給r,并返回步驟3.2執(zhí)行,直到r=m+1為止,從而獲得m1個接收節(jié)點,這是前m次循環(huán);
步驟3.4、判斷m1=m是否成立,若成立,則執(zhí)行步驟3.8,否則執(zhí)行步驟3.5;
步驟3.5、初始化r=1;
步驟3.6、第k個節(jié)點Nk在Redis集群中未選取的節(jié)點內第r次隨機選取一個接收節(jié)點;
步驟3.7、將r+1賦值給r,并返回步驟3.6執(zhí)行,直到r=m-m1+1為止,從而獲得m-m1個接收節(jié)點,r的最大值為m;
步驟3.8、第k個節(jié)點Nk向m個接收節(jié)點發(fā)送PING消息,這樣既能盡可能得選取與第k個節(jié)點Nk之間中斷PING/PONG通信時間超過T/2的接收節(jié)點,也能減低選取接收節(jié)點造成的性能開銷;
步驟4、圖2以主節(jié)點M′故障為例,展示主節(jié)點下線恢復的整個過程,分為疑似下線階段、下線階段和恢復階段;圖2中疑似下線階段:第k個節(jié)點Nk向發(fā)生故障的主節(jié)點M′發(fā)送PING消息,并在通信超時時間T內未收到主節(jié)點M′的PONG消息,則第k個節(jié)點Nk認為主節(jié)點M′處于疑似下線狀態(tài),并將主節(jié)點M′的狀態(tài)信息作為一條Gossip消息添加到PING/PONG消息的Gossip單元中,并發(fā)送給其他節(jié)點,從而告知其他節(jié)點主節(jié)點M′處于疑似下線狀態(tài);
步驟5、通過PING/PONG消息的傳播,主節(jié)點M′的疑似下線消息會在Redis集群中擴散,基于Gossip通信協(xié)議的優(yōu)化方法對w的值和Gossip單元的選取方式進行更改,是對圖1中接收節(jié)點的回復PONG消息的實現(xiàn)過程進行更改:
步驟5.1、令wk=w+uk;
步驟5.2、第k個節(jié)點Nk標記uk個處于疑似下線狀態(tài)的節(jié)點,并將uk個節(jié)點的狀態(tài)信息優(yōu)先添加到自身PING/PONG消息的Gossip單元中,此舉的目的是為了增加Gossip單元中疑似下線的節(jié)點狀態(tài)信息的比例;
步驟5.3、第k個節(jié)點Nk在未選取的節(jié)點中隨機選取w個節(jié)點,并將w個節(jié)點的狀態(tài)信息優(yōu)先添加到自身PING/PONG消息的Gossip單元中;從而共選取w+uk個節(jié)點作為wk個Gossip消息添加到Gossip單元中,由步驟3和步驟5組成的基于Gossip通信協(xié)議的優(yōu)化方法可以盡量加快所有節(jié)點的疑似下線消息在Redis集群內的傳播速度;當主節(jié)點的疑似下線消息能夠快速的在Redis集群內傳播,便可以有效減少Redis集群檢測主節(jié)點從的疑似下線階段到的下線階段的時間,如圖2中所示;
步驟6、圖2中下線階段:通過PING/PONG消息的傳播,第p個節(jié)點Np發(fā)現(xiàn)超過個主節(jié)點認為主節(jié)點M′處于疑似下線狀態(tài),則第p個節(jié)點Np認為主節(jié)點M′處于下線狀態(tài),并將主節(jié)點M′的下線消息廣播給其他節(jié)點;從而使得主節(jié)點M′處于下線狀態(tài)的消息在Redis集群中傳播;
步驟7、步驟7~10是圖2中恢復階段,并且圖3展示了恢復階段的詳細過程,假設發(fā)生故障的主節(jié)點M′所對應的主節(jié)點為第i個主節(jié)點Mi;則當從節(jié)點集合{Si1,Si2,…,Sij,…,Sin}接收到的PING/PONG消息中包含主節(jié)點M′處于下線狀態(tài)的信息時,第j個從節(jié)點Sij向所有節(jié)點發(fā)起投票請求;
步驟8、第k個節(jié)點Nk接收到第j個從節(jié)點Sij的投票請求,則基于Raft選舉算法對投票方式進行更改:
步驟8.1、第k個節(jié)點Nk將認知結構體CSk如圖4所示,將第k個節(jié)點Nk將認知結構體CSk上的當前紀元CEk和上一次投票紀元LEk保存到鏈表NOk的所有狀態(tài)結構體中;從而使得所有狀態(tài)結構體中均保存各自的當前紀元和上一次投票紀元,如在圖5中NOk的CNz上的ICEz和ILEz;1≤z≤N×(n+1);
步驟8.2、若第k個節(jié)點Nk是主節(jié)點,則獲得發(fā)生故障的主節(jié)點M′在所有節(jié)點中所在的位置z后,第k個節(jié)點Nk通過認知結構體CSk保存的第z個狀態(tài)結構體CNz上的當前紀元和上一次投票紀元來判斷是否發(fā)送支持票給第j個從節(jié)點Sij,即通過圖5中CNz上的當前紀元ICEz和上一次投票紀元ILEz來判斷是否投票給第j個從節(jié)點Sij;若第k個節(jié)點Nk是從節(jié)點,則第k個節(jié)點Nk對投票請求不做任何處理;1≤z≤N×(n+1);由步驟8構成的基于Raft選舉算法的優(yōu)化方法將當前紀元CEk和上一次投票紀元LEk分散保存每個節(jié)點的狀態(tài)結構體中,能對來自不同分片的投票請求進行單獨的比較,從而成功規(guī)避圖3中重新投票的情況;
步驟9、當?shù)趈個從節(jié)點Sij接收到個主節(jié)點的支持票時,第j個從節(jié)點Sij升為新的主節(jié)點,代替原來主節(jié)點的功能,并通過廣播PING消息告知所有的其他節(jié)點,從而使得Redis集群中所有節(jié)點得知第j個從節(jié)點Sij升為主節(jié)點。
步驟10、Redis集群恢復成功。