Are there any well documented use cases of Apache ZooKeeper being used to distribute configuration of Java applications, and in particular Spring services?
Like many use
After finding a suggestion to use a FactoryBean
to populate a regular PropertyPlaceholderConfigurer
I've built this:
package fms;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Properties;
public class ZkPropertiesFactoryBean extends AbstractFactoryBean<Properties> implements Watcher {
private Logger LOGGER = LoggerFactory.getLogger(ZkPropertiesFactoryBean.class);
private String zkConnect;
private String path;
private int timeout = 1000;
@Override protected Properties createInstance() throws Exception {
long start = System.currentTimeMillis();
Properties p = new Properties();
p.load(new ByteArrayInputStream(loadFromZk()));
double duration = (System.currentTimeMillis() - start)/1000d;
LOGGER.info(String.format("Loaded %d properties from %s:%s in %2.3f sec", p.size(), zkConnect, path, duration));
return p;
}
@Override public Class<Properties> getObjectType() {
return Properties.class;
}
private byte[] loadFromZk() throws IOException, KeeperException, InterruptedException {Stat stat = new Stat();
ZooKeeper zk = new ZooKeeper(zkConnect, timeout, this);
return zk.getData(path, false, stat);
}
@Override public void process(WatchedEvent event) {}
public void setPath(String path) {this.path = path;}
public void setZkConnect(String zkConnect) {this.zkConnect = zkConnect;}
}
In the spring-config.xml
you create the beans as follows:
<bean id="zkProperties" class="fms.ZkPropertiesFactoryBean" p:zkConnect="localhost:2181" p:path="/app/zk-properties"/>
<context:property-placeholder properties-ref="zkProperties"/>
Zookeeper can be very nicely leveraged with higher abstraction using Curator APIs for configuration management in distributed applications. To get started just follow these two steps.
STEP 1 : Start zookeper server and then start zookeeper cli and create some znodes. Znodes are nothing but UNIX like files which contain values, and name of files depict property name.
To create/fetch/update properties use these commands on zookeeper cli.
create /system/dev/example/port 9091
get /system/dev/example/port
set /system/dev/example/port 9092
To fetch these properties in java program refer this code snippet.
import java.util.HashMap;
import java.util.Map;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class App
{
public static void main( String[] args ) throws Exception
{
final String ZK = "localhost:2181";
final Map<String, String> data = new HashMap<String, String>();
CuratorFramework client = CuratorFrameworkFactory.newClient(ZK, new ExponentialBackoffRetry(100, 3));
client.start();
System.out.println(new String(client.getData().forPath("/system/dev/example/port")));
}
}
I created a set of spring beans integration zookeeper and springframework as propertyplaceholderconfigurer
, in github
: https://github.com/james-wu-shanghai/spring-zookeeper.git
you can take a look.
I was at an Apache Camel talk from James Strachen last week and he mentioned using ZooKeeper under the covers for their Java-based server in the cloud as the source of configuration info.
I've seen a talk from Adrian Colyer (CTO of SpringSource) about runtime config change in Spring, but does Spring support this today?
In my opinion, if you're starting from a typically architected Spring application, I don't see you having an easy job retrofitting dynamic config changes on top of it.
You should consider Spring Cloud Config:
http://projects.spring.io/spring-cloud/
Spring Cloud Config Centralized external configuration management backed by a git repository. The configuration resources map directly to Spring
Environment
but could be used by non-Spring applications if desired.
Source code available here:
https://github.com/spring-cloud/spring-cloud-config
Sample application here:
https://github.com/spring-cloud/spring-cloud-config/blob/master/spring-cloud-config-sample/src/main/java/sample/Application.java
Not spring in particular but for java generally, there is a CXF implementation of the distributed OSGI standard that uses ZooKeeper as the discovery server to push updated bundles down to the container : http://cxf.apache.org/dosgi-discovery.html.