Hazelcast叢集服務(1)——Hazelcast介紹

來源:互聯網
上載者:User

標籤:har   docker   ble   get   targe   pac   指令碼   ado   原理   

Hazelcast是什麼

    “分布式”、“叢集服務”、“網格式記憶體資料”、“分布式緩衝“、“彈性可伸縮服務”——這些牛逼閃閃的名詞拿到哪都是ITer裝逼的不二之選。在Javaer的世界,有這樣一個開源項目,只需要引入一個jar包、只需簡單的配置和編碼即可實現以上高端技能,他就是 Hazelcast

    Hazelcast 是由Hazelcast公司(沒錯,這公司也叫Hazelcast!)開發和維護的開源產品,可以為基於jvm環境啟動並執行各種應用提供分布式叢集和分布式快取服務。Hazelcast可以嵌入到任何使用Java、C++、.NET開發的產品中(C++、.NET只提供用戶端接入)。Hazelcast目前已經更新到3.X版本,Java中絕大部分資料結構都被其以為分布式的方式實現。比如Javaer熟悉的Map介面,當通過Hazelcast建立一個Map執行個體後,在節點A調用 Map::put("A","A_DATA") 方法添加資料,節點B使用 Map::get("A") 可以獲到值為"A_DATA" 的資料。Hazelcast 提供了 Map、Queue、MultiMap、Set、List、Semaphore、Atomic 等介面的分布式實現;提供了基於Topic 實現的訊息佇列或訂閱\發布模式;提供了分布式id產生器(IdGenerator);提供了分布式事件驅動(Distributed Events);提供了分散式運算(Distributed Computing);提供了分散式查詢(Distributed Query)。總的來說在獨立jvm經常使用資料結果或模型 Hazelcast 都提供了分布式叢集的實現。

    Hazelcast 有開源版本和商用版本。開源版本遵循 Apache License 2.0 開源協議免費使用。商用版本需要擷取特定的License,兩者之間最大的區別在於:商用版本提供了資料高密度儲存。我們都知道jvm有自己特定的GC機制,無論資料是在堆還是棧中,只要發現無效引用的資料區塊,就有可能被回收。而Hazelcast的分布式資料都存放在jvm的記憶體中,頻繁的讀寫資料會導致大量的GC開銷。使用商業版的Hazelcast會擁有高密度儲存的特性,大大降低Jvm的記憶體開銷,從而降低GC開銷。

    很多開源產品都使用Hazelcast 來組建微服務叢集,例如咱們的Vert.x,首選使用Hazelcast來組建分布式服務。有興趣可以看我的這篇分享——http://my.oschina.net/chkui/blog/678347 ,文中說明了Vert.x如何使用Hazelcast組建叢集。

    附:

  • Hazelcast源碼:https://github.com/hazelcast/hazelcast
  • 關於Hazelcast的問題可以到https://github.com/hazelcast/hazelcast/issues或http://stackoverflow.com。
Hazelcast的特性自治叢集(無中心化)

    Hazelcast 沒有任何中心節點(文中的節點可以理解為運行在任意伺服器的獨立jvm,下同),或者說Hazelcast 不需要特別指定一個中心節點。在啟動並執行過程中,它自己選定叢集中的某個節點作為中心點來管理所有的節點。

資料按應用分布式儲存

    Hazelcast 的資料是分布式儲存的。他會將資料盡量儲存在需要使用該項資料的節點上,以實現資料去中心化的目的。在傳統的資料存放區模型中(MySql、MongDB、Redis 等等)資料都是獨立於應用單獨存放,當需要提升資料庫的效能時,需要不斷加固單個資料庫應用的效能。即使是現在大量的資料庫支援叢集模式或讀寫分離,但是基本思路都是某幾個庫支援寫入資料,其他的庫不斷的拷貝更新資料副本。這樣做的壞處一是會產生大量髒讀的問題,二是消耗大量的資源來傳遞資料——從資料來源頻繁讀寫資料會耗費額外資源,當資料量增長或建立的主從服務越來越多時,這個消耗呈指數級增長。

    使用 Hazelcast 可以有效解決資料中心化問題。他將資料分散的儲存在每個節點中,節點越多越分散。每個節點都有各自的應用服務,而Hazelcast叢集會根據每個應用的資料使用方式分散儲存這些資料,在應用過程中資料會盡量“靠近”應用存放。這些在叢集中的資料共用整個叢集的儲存空間和計算資源。

