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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM