1. 程式人生 > >ES學習筆記之--ES的集群是如何組建起來的

ES學習筆記之--ES的集群是如何組建起來的

work sock 除了 wait 復雜 節點 產生 bully算法 tar

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的集群是如何組建起來的