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
ES學習筆記之--ES的集群是如何組建起來的