使用Curator和ZooKeeper发现Hazelcast成员
在一個項目中,我正在私有云中設置Hazelcast集群。 在群集內(nèi),所有節(jié)點都必須互相看見,因此在引導過程中,Hazelcast將嘗試查找其他群集成員。 沒有服務器,并且所有節(jié)點都相等。 在Hazelcast中實現(xiàn)了多種發(fā)現(xiàn)成員的技術。 不幸的是,它不是AWS,因此我們無法使用EC2自動發(fā)現(xiàn),并且組播被阻止,因此內(nèi)置的組播支持無用。 最后一種選擇是TCP / IP群集 ,其中所有節(jié)點的地址都需要在XML配置中進行硬編碼:
這不能很好地擴展,我們的云中的節(jié)點也是動態(tài)分配的,因此不可能在運行前確定地址。 在這里,我在下面展示基于Curator Service Discovery和ZooKeeper的概念證明。 首先,讓我們跳過普通的舊Java代碼中的hazelcast.xml配置和引導集群:
@Configuration public class HazelcastConfiguration {@Bean(destroyMethod = "shutdown")HazelcastInstance hazelcast(Config config) {return Hazelcast.newHazelcastInstance(config);}@BeanConfig config(ApplicationContext applicationContext, NetworkConfig networkConfig) {final Config config = new Config();config.setNetworkConfig(networkConfig);config.getGroupConfig().setName(applicationContext.getId());return config;}@BeanNetworkConfig networkConfig(@Value("${hazelcast.port:5701}") int port, JoinConfig joinConfig) {final NetworkConfig networkConfig = new NetworkConfig();networkConfig.setJoin(joinConfig);networkConfig.setPort(port);return networkConfig;}@BeanJoinConfig joinConfig(TcpIpConfig tcpIpConfig) {final JoinConfig joinConfig = disabledMulticast();joinConfig.setTcpIpConfig(tcpIpConfig);return joinConfig;}private JoinConfig disabledMulticast() {JoinConfig join = new JoinConfig();final MulticastConfig multicastConfig = new MulticastConfig();multicastConfig.setEnabled(false);join.setMulticastConfig(multicastConfig);return join;}@BeanTcpIpConfig tcpIpConfig(ApplicationContext applicationContext, ServiceDiscovery<Void> serviceDiscovery) throws Exception {final TcpIpConfig tcpIpConfig = new TcpIpConfig();final List<String> instances = queryOtherInstancesInZk(applicationContext.getId(), serviceDiscovery);tcpIpConfig.setMembers(instances);tcpIpConfig.setEnabled(true);return tcpIpConfig;}private List<String> queryOtherInstancesInZk(String name, ServiceDiscovery<Void> serviceDiscovery) throws Exception {return serviceDiscovery.queryForInstances(name).stream().map(ServiceInstance::buildUriSpec).collect(toList());}}我使用applicationContext.getId()避免對應用程序名稱進行硬編碼。 在Spring Boot中,可以用--spring.application.name=...替換它config.getGroupConfig().setName(...)為集群config.getGroupConfig().setName(...)分配名稱也是一個好主意–這將允許我們運行多個集群在同一網(wǎng)絡中,即使啟用了多播也是如此。 最后一個方法queryOtherInstancesInZk()最有趣。 創(chuàng)建TcpIpConfig我們手動提供其他群集成員所在的TCP / IP地址列表。 我們不是硬編碼此列表(如上面的XML示例),而是從Curator查詢ServiceDiscovery 。 我們請求應用程序的所有實例,并將其傳遞給TcpIpConfig 。 在進入Curator配置之前,只需幾句話就可以解釋Hazelcast如何使用TCP / IP配置。 顯然,并非所有節(jié)點都同時啟動。 當?shù)谝粋€節(jié)點啟動時,Curator幾乎不會返回一個實例(我們自己),因此群集將只有一個成員。 當?shù)诙€節(jié)點啟動時,它將看到已經(jīng)啟動的節(jié)點并嘗試與之形成集群。 顯然,第一個節(jié)點將發(fā)現(xiàn)剛剛連接到它的第二個節(jié)點。 歸納繼續(xù)進行-當更多的節(jié)點啟動時,它們從Curator服務發(fā)現(xiàn)中獲取現(xiàn)有節(jié)點并加入它們。 Hazelcast會通過從群集中刪除成員并重新平衡數(shù)據(jù)來避免成員的虛假崩潰。 另一方面,館長會將其從ZooKeeper中刪除。
好吧,現(xiàn)在ServiceDiscovery<Void>來自哪里? 這是完整的配置:
@Configuration public class CuratorConfiguration {@BeanWithLifecycleServiceDiscovery<Void> serviceDiscovery(CuratorFramework curatorFramework, ServiceInstance<Void> serviceInstance) throws Exception {return ServiceDiscoveryBuilder.builder(Void.class).basePath("hazelcast").client(curatorFramework).thisInstance(serviceInstance).build();}@BeanWithLifecycleCuratorFramework curatorFramework(@Value("${zooKeeper.url:localhost:2181}") String zooKeeperUrl) {ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3);return CuratorFrameworkFactory.newClient(zooKeeperUrl, retryPolicy);}@BeanServiceInstance<Void> serviceInstance(@Value("${hazelcast.port:5701}") int port, ApplicationContext applicationContext) throws Exception {final String hostName = InetAddress.getLocalHost().getHostName();return ServiceInstance.<Void>builder().name(applicationContext.getId()).uriSpec(new UriSpec("{address}:{port}")).address(hostName).port(port).build();}}默認情況下,Hazelcast監(jiān)聽5701,但是如果指定的端口被占用,它將嘗試后續(xù)端口。 啟動時,我們在Curator中注冊自己,提供主機名和Hazelcast端口。 當我們的應用程序的其他實例啟動時,他們將看到先前注冊的實例。 當應用程序出現(xiàn)故障時,Curator將使用ZooKeeper中的臨時節(jié)點機制注銷我們的注冊。 順便說一句@BeanWithLifecycle不是來自Spring或Spring Boot,我自己創(chuàng)建了它以避免重復:
@Target({METHOD, ANNOTATION_TYPE}) @Retention(RUNTIME) @Bean(initMethod = "start", destroyMethod = "close") @interface BeanWithLifecycle { }運行ZooKeeper(默認情況下在localhost:2181 ),我們可以啟動任意數(shù)量的節(jié)點,它們將很快相互找到對方。 唯一的共享信息是ZooKeeper URL。
翻譯自: https://www.javacodegeeks.com/2014/12/hazelcast-member-discovery-using-curator-and-zookeeper.html
總結
以上是生活随笔為你收集整理的使用Curator和ZooKeeper发现Hazelcast成员的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前调中调后调是什么意思 前调中调后调的意
- 下一篇: 功能介面