抗單點故障

    叢集中的節點是無中心化的,每個節點都有可能隨時退出或隨時進入。因此,在叢集中儲存的資料都會有一個備份(可以配置備份的個數,也可以關閉資料備份)。這樣的方式有點類似於 hadoop,某項資料存放在一個節點時,在其他節點必定有至少一個備份存在。當某個節點退出時,節點上存放的資料會由備份資料替代,而叢集會重新建立新的備份資料。

簡易性

    所有的 Hazelcast 功能只需引用一個jar包,除此之外,他不依賴任何第三方包。因此可以非常便捷高效的將其嵌入到各種應用伺服器中,而不必擔心帶來額外的問題(jar包衝突、類型衝突等等)。他僅僅提供一系列分布式功能,而不需要綁定任何架構來使用,因此適用於任何情境。

    除了以上特性,Hazelcast 還支援伺服器/用戶端模型,支援指令碼管理、能夠和 Docker 快速整合等等。

簡單使用例子

    前面說了那麼多概念,必須要來一點乾貨了。下面是一個使用 Hazelcast 的極簡例子。文中的所有代碼都在github上:https://github.com/chkui/hazelcast-demo。

    首先引入Hazelcast的jar包。

    Maven(pom.xml)

<dependency>    <groupId>com.hazelcast</groupId>    <artifactId>hazelcast</artifactId>    <version>${hazelcast.vertsion}</version></dependency>

    Gradle(build.gradle)

compile com.hazelcast:hazelcast:${hazelcast.vertsion}

    先創一個建 Hazelcast 節點:

//org.palm.hazelcast.getstart.HazelcastGetStartServerMaster public class HazelcastGetStartServerMaster {    public static void main(String[] args) {        // 建立一個 hazelcastInstance執行個體        HazelcastInstance instance = Hazelcast.newHazelcastInstance();        // 建立叢集Map        Map<Integer, String> clusterMap = instance.getMap("MyMap");        clusterMap.put(1, "Hello hazelcast map!");        // 建立叢集Queue        Queue<String> clusterQueue = instance.getQueue("MyQueue");        clusterQueue.offer("Hello hazelcast!");        clusterQueue.offer("Hello hazelcast queue!");    }}

    上面的代碼使用 Hazelcast 執行個體建立了一個節點。然後通過這個執行個體建立了一個分布式的Map和分布式的Queue,並向這些資料結構中添加了資料。運行這個main方法,會在console看到以下內容:

Members [1] {
    Member [192.168.1.103]:5701 this
}

     隨後再建立另外一個節點:

// org.palm.hazelcast.getstart.HazelcastGetStartServerSlavepublic class HazelcastGetStartServerSlave {    public static void main(String[] args) {        //建立一個 hazelcastInstance執行個體        HazelcastInstance instance = Hazelcast.newHazelcastInstance();        Map<Integer, String> clusterMap = instance.getMap("MyMap");        Queue<String> clusterQueue = instance.getQueue("MyQueue");                System.out.println("Map Value:" + clusterMap.get(1));        System.out.println("Queue Size :" + clusterQueue.size());        System.out.println("Queue Value 1:" + clusterQueue.poll());        System.out.println("Queue Value 2:" + clusterQueue.poll());        System.out.println("Queue Size :" + clusterQueue.size());    }}

    該節點的作用是從Map、Queue中讀取資料並輸出。運行會看到以下輸出

Members [2] {
    Member [192.168.1.103]:5701
    Member [192.168.1.103]:5702 this
}

八月 06, 2016 11:33:29 下午 com.hazelcast.core.LifecycleService
資訊: [192.168.1.103]:5702 [dev] [3.6.2] Address[192.168.1.103]:5702 is STARTED
Map Value:Hello hazelcast map!
Queue Size :2
Queue Value 1:Hello hazelcast!
Queue Value 2:Hello hazelcast queue!
Queue Size :0

    至此,2個節點的叢集建立完畢。第一個節點向map執行個體添加了{key:1,value:"Hello hazelcast map!"},向queue執行個體添加[“Hello hazelcast!”,“Hello hazelcast queue!”],第二個節點讀取並列印這些資料。

    除了直接使用Hazelcast服務來組建叢集,Hazelcast還提供了區別於服務端的用戶端應用程式套件。用戶端與服務端最大的不同是:他不會儲存資料也不能修改叢集中的資料。目前用戶端有C++、.Net、Java多種版本。

    使用用戶端首先要引入用戶端jar包。

    Maven(pom.xml)

<dependency>    <groupId>com.hazelcast</groupId>    <artifactId>hazelcast-client</artifactId>    <version>${hazelcast.version}</version></dependency>

    Gradle(build.gradle)

compile com.hazelcast:hazelcast-client:${hazelcast.vertsion}

    建立一個client節點。

public class HazelcastGetStartClient {    public static void main(String[] args) {        ClientConfig clientConfig = new ClientConfig();        HazelcastInstance instance = HazelcastClient.newHazelcastClient(clientConfig);        Map<Integer, String> clusterMap = instance.getMap("MyMap");        Queue<String> clusterQueue = instance.getQueue("MyQueue");                System.out.println("Map Value:" + clusterMap.get(1));        System.out.println("Queue Size :" + clusterQueue.size());        System.out.println("Queue Value 1:" + clusterQueue.poll());        System.out.println("Queue Value 2:" + clusterQueue.poll());        System.out.println("Queue Size :" + clusterQueue.size());    }}

    然後先啟動 HazelcastGetStartServerMaster::main,再啟動 HazelcastGetStartClient::main。可以看到用戶端輸出:

Members [1] {
    Member [192.168.197.54]:5701
}

八月 08, 2016 10:54:22 上午 com.hazelcast.core.LifecycleService
資訊: HazelcastClient[hz.client_0_dev][3.6.2] is CLIENT_CONNECTED
Map Value:Hello hazelcast map!
Queue Size :2
Queue Value 1:Hello hazelcast!
Queue Value 2:Hello hazelcast queue!
Queue Size :0

    至此,用戶端功能也建立完畢 。可以看到用戶端的console輸出內容比服務端少了很多,這是因為用戶端不必承載服務端的資料處理功能,也不必維護各種節點資訊。

例子運行解析

    下面我們根據console的輸出來看看 Hazelcast 啟動時到底幹了什麼事。(下面的輸出因環境或IDE不同,可能會有差異)

class: com.hazelcast.config.XmlConfigLocator
info: Loading ‘hazelcast-default.xml‘ from classpath. 

    這裡輸出的內容表示Hazelcast啟動時載入的設定檔。如果使用者沒有提供有效設定檔,Hazelcast會使用預設設定檔。後續的文章會詳細說明 Hazelcast 的配置。

class: com.hazelcast.instance.DefaultAddressPicker
info: Prefer IPv4 stack is true.
class: com.hazelcast.instance.DefaultAddressPicker
info: Picked Address[192.168.197.54]:5701, using socket ServerSocket[addr=/0:0:0:0:0:0:0:0,localport=5701], bind any local is true

    這一段輸出說明了當前 Hazelcast 的網路環境。首先是檢測IPv4可用且檢查到當前的IPv4地址是192.168.197.54。然後使用IPv6啟用socket。在某些無法使用IPv6的環境上,需要強制指定使用IPv4,增加jvm啟動參數:-Djava.net.preferIPv4Stack=true 即可。

class: com.hazelcast.system
info: Hazelcast 3.6.2 (20160405 - 0f88699) starting at Address[192.168.197.54]:5701
class: com.hazelcast.system
info: [192.168.197.54]:5701 [dev] [3.6.2] Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.

     這一段輸出說明了當前執行個體的初始化連接埠號碼是5701。Hazelcast 預設使用5701連接埠。如果發現該連接埠被佔用,會+1查看5702是否可用,如果還是不能用會繼續向後探查直到5800。Hazelcast 預設使用5700到5800的連接埠,如果都無法使用會拋出啟動異常。

class: com.hazelcast.system
info: [192.168.197.54]:5701 [dev] [3.6.2] Configured Hazelcast Serialization version : 1
class: com.hazelcast.spi.OperationService
info: [192.168.197.54]:5701 [dev] [3.6.2] Backpressure is disabled
class: com.hazelcast.spi.impl.operationexecutor.classic.ClassicOperationExecutor
info: [192.168.197.54]:5701 [dev] [3.6.2] Starting with 2 generic operation threads and 4 partition operation threads.

     這一段說明了資料的序列化方式和啟用的線程。Hazelcast 在節點間傳遞資料有2種序列化方式,在後續的文章中會詳細介紹。Hazelcast 會控制多個線程執行不同的工作,有負責維持節點串連的、有負責資料分區管理的。

