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