Service Discovery

  我们通常在调用服务的时候,需要知道服务的地址,端口,或者其他一些信息,通常情况下,我们是把他们写到程序里面,但是随着服务越来越多,维护起来也越来越费劲,更重要的是,由于地址都是在程序中配置的,我们根本不知道远程的服务是否可用,当我们增加或者删除服务,我们又需要到配置文件中配置么? 这时候,Zookeeper帮大忙了,我们可以把我们的服务注册到Zookeeper中,创建一个临时节点(当连接断开之后,节点将被删除),存放我们的服务信息(url,ip,port等信息),把这些临时节点都存放在以serviceName命名的节点下面,这样我们要获取某个服务的地址,只需要到Zookeeper中找到这个path,然后就可以读取到里面存放的服务信息,这时候我们就可以根据这些信息调用我们的服务。这样,通过Zookeeper我们就做到了动态的添加和删除服务,做到了一旦一个服务时效,就会自动从Zookeeper中移除,基本上Curator中的Service Discovery就是做的这点事。
  下面我们用两张图片来比较一下,一般情况下的服务调用,和使用 Dynamic Service Registry 的区别

    

  使用zookeeper做服务注册之后:

关于Apache curator的service discovery的一些介绍可以参考官方文档:http://curator.apache.org/curator-x-discovery/index.html

Service Discovery 的使用

  一般而言,分为 Service Registry 和 Service Discovery,对应服务端和客户端。也就是由服务提供者,讲自身的信息注册到Zookeeper,然后,客户端通过到Zookeeper中查找服务信息,然后根据信息就行调用(见上图)。说了这么多,上代码了。

  首先我们定义个payload,我们这一在里面存储一些服务信息。这个信息会被保存在Zookeeper,这里只是举个例子,你还可以写入更多你想要的信息。

一般情况下,会在我们服务启动的时候就将服务信息注册,比如我们是web项目的话可以写一个Servlet Listener进行注册,这里为了方便,写一个Main方法进行测试,如果我们把我们的信息存储在payload中的话,UriSpec是可以不定义的。

package com.sf.zkclient.discovery;

import org.codehaus.jackson.map.annotate.JsonRootName;

