閱讀708 返回首頁    go 阿裏雲 go 技術社區[雲棲]


hazelcast的坑爹事

簡介

開源中國的簡介:

Hazelcast是一個高度可擴展的數據分發和集群平台。特性包括:

  • 提供java.util.{Queue, Set, List, Map}分布式實現。
  • 提供java.util.concurrency.locks.Lock分布式實現。
  • 提供java.util.concurrent.ExecutorService分布式實現。
  • 提供用於一對多關係的分布式MultiMap。
  • 提供用於發布/訂閱的分布式Topic(主題)。
  • 通過JCA與J2EE容器集成和事務支持。
  • 提供用於安全集群的Socket層加密。
  • 支持同步和異步持久化。
  • 為Hibernate提供二級緩存Provider 。
  • 通過JMX監控和管理集群。
  • 支持動態HTTP Session集群。
  • 利用備份實現動態分割。
  • 支持動態故障恢複。

簡介是美好的,現實是坑爹的。

優點

先說下優點吧:

有個Manager Center的管理界麵,很漂亮,可以看到很多有用的數據。包括每個Map的請求次數等。這些在Memcached,Redis上隻能看個大概。

簡單的配置很方便,可以像JDK裏的Map,List一樣使用。


坑爹事情

配置各種找不到

有很多xml的配置方式沒有寫在文檔上,要到代碼裏各種找。友情提示,可以到代碼裏的test目錄下找到比較完整的配置:

https://github.com/hazelcast/hazelcast/blob/maintenance-3.x/hazelcast-spring/src/test/resources/com/hazelcast/spring/node-client-applicationContext-hazelcast.xml

有很多參數的配置沒有寫在文檔上,要到代碼裏各種找。友情提示,在com.hazelcast.instance.GroupProperties 這個類裏找到一些在文檔上沒有的配置參數。

默認的超時配置太長

很多超時配置都是上百秒的,試想現在的網站或者應用,有哪個可以忍受上百秒的超時。從另一個側麵也可以看出hazelcast的自己的信心不足,要靠超長時間的超時來保證運行的正確性。

即使配置了較短的超時時間,還是有可能會有各種出人意料的超時,認真研究過代碼後,發現是有很多超時時間是在代碼裏寫死的。。

版本之間不兼容

版本之間不兼容,不能滾動升級。這就意味著,當升級時,整個集群都要一塊重啟,這對很多網站來說,是不能忍受的。據說從3.1版本後會保證小版本的兼容性。

https://github.com/hazelcast/hazelcast/issues/14

hazelcast裏代碼一大問題就是把序列化方案和網絡通訊混在一起了,導致各種升級兼容問題。每個消息包在解析時,都有可能因為類有改動而不兼容。

而且序列化方案還是那種要實現一個特定接口的。在Protobuf,Thrift,及各種基於反射的序列化方案這麼流行的今天,很難想像會有這樣難用的序列化方式。

一個結點出問題,影響整個集群

當集群裏某個節點出故障時,比如OOM,CPU100%,沒反應之後,集群裏發到那個結點的操作就各種超時,各種不正常。這個可以算是hazelcast的一個致命的缺點。

我們線上的集群有30多個結點,隨便一個有問題,都會導致整個集群有問題。另外,當集群裏有一個應用下線/上線,都會引起數據的遷移,盡管遷移是自動的,但是也是一個不可控的風險。

我們開始時用的是hazelcast2.5.1,後來升級到3.1.3版本。升級後發現兩個結點間經常會有網絡流量超高的情況,最後發現是merge-policy的配置在3.0隻能配置類的全名,而在2.5是可以配置一個簡稱的。然後在集群裏有數據要遷移,進行Merge時,就會因為ClassNotFoundException而失敗。而Hazelcast坑爹的地方在於它不斷地重試,而且是無停頓地重試,從而導致兩個結點之間網絡流量超高,甚至超過了100Mbps。

hazelcast client很難用

首先,還是文檔太少,很多配置根本沒有提到,得自己到代碼裏去找。

另外,如果hazelcast server集群全部掛掉後,client居然不會自己重連(重試3次就放棄了)。現在的各種組件重啟是很正常的事情,而hazelcast client居然不會自動重連,真心令人無語。更加扯蛋的是,比如map.get,如果沒有連接上,會拋出一個RuntimeException,那麼整個線程都退出了。

3.0版本和3.0.2版本之間的配置格式居然有很大的變化,很多時候,找個配置,得自己去看xml的xsd文件。。

結點之間Merge時,需要反序列化

這個我認為是代碼太多導致的混亂。結點之間數據合並時,本來隻要比較下數據的版本,時間等就可以了,但是在合並時卻把對象反序化出來。如果在Server端沒有對應的jar包,則會拋出ClassNotFoundException。

參考這裏:

https://github.com/hazelcast/hazelcast/issues/1514


一些原理性的東東

Partition

從原理上來說,hazelcast是默認有271個partition,這271個parition平均分布在集群裏的結點中,因此集群裏的數據分散在每個結點中。然後在進行操作時,先計算得到key所在的partiion,再進行操作。

詳細請參考PartitionServiceImpl這個類的代碼:

public final int getPartitionId(Data key) {
    int hash = key.getPartitionHash();
    return (hash != Integer.MIN_VALUE) ? Math.abs(hash) % partitionCount : 0;
}

NearCache的實現原理

hazelcast裏有一個所謂的nearcache的東東,其實這個很簡單,就是一個本地的二級緩存。在get的時候先到本地的nearcache裏查找,如果沒有計算hash,再到對應的結點中取數據,再放到nearcache裏。

參考:

https://www.oschina.net/p/hazelcast

https://www.hazelcast.org/docs/3.1/manual/html-single/


最後更新:2017-04-03 12:54:38

  上一篇:go 數據庫事務
  下一篇:go 藍橋杯-曆屆試題 翻硬幣