class: com.hazelcast.instance.Node
info: [192.168.197.54]:5701 [dev] [3.6.2] Creating MulticastJoiner
class: com.hazelcast.core.LifecycleService
info: [192.168.197.54]:5701 [dev] [3.6.2] Address[192.168.197.54]:5701 is STARTING
class: com.hazelcast.nio.tcp.nonblocking.NonBlockingIOThreadingModel
info: [192.168.197.54]:5701 [dev] [3.6.2] TcpIpConnectionManager configured with Non Blocking IO-threading model: 3 input threads and 3 output threads
class: com.hazelcast.cluster.impl.MulticastJoiner
info: [192.168.197.54]:5701 [dev] [3.6.2] 

     上面這一段輸出中,Creating MulticastJoiner表示使用組播協議來組建叢集。還建立了6個用於維護非擁塞資訊輸出\輸出。

Members [1] {
    Member [192.168.197.54]:5701
    Member [192.168.197.54]:5702 this
}

class: com.hazelcast.core.LifecycleService
info: [192.168.197.54]:5701 [dev] [3.6.2] Address[192.168.197.54]:5701 is STARTED
class: com.hazelcast.partition.InternalPartitionService
info: [192.168.197.54]:5701 [dev] [3.6.2] Initializing cluster partition table arrangement...

    Members[2]表示當前叢集只有2個節點。2個節點都在ip為192.168.197.54的這台裝置上,2個節點分別佔據了5701連接埠和5702連接埠。連接埠後面的this說明這是當前節點,而未標記this的是其他接入叢集的節點。最後InternalPartitionService輸出的資訊表示叢集初始化了“資料分區”,後面會介紹“資料分區”的概念和原理。

    上面就是Hazelcast在預設情況下執行的啟動過程,可以看出在初始化的過程中我們可以有針對性的修改一些Hazelcast的行為:

  1. 使用預設配置文檔 hazelcast-default.xml 來啟動叢集。因此我們可以自訂這個設定檔來影響Hazelcast 的行為。
  2. 啟用IPv4或IPv6來建立叢集,因此可以知道Hazelcast叢集的通訊是基於TCP、UDP,需要開啟socket支援叢集互動。因此我們可以指定使用的通訊方案。
  3. Hazelcast會啟動多個線程來執行不同的工作,有些負責維護資料、有些負責叢集通訊、有些負責一些基礎操作。因此我們可以配置和管理這些線程。
  4. Hazelcast預設使用MulitCast(組播協議)來組建叢集,因此在區域網路環境他可以無需配置自己完成叢集組建。因此我們可以指定使用TCP/IP或其他通訊協議。
  5. Hazelcast會自己探尋可以使用的連接埠,預設情況下會使用5700到5800間沒有被佔用的連接埠。因此我們可以配置這些連接埠如何使用。
  6. Hazelcast初始化一個名為“資料分區”的方案來管理和儲存資料。因此我們可以調整和控制這些資料分區。

    以上所有紅色字型的部分都可以通過設定檔來影響。在後續的文章中會詳細介紹相關的 配置說明(待續)。