@JsonRootName("details")
public class InstanceDetails { private String id; private String listenAddress; private int listenPort; private String interfaceName; public InstanceDetails(String id, String listenAddress, int listenPort, String interfaceName) {
this.id = id;
this.listenAddress = listenAddress;
this.listenPort = listenPort;
this.interfaceName = interfaceName;
} public InstanceDetails() {
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getListenAddress() {
return listenAddress;
} public void setListenAddress(String listenAddress) {
this.listenAddress = listenAddress;
} public int getListenPort() {
return listenPort;
} public void setListenPort(int listenPort) {
this.listenPort = listenPort;
} public String getInterfaceName() {
return interfaceName;
} public void setInterfaceName(String interfaceName) {
this.interfaceName = interfaceName;
} @Override
public String toString() {
return "InstanceDetails{" + "id='" + id + '\'' + ", listenAddress='" + listenAddress + '\'' + ", listenPort="
+ listenPort + ", interfaceName='" + interfaceName + '\'' + '}';
}
}
package com.sf.zkclient.discovery;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.x.discovery.ServiceDiscovery;
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.curator.x.discovery.details.JsonInstanceSerializer; import java.io.IOException; public class ServiceRegistry { private ServiceDiscovery<InstanceDetails> serviceDiscovery;
private final CuratorFramework client; public ServiceRegistry(CuratorFramework client, String basePath) throws Exception {
this.client = client;
JsonInstanceSerializer<InstanceDetails> serializer = new JsonInstanceSerializer<InstanceDetails>(
InstanceDetails.class);
serviceDiscovery = ServiceDiscoveryBuilder.builder(InstanceDetails.class).client(client).serializer(serializer)
.basePath(basePath).build();
serviceDiscovery.start();
} public void registerService(ServiceInstance<InstanceDetails> serviceInstance) throws Exception {
serviceDiscovery.registerService(serviceInstance);
} public void unregisterService(ServiceInstance<InstanceDetails> serviceInstance) throws Exception {
serviceDiscovery.unregisterService(serviceInstance); } public void updateService(ServiceInstance<InstanceDetails> serviceInstance) throws Exception {
serviceDiscovery.updateService(serviceInstance); } public void close() throws IOException {
serviceDiscovery.close();
}
}
package com.sf.zkclient.discovery;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.utils.CloseableUtils;
import org.apache.curator.x.discovery.ServiceDiscovery;
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.curator.x.discovery.ServiceProvider;
import org.apache.curator.x.discovery.details.JsonInstanceSerializer;
import org.apache.curator.x.discovery.strategies.RandomStrategy; import java.io.Closeable;
import java.util.List;
import java.util.Map; public class ServiceDiscoverer {
private ServiceDiscovery<InstanceDetails> serviceDiscovery;
private Map<String, ServiceProvider<InstanceDetails>> providers = Maps.newHashMap();
private List<Closeable> closeableList = Lists.newArrayList();
private Object lock = new Object(); public ServiceDiscoverer(CuratorFramework client, String basePath) throws Exception {
JsonInstanceSerializer<InstanceDetails> serializer = new JsonInstanceSerializer<InstanceDetails>(
InstanceDetails.class);
serviceDiscovery = ServiceDiscoveryBuilder.builder(InstanceDetails.class).client(client).basePath(basePath)
.serializer(serializer).build(); serviceDiscovery.start();
} public ServiceInstance<InstanceDetails> getInstanceByName(String serviceName) throws Exception {
ServiceProvider<InstanceDetails> provider = providers.get(serviceName);
if (provider == null) {
synchronized (lock) {
provider = providers.get(serviceName);
if (provider == null) {
provider = serviceDiscovery.serviceProviderBuilder().serviceName(serviceName)
.providerStrategy(new RandomStrategy<InstanceDetails>()).build();
provider.start();
closeableList.add(provider);
providers.put(serviceName, provider);
}
}
} return provider.getInstance();
} public synchronized void close() {
for (Closeable closeable : closeableList) {
CloseableUtils.closeQuietly(closeable);
}
} }
package com.sf.zkclient.discovery;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.curator.x.discovery.UriSpec; import java.util.UUID; /**
* User: hupeng
* Date: 14-9-16
* Time: 下午8:05
*/
public class ServerApp { public static void main(String[] args) throws Exception {
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(1000, 3));
client.start();
ServiceRegistry serviceRegistrar = new ServiceRegistry(client,"services");
ServiceInstance<InstanceDetails> instance1 = ServiceInstance.<InstanceDetails>builder()
.name("service1")
.port(12345)
.address("192.168.1.100") //address不写的话,会取本地ip
.payload(new InstanceDetails(UUID.randomUUID().toString(),"192.168.1.100",12345,"Test.Service1"))
.uriSpec(new UriSpec("{scheme}://{address}:{port}"))
.build();
ServiceInstance<InstanceDetails> instance2 = ServiceInstance.<InstanceDetails>builder()
.name("service2")
.port(12345)
.address("192.168.1.100")
.payload(new InstanceDetails(UUID.randomUUID().toString(),"192.168.1.100",12345,"Test.Service2"))
.uriSpec(new UriSpec("{scheme}://{address}:{port}"))
.build();
serviceRegistrar.registerService(instance1);
serviceRegistrar.registerService(instance2); Thread.sleep(Integer.MAX_VALUE);
}
}
package com.sf.zkclient.discovery;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.utils.CloseableUtils;
import org.apache.curator.x.discovery.ServiceInstance; public class ClientApp { public static void main(String[] args) throws Exception {
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(1000, 3));
client.start();
ServiceDiscoverer serviceDiscoverer = new ServiceDiscoverer(client,"services"); ServiceInstance<InstanceDetails> instance1 = serviceDiscoverer.getInstanceByName("service1"); System.out.println(instance1.buildUriSpec());
System.out.println(instance1.getPayload()); ServiceInstance<InstanceDetails> instance2 = serviceDiscoverer.getInstanceByName("service1"); System.out.println(instance2.buildUriSpec());
System.out.println(instance2.getPayload()); serviceDiscoverer.close();
CloseableUtils.closeQuietly(client);
}
}

结果:

17/02/25 16:59:06 INFO zookeeper.ClientCnxn: Socket connection established to 127.0.0.1/127.0.0.1:2181, initiating session
17/02/25 16:59:06 WARN zookeeper.ClientCnxnSocket: Connected to an old server; r-o mode will be unavailable
17/02/25 16:59:06 INFO zookeeper.ClientCnxn: Session establishment complete on server 127.0.0.1/127.0.0.1:2181, sessionid = 0x15a739961cd0011, negotiated timeout = 40000
17/02/25 16:59:06 INFO state.ConnectionStateManager: State change: CONNECTED
http://192.168.1.100:12345
InstanceDetails{id='a197a1b9-a6c6-495e-b500-1160e02bd0a6', listenAddress='192.168.1.100', listenPort=12345, interfaceName='Test.Service1'}
http://192.168.1.100:12345
InstanceDetails{id='a197a1b9-a6c6-495e-b500-1160e02bd0a6', listenAddress='192.168.1.100', listenPort=12345, interfaceName='Test.Service1'}
17/02/25 16:59:07 INFO imps.CuratorFrameworkImpl: backgroundOperationsLoop exiting
17/02/25 16:59:07 INFO zookeeper.ZooKeeper: Session: 0x15a739961cd0011 closed

