上篇文章:
RabbitMQ集群搭建https://blog.csdn.net/sniper_fandc/article/details/149312481?fromshare=blogdetail&sharetype=blogdetail&sharerId=149312481&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link
目錄
1 Raft一致性算法
1.1 角色劃分和相關名詞
1.2 Leader選舉
1.3 日志復制
2 仲裁隊列使用
2.1 配置文件
2.2 聲明仲裁隊列
2.3 生產者
2.4 演示仲裁隊列的復制
????????仲裁隊列是基于Raft一致性算法實現的隊列。其主要作用是提供復制能力,向其它節點復制消息從而保證集群的高可用性。要介紹仲裁隊列首先就需要了解Raft算法:
1 Raft一致性算法
????????Raft一致性算法是一種通過投票選擇主節點來保證節點之間達成共識的算法。通過選舉Leader(主節點),由Leader和客戶端進行交互,負責把客戶端的操作打包成日志然后把日志同步給其它從節點(日志復制),只有大部分從節點都成功同步并返回確認主節點才會認為此次操作成功。
????????關于Raft算法的具體細節見原文:
https://web.stanford.edu/~ouster/cgi-bin/papers/raft-atc14
1.1 角色劃分和相關名詞
????????Raft算法共有三種角色:
????????Leader(領導者):Leader就相當于主節點,負責和客戶端交互和日志復制,并且定期向所有Follower發送心跳包,防止Follower以為Leader掛掉而進入選舉Leader的流程。
????????Follower(跟隨者):Follower相當于從節點,接受來自Leader的日志并同步到本地,作用就是集群的副本。
????????Candidate(候選人):當Follower一段時間內接收不到Leader的心跳包(認為其掛掉了),就會出發選舉Leader的流程,此時Follower變為Candidate。
????????在三種角色的劃分下,整個集群的工作時間被劃分為兩個部分:選舉期(election)和任期(term)。選舉期就是進行Leader選舉時間的投票時期,Leader選舉成功后就會進入term,任期就是集群正常工作的時期。
????????term長度任意長(如果某次選舉期沒有選出Leader就認為該term長度為0,即沒有任期)。每個節點內部都記錄著current term(當前任期號,單調遞增),節點之間通信時會攜帶該任期號,當節點任期號小于通信節點的任期號,就會把當前任期號改為較大值。Candidate(可能沒有競爭過其它Candidate)或Leader(可能之前宕機后恢復或者Leader網絡恢復正常)如果接收到新Leader的心跳包,就會發現自己已經的term已經過期了,就會恢復Follower角色并修改任期號為最新值。
????????節點之間采用RPC通信,有兩種類型的請求:
????????RequestVote RPCs:請求投票,Candidate在選舉過程中發出。
????????AppendEntries RPCs:追加條目,Leader發出的日志復制和心跳機制。
1.2 Leader選舉
????????Leader選舉有三條規則:
????????1.每個節點只有一票;
????????2.Candidate超過半數節點投票就會選舉為Leader;
????????3.投票按照先來先到原則進行投。
????????而觸發選舉有兩個時機,一是集群啟動的初始時刻,此時沒有Leader,率先超過心跳包過期時間的進入Candidate發起投票。二是其它節點沒有及時接受到心跳包(故障或網絡問題),先發現問題的先進入Candidate發起投票。因此假設集群有5個節點,Leader選舉流程如下:
????????初始情況下,集群沒有Leader,節點外圈的環形進度條表示超時時間。S3節點會率先超時成為Candidate。
????????S3成為Candidate后發起投票,并先給自己投了一票,上圖綠色的則是請求投票的數據包(RequestVote RPCs)。
????????其它節點接受到投票請求后把各自唯一一票投給S3,于是S3接收到5票(超過半數投票),因此成為Leader。
????????S3成為Leader后向其它節點告知新的Leader的信息,發送心跳包(AppendEntries RPCs),如上圖黃色數據包。待接受其它節點的響應后,便開始正常的工作流程,如與客戶端交互、日志復制等,在任期期間,S3會不斷向Follower發送心跳包維持Leader任期。
????????對于Candidate除了成為Leader,還可能出現其它兩種情況:一是其它節點成為Leader;二是多個Candidate平票,無法選出Leader。
????????假設發生其它節點成為Leader:
????????S3先成為Candidate,S1后成為Candidate,因此S3獲得3票,S1只獲得2票,于是S3成為Leader。S3成為新Leader后向所有節點發送心跳包,此時S1處于Candidate狀態接收到心跳包后得知S3的term高于自己,說明已經有新Leader,于是變為Follower,開始正常工作。
????????假設發生多個Candidate平票:
????????這種情況常發生在偶數個節點參與投票,并且有多個Follower同時成為Candidate的時機。比如S1和S3同時成為Candidate,并各自收到其它節點1票和自己的一票,平票狀態無法選出Leader,因此會進行下一輪投票。
????????但是如果由于同時成為Candidate很有可能結束投票的時間也一致,因此下一輪還可能同時成為Candidate并平票。因此Raft算法采用隨機選舉超時時間:每個Candidate的投票期的時間在一個區間內隨機生成,保證各個Candidate的選舉時間不一樣,因此就很難出現同時選舉并平票的情況。
1.3 日志復制
????????成為Leader的節點負責和客戶端進行通信,其它節點作為副本。Leader把和客戶端的交互的消息打包成日志,并同步給其它節點。只有其它節點超過半數(同步較慢的節點并不影響整個集群的性能)都把消息同步到本地,并返回確認,Leader節點才會認為此次操作成功。
????????而仲裁隊列就是上述Raft算法運行的集群上的隊列,每個仲裁隊列有一個主和多個從副本,主副本在主節點(創建仲裁隊列的節點是主節點)上,從副本在從節點上。由主副本把消費復制到從副本上,當主副本掛掉從副本就會參與選舉Leader成為新的主副本進行工作。
2 仲裁隊列使用
????????這里使用SpringBoot來創建和使用仲裁隊列:
2.1 配置文件
spring:rabbitmq:addresses: amqp://admin:admin@192.168.159.150:5673/testVirtual
2.2 聲明仲裁隊列
public class RabbitMQConnection {public static final String QUORUM_QUEUE = "quorum.queue";}
@Configurationpublic class RabbitMQConfig {@Bean("quorumQueue")public Queue quorumQueue(){return QueueBuilder.durable(RabbitMQConnection.QUORUM_QUEUE).quorum().build();}}
2.3 生產者
@RestController@RequestMapping("/producer")public class ProducerController {@Resource(name = "rabbitTemplate")private RabbitTemplate rabbitTemplate;@RequestMapping("quorum")public String quorum() {rabbitTemplate.convertAndSend("", RabbitMQConnection.QUORUM_QUEUE, "Hello SpringBoot RabbitMQ");return "發送成功";}}
2.4 演示仲裁隊列的復制
????????仲裁隊列所在的主副本在rabbitmq1節點上,管理界面登錄的是rabbit節點,可以發現,我們向rabbitmq1的仲裁隊列上發送消息,成功發送:
????????上述+2表示還有2個副本。仲裁隊列副本默認有5個,1主4從副本。當集群中節點的個數小于5個,比如4個節點,則1主3從副本;當集群中節點數大于五個,比如6個節點,則默認只有5個副本,1主4從副本,從副本隨機分配在除主節點外的其它5個節點上(有一個節點會沒有從副本)。
????????當rabbitmq1節點宕機時,如果是普通隊列,所有節點上的消息都會消失,而仲裁隊列其它節點消息還會存在:
????????可以發現,在rabbitmq1宕機后,發生選舉rabbitmq2成為新的Leader,而rabbit還是Follower。
下篇文章:
RabbitMQ—HAProxy負載均衡https://blog.csdn.net/sniper_fandc/article/details/149312701?fromshare=blogdetail&sharetype=blogdetail&sharerId=149312701&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link