您好,登錄后才能下訂單哦!
ES作為一個分布式系統,需要多個節點協同,來管理集群,處理用戶請求。那么很自然有個問題,ES的集群是如何組建起來的?
所謂集群,就是多臺計算機一起協同工作。 既然是協同工作,那么就必須步調一致,步調一致才能得解放。需要有領導這個角色來協調資源, 這個角色在ES中命名為Master。 Master這個角色,不是ES的獨有的,基本上所有的分布式系統都有這個角色的存在,比如Zookeeper, Mongo等。
Master的產生機制也很有意思: 選舉。既然是選舉,那么必然會出現一個問題:怎么選舉? 這就是所謂的“選舉算法”。 “選舉算法”中最有名的就是Paxos算法,也是最難理解的算法。好在ES用的不是這么復雜的算法,ES用的是Bully算法。ES需要解決的問題是節點的選舉, 而Paxos算法除了選舉,還解決了一致性的問題,殺雞焉用牛刀。
基于Bully算法,ES實現ZenDiscovery。 順便說一句,ES的節點發現由統一的模塊處理,就是DiscoveryModule
。有興趣了解ES源碼,可以作為一個入口。
ZenDiscovery的流程相當簡潔, 就兩步:
1. 每個節點和其他的節點通信,獲取其他節點的nodeId, 從中選取nodeId最小的那個作為自己的投票。
2. 每個節點接收其他節點的投票,如果有一個節點得到足夠多的選票,則接受自己成為Leader的事實,開始分發節點狀態到整個集群的其他節點。
下面通過具體的代碼來理解這一個流程。既然是理解ES集群的組建過程,那么就從ES的進程啟動開始,以elasticsearch-2.4.5為例。
我們知道,ES的啟動命令是bin/elasticsearch
,這個命令會調用org.elasticsearch.bootstrap.Elasticsearch.java
的main方法。
啟動elasticsearch后, 通過使用如下的命令可以確定:
$ jps
13201 Elasticsearch
$$ cat /proc/13201/cmdline | strings
/opt/jdk1.8.0_51/bin/java
-Xms256m
-Xmx1g
-Djava.awt.headless=true
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+HeapDumpOnOutOfMemoryError
-XX:+DisableExplicitGC
-Dfile.encoding=UTF-8
-Djna.nosys=true
-Des.path.home=/opt/elasticsearch-2.4.5-SNAPSHOT
/opt/elasticsearch-2.4.5-SNAPSHOT/lib/elasticsearch-2.4.5-SNAPSHOT.jar:/opt/elasticsearch-2.4.5-SNAPSHOT/lib/*
org.elasticsearch.bootstrap.Elasticsearch
start
接下來,會實例化一個Node對象,代表這個ES節點。然后start這個node.
Bootstrap.init(args); // Elasticsearch.java line 45
INSTANCE.start(); // Bootstrap.java line 288
node.start(); // Bootstrap.java line 222
discoService.joinClusterAndWaitForInitialState(); // Node.java 286
如果在es的配置文件進行如下的配置,那么可以debug這個過程.
// 當前啟動節點的IP地址
network.host: 192.168.43.239
// 集群的IP列表
discovery.zen.ping.unicast.hosts: ["192.168.43.239", "192.168.43.239:9800","192.168.43.239:9900"]
我們忽略代碼間的跳轉,直接到核心業務邏輯代碼ZenDiscovery.innerJoinCluster()
,具體的業務邏輯如下:
s1: 確定master ZenDiscovery.findMaster()
s2: 判斷master是否是當前節點,如果是則等待其他的節點加入;否則連接master, 然后發起狀態更新的請求到master.
關于集群節點間的通信,還有很多其他的細節。我們先拋開ES相關的知識,回到操作系統層面。 兩臺計算機通信,依賴的是計算機網絡方面的知識。 簡單來說就是TCP/IP協議。從Java語言的實現來說就是Socket編程。 Socket編程遵循的模式是C/S模式,即一臺計算機作為服務端,監聽一個端口;另一臺計算機作為客戶端,連接該端口。
通常開發中不會自己使用原生的Socket編程,而是使用Netty框架。 Netty框架封裝了繁雜的底層操作,又在性能上做了很多工作。其基于異步/時間驅動的特性使其成為網絡編程的首選框架。
基于Netty框架, ES構建了功能上類似于dubbo的RPC服務,這個就是Transport。代碼的入口是`TransportModule`。關于Transport的細節,需單獨寫博客說明,非本文關注的重點,略過。
基于Transport模塊,ES構建了DiscoveryModule,就是ES的節點發現。即本文試圖理解的核心點。
參考:
https://www.jianshu.com/p/9454ac19921d
https://www.elastic.co/blog/found-leader-election-in-general
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。