How to Share Data Across Multiple JVMs in a Distributed Environment Using Zookeeper

This guide demonstrates how to use Zookeeper with Spring Boot to enable data sharing among multiple JVM processes in a distributed system, covering Maven dependencies, configuration files, and Java code for connection, node watching, and data change handling.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
How to Share Data Across Multiple JVMs in a Distributed Environment Using Zookeeper

In a distributed environment, Zookeeper can be used to share data among multiple JVM processes. The example uses Zookeeper 3.6.2 together with Spring Boot 2.2.10.

Required Maven dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.6.2</version>
    </dependency>
</dependencies>

Application configuration (application.yml)

server:
  port: 9881
---
zk:
  connectString: localhost:2181,localhost:2182,localhost:2183
  timeout: 3000
  config:
    path: /config/ids

Java configuration

@Configuration
public class ZKConfig {
    private static Logger logger = LoggerFactory.getLogger(ZKConfig.class);

    @Value("${zk.connectString}")
    private String connectString;

    @Value("${zk.timeout}")
    private Integer timeout;

    @Bean
    public ZooKeeper zookeeper() {
        ZooKeeper zookeeper = null;
        try {
            CountDownLatch cdl = new CountDownLatch(1);
            logger.info("zk准备连接: {}", connectString);
            zookeeper = new ZooKeeper(connectString, timeout, event -> {
                if (event.getState() == Event.KeeperState.SyncConnected) {
                    logger.info("zk服务器连接成功");
                    cdl.countDown();
                }
            });
            cdl.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return zookeeper;
    }

    @Configuration
    public static class WatchNodeData implements InitializingBean {
        public static Set<String> cache = new HashSet<>();

        @Resource
        private ZooKeeper zk;

        @Value("${zk.config.path}")
        private String path;

        @Override
        public void afterPropertiesSet() throws Exception {
            if (zk.exists(path, null) == null) {
                zk.create(path, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
            // PERSISTENT_RECURSIVE watches child nodes recursively
            zk.addWatch(path, new NodeIdWatch(zk), AddWatchMode.PERSISTENT_RECURSIVE);
        }

        private static class NodeIdWatch implements Watcher {
            private ZooKeeper zk;
            public NodeIdWatch(ZooKeeper zk) { this.zk = zk; }
            @Override
            public void process(WatchedEvent event) {
                switch (event.getType()) {
                    case NodeDataChanged:
                        try {
                            String val = new String(this.zk.getData(event.getPath(), false, null));
                            logger.info("节点{} 数据发生变化, 当前值:{}", event.getPath(), val);
                            WatchNodeData.cache.add(val);
                        } catch (Exception e) { e.printStackTrace(); }
                        break;
                    case NodeCreated:
                        logger.info("创建了节点:{}", event.getPath());
                        break;
                    case NodeChildrenChanged:
                        logger.info("子节点发生了变化:{}", event.getPath());
                        break;
                    default:
                        break;
                }
            }
        }
    }
}

With the above configuration, the application watches for node data changes; whenever a change occurs, the new value is added to a Set<String>. This approach works for small data volumes but is not suitable for massive data sets that cannot be cached in JVM memory.

To update a value in Zookeeper, simply call zk.setData. Once the data is set, all services in the cluster receive the change through the watch mechanism.

Finished!

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JVMZooKeeperSpring Bootdata sharing
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.