-----------------------------------亮瞎人的分割線-----------------------------------

    如果對Hazelcast的基本原理沒什麼興趣,就不用向下看“運行結構“和“資料分區原理”了,直接去 Hazelcast基本配置(http://my.oschina.net/chkui/blog/732408) 瞭解如何使用Hazelcast吧。

Hazelcast運行結構

    Hazelcast的官網上列舉了2種運行模式,一種是p2p(點對點)模式、一種是在點對點模式上擴充的C/S模式。是p2p模式的拓補結構。

    在p2p模式中,所有的節點(Node)都是叢集中的服務節點,提供相同的功能和計算能力。每個節點都分擔叢集的總體效能,每增加一個節點都可以線性增加叢集能力。

    在p2p服務叢集的基礎上,我們可以增加許多用戶端接入到叢集中,這樣就形成了叢集的C/S模式,提供服務叢集視作S端,接入的用戶端視作C端。這些用戶端不會分擔叢集的效能,但是會使用叢集的各種資源。的結構就是用戶端接入叢集的情況。

    可以為用戶端提供特別的緩衝功能,告知叢集讓那些它經常要使用的數存放在“離它最近”的節點。

Hazelcast分區概念與原理

   Hazelcast通過分區來儲存和管理所有進入叢集的資料,採用分區的方案目標是保證資料可以快速被讀寫、通過冗餘保證資料不會因節點退出而丟失、節點可線性擴充儲存能力。下面將從理論上說明Hazelcast是如何進行分區管理的。

分區

    Hazelcast的每個資料分區(shards)被稱為一個分區(Partitions)。分區是一些記憶體段,根據系統記憶體容量的不同,每個這樣的記憶體段都包含了幾百到幾千項資料條目,預設情況下,Hazelcast會把資料劃分為271個分區,並且每個分區都有一個備份副本。當啟動一個叢集成員時,這271個分區將會一起被啟動。

    展示了叢集只有一個節點時的分區情況。

                            

    從一個節點的分區情況可以看出,當只啟動一個節點時,所有的271個分區都存放在一個節點中。然後我們啟動第二個節點。會出現下面這樣的分區方式。

                            

    二個節點的圖中,用黑色文字標記的表示主要磁碟分割,用藍色文字標記的表示複製分區(備份分區)。第一個成員有135個主要磁碟分割(黑色部分),所有的這些分區都會在第二個成員中有一個副本(藍色部分),同樣的,第一個成員也會有第二個成員的資料副本。

    當增加更多的成員時,Hazelcast會將主要資料和備份資料一個接一個的遷移到新成員上,最終達成成員之間資料均衡且相互備份。當Hazelcast發生擴充的時候,只有最小數量的分區被移動。呈現了4個成員節點的分區分布情況。

                           

    上面的幾個圖說明了的Hazelcast是如何執行分區的。通常情況下,分區的分布情況是無序的,他們會隨機分布在叢集中的各個節點中。最重要的是,Hazelcast會平均分配成員之前的分區,並均勻在的成員之間建立備份。

    在Hazelcast 3.6版本中,新增了一種叢集成員:“精簡成員”(lite members),他的特點是不擁有任何分區。“精簡成員”的目標是用於“高密度運算”任務(computationally-heavy task executions。估計是指CPU密集型運算)或者註冊監聽(listener) 。雖然“精簡成員”沒有自己的分區,但是他們同樣可以訪問叢集中其他成員的分區。

    總的來說,當叢集中的節點發送變動時(進入或退出),都會導致分區在節點中移動並重新平衡,以確保資料均勻儲存。但若是“精簡節點”的進入或退出,並不會出現重新劃分分區情況,因為精簡節點並不會儲存任何分區。

資料分區管理

    建立了分區以後,Hazelcast會將所有的資料存放到每個分區中。它通過雜湊運算將資料分布到每個分區中。擷取儲存資料Key值(例如map)或value值(例如topic、list),然後進行以下處理:

  1. 將設定的key或value轉換成byte[];
  2. 對轉換後的byte[]進行雜湊計算;
  3. 將雜湊計算的結果和分區的數量(271)進行模運算(同餘運算、mod運算、%運算)。

    因為byte[]是和271進行同模運算,因此計算結果一定會在0~270之間,根據這個值可以指定到用於存放資料的分區。

分區表

    當建立分區以後,叢集中的所有成員必須知道每個分區被儲存到了什麼節點。因此叢集還需要維護一個分區表來追蹤這些資訊。

    當啟動第一個節點時,一個分區表將隨之建立。表中包含分區的ID和標記了他所屬的叢集節點。分區表的目標就是讓叢集中所有節點(包括“精簡節點”)都能擷取到資料存放區資訊,確保每個節點都知道資料在哪。叢集中最老的節點(通常情況下是第一個啟動的成員)定期發送分區表給所有的節點。以這種方式,當分區的所有權發生變動時,叢集中的所有節點都會被通知到。分區的所有權發生變動有很多種情況,比如,新加入一個節點、或節點離開叢集等。如果叢集中最早啟動的節點被關閉,那麼隨後啟動的節點將會繼承發送分區表的任務,繼續將分區表發送給所有成員。

原文地址:https://my.oschina.net/chkui/blog/729698

Hazelcast叢集服務(1)——Hazelcast介紹

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.