Hazelcast

前言

在看部門基礎設施架構時, OSG模塊服務Eureka用於服務發現, 從Apollo啓動讀取配置, 從MySQL定時加載網關配置, 並集成了緩存Hazelcast, Hazelcast是什麼? 怎麼用? 爲什麼用它? 帶着問題, 找到挺不錯的一篇文章, 以下爲轉載正文!

正文

聲明

本系列文章爲學習Hazelcast的筆記,內容大部分都爲官方文檔翻譯,如果對Hazelcast感興趣,可移步Hazelcast查看官方原版文檔。

學習目的

公司項目服務化改造後,缺少一種在微服務多個實例間廣播、多播的機制,爲了解決這個問題決定引入Vert.x Event Bus(cluster)來實現,在學習使用Event Bus的過程中瞭解到Event Bus的默認ClusterManager基於Hazelcast項目,簡單看了一下感覺還不錯,決定整體學習一遍擴展視野。

1.1 Hazelcast是什麼

Hazelcast是基於內存的數據網格開源項目,同時也是該公司的名稱。Hazelcast提供彈性可擴展的分佈式內存計算,Hazelcast被公認是提高應用程序性能和擴展性最好的方案。Hazelcast通過開放源碼的方式提供以上服務。更重要的是,Hazelcast通過提供對開發者友好的Map、Queue、ExecutorService、Lock和JCache接口使分佈式計算變得更加簡單。例如,Map接口提供了內存中的鍵值存儲,這在開發人員友好性和開發人員生產力方面提供了NoSQL的許多優點。

除了在內存中存儲數據外,Hazelcast還提供了一組方便的api來訪問集羣中的cpu,以獲得最大的處理速度。輕量化和簡單易用是Hazelcast的設計目標。Hazelcast以Jar包的方式發佈,因此除Java語言外Hazelcast沒有任何依賴。Hazelcast可以輕鬆地內嵌已有的項目或應用中,並提供分佈式數據結構和分佈式計算工具。

Hazelcast 具有高可擴展性和高可用性(100%可用,從不失敗)。分佈式應用程序可以使用Hazelcast進行分佈式緩存、同步、集羣、處理、發佈/訂閱消息等。Hazelcast基於Java實現,並提供C/C++,.NET,REST,Python、Go和Node.js客戶端。Hazelcast遵守內存緩存協議,可以內嵌到Hibernate框架,並且可以和任何現有的數據庫系統一起使用。
Hazelcast的整體架構如下:

 

 

Hazelcast整體架構

Hazelcast的架構不對開發者暴露

如果你正在尋找基於內存的、高速的、可彈性擴展的、對開發者友好的NoSQL,Hazelcast是一個很棒的選擇。

1.2 Hazelcast的特點

  • 簡單
    Hazelcast基於Java語言編寫,沒有任何其他依賴。Hazelcast基於熟悉的Java util包對外暴露相同的API和接口。只要將Hazelcast的jar包添加到classpath中,便可以快速使用JVM集羣,並開始構建可擴展的應用程序。
  • 節點對等
    和大多數NoSQL解決方案不同,Hazelcast集羣中的節點是對等的,集羣中沒有主備角色之分,因此Hazelcast無單點故障問題。集羣內所有節點存儲和計算同量數據。可以把Hazelcast內嵌到已有的應用程序中或使用客戶端服務器模式(應用程序作爲Hazelcast集羣中一個節點的客戶端)。
  • 可擴展
    Hazelcast被設計爲可以擴展到成百上千個節點,簡單的增加節點,新加入的節點可以自動發現集羣,集羣的內存存儲能力和計算能力可以維持線性增加。集羣內每兩個節點之間都有一條TCP連接,所有的交互都通過該TCP連接。
  • 快、快、快
    所有數據都存儲在內存中,Hazelcast支持快速寫和更新操作。

1.3 Hazelcast中的分片

Hazelcast中的分片也稱爲分區,Hazelcast默認271個分區。Hazlecast通常也會對分區備份,並將副本分佈到集羣的不同節點上,通過數據冗餘提高可靠性,這種數據的存儲方式和kafka、Redis Cluster類似。給定一個key,在Hazelcast集羣中查找key對應數據的過程如下圖所示:

 

 

Value查找過程

1.4 Hazelcast的拓撲結構