zookeeper使用和原理探究(一)(转)的更多相关文章

  1. zookeeper使用和原理探究(一)

      zookeeper介绍zookeeper是一个为分布式应用提供一致性服务的软件,它是开源的Hadoop项目中的一个子项目,并且根据google发表的<The Chubby lock serv ...

  2. zookeeper使用和原理探究

    转:http://www.blogjava.net/BucketLi/archive/2010/12/21/341268.html zookeeper介绍 zookeeper是一个为分布式应用提供一致 ...

  3. 【转载】zookeeper使用和原理探究(一)

    最近开始看到一些公司在使用zookeeper,本身对此了解的很少,这里看到一篇非常好的文章,因此转载 原贴地址:http://www.blogjava.net/BucketLi/archive/201 ...

  4. Zookeeper 配置和原理探究

    一 Zookeeper是什么? 服务集群对外提供服务的过程中,有很多的配置需要随时更新,服务间需要协调工作,那么这些信息如何推送到各个节点?并且保证信息的一致性和可靠性?我们知道分布式协调服务很难正确 ...

  5. [原] KVM 虚拟化原理探究(1)— overview

    KVM 虚拟化原理探究- overview 标签(空格分隔): KVM 写在前面的话 本文不介绍kvm和qemu的基本安装操作,希望读者具有一定的KVM实践经验.同时希望借此系列博客,能够对KVM底层 ...

  6. [原] KVM 虚拟化原理探究 —— 目录

    KVM 虚拟化原理探究 -- 目录 标签(空格分隔): KVM KVM 虚拟化原理探究(1)- overview KVM 虚拟化原理探究(2)- QEMU启动过程 KVM 虚拟化原理探究(3)- CP ...

  7. [原] KVM 虚拟化原理探究(6)— 块设备IO虚拟化

    KVM 虚拟化原理探究(6)- 块设备IO虚拟化 标签(空格分隔): KVM [toc] 块设备IO虚拟化简介 上一篇文章讲到了网络IO虚拟化,作为另外一个重要的虚拟化资源,块设备IO的虚拟化也是同样 ...

  8. [原] KVM 虚拟化原理探究(5)— 网络IO虚拟化

    KVM 虚拟化原理探究(5)- 网络IO虚拟化 标签(空格分隔): KVM IO 虚拟化简介 前面的文章介绍了KVM的启动过程,CPU虚拟化,内存虚拟化原理.作为一个完整的风诺依曼计算机系统,必然有输 ...

  9. [原] KVM 虚拟化原理探究(4)— 内存虚拟化

    KVM 虚拟化原理探究(4)- 内存虚拟化 标签(空格分隔): KVM 内存虚拟化简介 前一章介绍了CPU虚拟化的内容,这一章介绍一下KVM的内存虚拟化原理.可以说内存是除了CPU外最重要的组件,Gu ...

随机推荐

  1. 生产项目加入到SVN版本控制

    零.介绍 每天定时备份是通过ftp打包和同步的方式,这些都是比较粗的备份,没法恢复到指定时间的文件,所以需要用到svn控制版本. (请不要问我为什么不用git) 一.现有项目文件加入版本控制 因为项目 ...

  2. 关于NPC和NP-Hard问题

    参考链接: 1. P.NP.NPC和NP-hard问题的理解 参考:<算法导论>

  3. Python基于比较的排序

    排序是算法学习中最基本的问题. 1.平均时间复杂度均为O(N2)的排序 1.1 插入排序 插入排序对少量元素的排序非常有效.工作机制就像打牌一样,为了将牌插入到已排好序的牌中,需要将牌与手中的牌从右向 ...

  4. 关于return和exit

    关于return和exit 在子进程退出的时候有两种方式,exit和exec族函数,不能使用return,为什么不能用return呢,exit改成return 会出现父子进程又各自重复开始进行. 1. ...

  5. BZOJ 1227 虔诚的墓主人

    Description 小W 是一片新造公墓的管理人.公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地.当地的居民都是非常虔诚的基督徒,他们愿意提前为自己 ...

  6. bootstrap form

    http://getbootstrap.com/examples/starter-template/ <form class="form-horizontal" role=& ...

  7. add a path cgi-bin to asp.net mvc

    1.简单,但是会丢失请求数据 protected void Application_BeginRequest() { string url = HttpContext.Current.Request. ...

  8. 视频边下边播--缓存播放数据流-b

    google搜索“iOS视频变下边播”,有好几篇博客写到了实现方法,其实只有一篇,其他都是copy的,不过他们都是使用的本地代理服务器的方式. 原理很简单,但是缺点也很明显,需要自己写一个本地代理服务 ...

  9. mongodb 简单部署方案及实例

    mongodb 简单部署方案及实例 转载:http://my.oschina.net/zhuzhu0129/blog/53290 第一节 准备工作 一 安装mongodb  我这里选用rehl 5.6 ...

  10. 读取Excel列内容

    http://blog.sina.com.cn/s/blog_6e001be701016yi8.html