摘要:在访问依赖的服务过程中,我们通常会通过在程序或者配置文件中写死ip列表的形式来发现下游服务,但在下游服务Cluster出现ip迁移的时候,会导致所有依赖该服务的上游应用重新配置ip列表并重新发布或者重启才能生效。本文介绍了如何使用阿里云配置管理产品ACM,并以zookeeper cluster服务为例,如何方便的在数据中心里实现透明的替换zookeeper坏掉的机器节点。
更好阅读体验参考:
https://yq.aliyun.com/articles/307579?spm=5176.8091938.0.0.23e81e01fyoLHL 
# 场景介绍
 
 
在一个数据中心里,一个zookeeper cluster常常会服务多条业务线或者业务系统,每个业务线或者业务系统有自己的开发团队,而zookeeper这类公共服务则会有专门的运维或者团队负责保障其服务可用性和连续性。
业务应用通过Apache Curator客户端或者原生的zookeeper客户端访问zookeeper服务,在这个过程中,必须在应用程序里指定connectString,即zookeeper服务所在的机器的ip列表, 代码示例如下:
                
final String connectString = "192.168.1.151:2181,192.168.1.152:2181,192.168.1.153:2181,192.168.1.154:2181,192.168.1.155:2181";
        final int sessionTimeoutInMs = 15000;
        final int connectionTimeoutInMs = 1000;
        final String appNs = "app1";
        CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder();
        
        CuratorFramework zkClient = builder
                       .connectString(connectString)
                       .connectionTimeoutMs(connectionTimeoutInMs)
                       .sessionTimeoutMs(sessionTimeoutInMs)
                       .namespace(appNs)
                       .retryPolicy(new RetryNTimes(6, 100))
                       .build();
        
        zkClient.start();
 
 
但在zookeeper的生产运行过程中,zookeeper服务cluster可能会遇到机器故障,机器迁移等情况,这个过程则需要zookeeper运维人员替换节点,将服务迁移到新的ip节点,整个流程,如下图所示,
 
 
https://img.alicdn.com/5476e8b07b923/TB1pF1Tef6H8KJjSspmXXb2WXXa
 
 
# 方案1 使用DNS或者VIP的服务发现方案
 
 
该方案如图所示:

 
 
在这个方案中,可以将zk服务ip挂在一个dns域名或者vip上.
这样在zookeeper替换节点时,应用无感知,这个方案即服务发现方案。
 
 
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.curator.ensemble.EnsembleProvider;
import com.alibaba.edas.acm.listener.ConfigChangeListener;
import com.alibaba.edas.acm.ConfigService;
import com.alibaba.edas.acm.exception.ConfigException;
public class ACMEnsembleProvider implements EnsembleProvider {
    private static final String ACM_ZK_CFG_DATAID = "com.taobao.zookeeper.connCfg";
    private static final String ACM_ZK_CFG_GROUP = "zookeeper";
    private static final int ACM_TIME_OUT_MS = 3000;
    private final static Executor acmCallBackExecutor = Executors.newSingleThreadScheduledExecutor();
    private ConfigChangeListener configChangeListener;
    private final AtomicReference<String> connectionString = new AtomicReference<String>("");
    private Properties cfg = new Properties();
    public String getZkHosts() {
        // 从ACM控制台该配置的"示例代码"中拷贝对应的值
        ConfigService.init("${domain}", "${namespace}", "${accessKey}", "${secretKey}");
        try {
            String zkServiceCfg = ConfigService.getConfig(ACM_ZK_CFG_DATAID, ACM_ZK_CFG_GROUP, ACM_TIME_OUT_MS);
            cfg.load(new StringReader(zkServiceCfg));
            String connectString = cfg.getProperty("connectString");
            connectionString.set(connectString);
            return connectString;
        } catch (ConfigException e1) {
            // logger.warn("acm.getConfig error with dataId : " +
            // dataIdZkHosts, e);
            e1.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    public void start() throws Exception {
        configChangeListener = new ConfigChangeListener() {
            public Executor getExecutor() {
                return acmCallBackExecutor;
            }
            public void receiveConfigInfo(String configInfo) {
                // logger.warn("receive zkHosts change in diamond, dataId : " +
                // dataIdZkHosts + ", changed zkHosts : "
                // + configInfo);
                try {
                    cfg.load(new StringReader(configInfo));
                } catch (IOException e) {
                    // process exception
                    e.printStackTrace();
                }
                String connectString = cfg.getProperty("connectString");
                connectionString.set(connectString);
            }
        };
        ConfigService.addListener(ACM_ZK_CFG_DATAID, ACM_ZK_CFG_GROUP, configChangeListener);
    }
    public String getConnectionString() {
        return connectionString.get();
    }
    public void close() throws IOException {
        // ConfigService.removeListener(ACM_ZK_CFG_DATAID, ACM_ZK_CFG_GROUP,
        // configChangeListener);
    }
}
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。