Hazelcast集羣有兩種部署模式:內嵌模式,客戶端/服務器模式。

  • 內嵌模式
    如果您有一個應用程序,其主要關注點是異步或高性能計算和執行大量任務,在這種應用場景使用內嵌部署模式比較合適,在內嵌部署模式下,Hazelcast集羣中的一個節點包括:應用程序,Hazelcast分區數據,Hazelcast服務三部分。內嵌部署模式的優勢是讀取數據延遲低。內嵌部署模式如下圖所示:

     

     


    內嵌部署模式
  • 客戶端/服務器部署模式
    Hazelcast數據和服務集中在一個或多個節點上,應用通過客戶端讀寫數據。可以部署一個提供服務的獨立Hazelcast集羣,服務集羣可以獨立創建,獨立擴展。客戶端通過和集羣中的節點交互來獲取Hazelcast數據和服務。Hazelcast提供Java,.NET、C++、Memcache和REST客戶端。客戶端/服務器部署模式如下圖所示:

     

     


    客戶端/服務器模式

    客戶端/服務器部署模式的優點包括:可預測性高、可靠的Hazelcast服務、問題定位定界簡單,更重要的是具備高可擴展性。在客戶端/服務器模式下,當集羣需要擴展時,只需添加或減少Hazelcast服務器節點。客戶端和服務器的伸縮可以獨立進行。如果既想擁有低延遲數據訪問(內嵌部署模式),又想充分利用客戶端/服務器模式的靈活擴展性,需要考慮將客戶端部署在更靠近緩存的地方,並將客戶端的熱點數據緩存到客戶端本地緩存中。

1.5 爲什麼選擇Hazelcast

      1.5.1傳統的數據一致性方案

數據是軟件系統的核心,在傳統的架構中,通常使用關係型數據庫存儲並提供數據訪問服務。應用程序直接和數據交互,數據庫在另外的機器上通常存在一個備份。爲了提高性能,需要對數據庫調優或購買更高性能的服務器,這需要大量的投資和努力。

架構通常的做法是在更加靠近數據庫的地方保存一份數據的備份,通常採用外部K-V存儲技術或二級緩存來降低數據庫訪問壓力。然而,當數據的性能達到極限或應用程序更多的請求是寫請求時,這種方案對降低數據庫的訪問壓力無能爲力,因爲不管是K-V存儲還是二級多級緩存方案都只能降低數據庫讀壓力。即便應用程序大多數是讀請求,上述方案也有很多問題:當數據變化後,對緩存的影響是什麼,緩存如何處理數據變化(目前公司的項目也在考慮方案解決整個問題),在這種條件下緩存存活時間(TTL)和直寫緩存(Write-through )的概念誕生了。

考慮TTL的情況,如果訪問的頻率比TTL更低(TTL=30s,每次請求間隔35S),則每次訪問的數據都不在緩存中,都需要從數據庫讀取數據,緩存每次都被穿透。另一方面,考慮直寫緩存場景,如果集羣中緩存的數據有多份,同樣會面臨數據一致性問題。數據一致問題可以通過節點間的互相通信解決,當一個數據不可用時,該消息可以在集羣內的節點之間傳播。

基於TTL和直寫緩存可以設計一個理想的緩存模型,在該領域已經有緩存服務器和內存數據庫等。然而,這些解決方案都是具有由其他技術提供的分佈式機制的獨立的單機實例(本質不是分佈式集羣,只是通過其他技術附加了集羣特性)。回到問題的起點,如果產品是單節點,或者發行版沒有提供一致性,總有一天會遇到容量問題。

      1.5.2Hazelcast的一致性解決方案

圍繞分佈式思想設計的Hazelcast提供一種全新訪問處理數據的方法。爲了提高靈活性和性能,Hazelcast在集羣周圍共享數據。Hazelcast基於內存的數據網格爲分佈式數據提供集羣和高可擴展性。

集羣無主節點是Hazelcast的一個主要特性,從功能上來講,集羣內每個節點都被配置爲對等。第一個加入集羣的節點負責管理集羣內其他所有節點,例如數據自動平衡、分區表更新廣播。如果第一個節點下線,第二個加入集羣的節點負責管理集羣其他節點。第一個節點故障切換方式如下圖所示:

 

 


集羣自治

數據完全基於內存存儲、訪問速度快是Hazelcast的另外一個特點。由於Hazelcast將數據的副本分佈到集羣中的其他節點上,所以在故障條件下(節點宕機)也不會有數據丟失。Hazelcast提供很多分佈式數據結構和分佈式計算工具,增強分佈式集羣內存的訪問並通過CPU最大化分佈式計算的速度。

      1.5.3Hazelcast的優勢

  • 開源。
  • 基於Jar發佈,無需安裝軟件。
  • 不對用戶暴露Hazelcast的架構。
  • 提供開箱即用的分佈式數據結構。
  • 無單點故障。
  • 支持動態彈性擴展。
  • 數據備份,節點故障數據無丟失。
  • 集羣內節點彼此感知。
  • 使用SPI可以構建自己的分佈式數據結構。
  • 擁有一個活躍的開源社區。

1.6 數據分區

Hazelcast中的分片也叫做分區,分區是一個內存段,分區中存儲數百或數千數據實體,分區的存儲容量取決於節點自身的存儲能力。

Hazelcast默認提供271個分區,類似Redis擁有16384個槽位。當啓動只有一個節點的Hazelcast集羣時,節點擁有全部271個分區。Hazelcast集羣只有一個節點的條件下的分區分佈如下圖所示:

 

 


單節點分區分佈

Hazelcast集羣新增加一個節點,或啓動一個包含兩個節點的Hazelcast集羣,分區的分佈情況如下圖所示:

 

 


兩節點分區分佈

黑色字體表示的分區爲主分區,藍色字體表示主分區的副本。

不斷加入新的節點,Hazelcast會一個一個的把主分區和主分區副本遷移到新加入的節點上,保證主備分區的一致性和冗餘性。當集羣有四個節點時, 集羣分區的一種可能方案如下:

 

 


四節點集羣分區分佈

Hazelcast將分區均勻的分佈到集羣的各個節點,Hazelcast自動創建分區的副本,並將副本分佈到各個節點來提供可靠性。以上圖片展示的Hazelcast分區僅僅是爲了方便和清晰的描述Hazelcast分區機制。通常來說分區的分佈不是有序的,Hazelcast使用一種隨機的方式分佈各個分區。這裏重點說明Hazelcast均勻的分佈分區和分區副本。Hazelcast 3.6版本引入輕量化節點(存儲輕量化節點),輕量化節點是一種新的節點類型,輕量化節點不持有任何分區數據。輕量化節點主要用於計算型任務和監聽器註冊,儘管輕量化節點不保存分區數據,但是輕量化節點可以訪問集羣中其他節點所持有的分區數據。

      1.6.1 數據如何被分區

Hazelcast使用一種哈希算法將數據分佈到特定分區。給定一個key,分區計算過程如下:

  • 將key序列化爲byte數組。
  • 計算byte數組的哈希值。
  • 哈希值與分區數求餘,得到分區ID(注意不是節點數)。

同一個key的分區ID必須保持一致。

      1.6.2 分區表

啓動集羣內的一個節點時,該節點會自動創建一個分區表。分區表存儲分區ID和集羣內其他的節點信息。分區表的主要目的是讓集羣內的所有節點(包括輕量節點)瞭解分區信息,確保每個節點都知道數據存儲在哪個分區,哪個節點上。最早加入集羣的節點週期性的向集羣內其他節點發送分區表。通過這種方式,當分區關係發生變化時,集羣內的所有節點都可以感知該變化。當一個節點加入或離開集羣時,分區關係就會發生變化。
當集羣內最早加入的節點故障時,剩餘節點中最早加入集羣的節點負責週期性的向其他節點發送分區表
發送分區表的週期默認是15S,如果想修改週期,可以通過設置環境變量hazelcast.partition.table.send.interval來進行修改。

      1.6.3 重分區

重分區是Hazelcast重新分配分區關係的過程,以下兩種情況會觸發Hazelcast執行重分區動作。

  • 一個節點加入集羣.
  • 一個節點離開集羣.
    在這種情況下,最早加入集羣的節點會更新分區關係表,並將更新後的分區表發送給集羣內其他節點。輕量節點加入集羣不會觸發重分區動作,因爲輕量節點主要執行計算任務,本身不保存任何分區數據。

1.7 使用場景

  • 共享服務器配置和服務器信息,
  • 集羣數據變更通知,
  • 作爲簡單的內存緩存,
  • 作爲一個在特定節點執行特定任務的調度器,
  • OSGI框架下不同節點共享信息.
  • 集羣內共享數千個key,
  • 作爲Cassadra的前端.
  • 集羣內分發用戶狀態,不同對象間傳遞信息,共享系統數據結構,
  • 多租戶緩存,每個租戶都有自己獨立的緩存,
  • 共享數據集合,
  • 從亞馬遜EC2分發和收集服務負載信息,
  • 作爲性能檢測的實時流,
  • Session存儲器 

如何使用

以把它看做是內存數據庫,不過它與 Redis 等內存數據庫又有些不同。項目地址:http://hazelcast.org/

import com.hazelcast.config.Config;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;

import java.util.concurrent.ConcurrentMap;

public class DistributedMap {
    public static void main(String[] args) {
        Config config = new Config();
        HazelcastInstance h = Hazelcast.newHazelcastInstance(config);
        ConcurrentMap<String, String> map = h.getMap("my-distributed-map");
        map.put("key", "value");
        map.get("key");

        //Concurrent Map methods
        map.putIfAbsent("somekey", "somevalue");
        map.replace("key", "value", "newvalue");
    }
}

 

感謝

https://www.jianshu.com/p/99d98acb3195

https://www.cnblogs.com/seasonsluo/p/hazelcast-intro.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章