最近尝试了一下etcd来做服务的注册发现

【etcd服务】

从etcd官网下载二进制文件即可,分配了三台机器做集群

10.0.1.98    etcd-001

10.0.1.205 etcd-002

10.0.1.182  etcd-003

然后用脚本启动服务

etcd --name etcd-002 --initial-advertise-peer-urls http://10.0.1.205:2380 --listen-peer-urls http://10.0.1.205:2380 --listen-client-urls http://10.0.1.205:2379,http://127.0.0.1:2379 --advertise-client-urls http://10.0.1.205:2379 --initial-cluster-token etcd-cluster --initial-cluster etcd-001=http://10.0.1.98:2380,etcd-002=http://10.0.1.205:2380,etcd-003=http://10.0.1.182:2380 --initial-cluster-state new

etcd --name etcd-001 --initial-advertise-peer-urls http://10.0.1.98:2380 --listen-peer-urls http://10.0.1.98:2380 --listen-client-urls http://10.0.1.98:2379,http://127.0.0.1:2379 --advertise-client-urls http://10.0.1.98:2379 --initial-cluster-token etcd-cluster --initial-cluster etcd-001=http://10.0.1.98:2380,etcd-002=http://10.0.1.205:2380,etcd-003=http://10.0.1.182:2380 --initial-cluster-state new

etcd --name etcd-003 --initial-advertise-peer-urls http://10.0.1.182:2380 --listen-peer-urls http://10.0.1.182:2380 --listen-client-urls http://10.0.1.182:2379,http://127.0.0.1:2379 --advertise-client-urls http://10.0.1.182:2379 --initial-cluster-token etcd-cluster --initial-cluster etcd-001=http://10.0.1.98:2380,etcd-002=http://10.0.1.205:2380,etcd-003=http://10.0.1.182:2380 --initial-cluster-state new

即可。

【服务发布】

etcd和zk不一样,他自身没有临时节点,需要客户端自己来实现。实现的大概逻辑是这样的:

设置一个一段时间超时的节点,比如60秒超时,如果超时了etcd上就找不到这个节点,

然后客户端用一个更小的时间间隔刷新这个节点的超时时间,比如每隔40秒刷新一次,重新把ttl设置成60秒。这样就可以保证在etcd上只要服务存活节点就一定存在,当服务关掉的时候,节点过一阵就消失了。

当然,如果能探测到服务关闭发一个del给etcd主动删除节点就更完美了。

在maven中添加依赖

 <dependency><groupId>org.mousio</groupId><artifactId>etcd4j</artifactId><version>2.13.0</version></dependency>

以spring boot上为例

package com.seeplant.etcd;import java.io.IOException;
import java.net.URI;
import java.util.concurrent.TimeoutException;import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.seeplant.util.Property;
import com.seeplant.util.ServerLogger;import mousio.client.retry.RetryOnce;
import mousio.etcd4j.EtcdClient;
import mousio.etcd4j.promises.EtcdResponsePromise;
import mousio.etcd4j.responses.EtcdAuthenticationException;
import mousio.etcd4j.responses.EtcdException;
import mousio.etcd4j.responses.EtcdKeysResponse;@Component
@Scope("singleton")
public class EtcdUtil {private EtcdClient client;private final String serverName = Property.getProperty("serverName"); // 自定义的服务名字,我定义成roomServerprivate final String dirString = "/roomServerList";private final String zoneId = Property.getProperty("zeonId"); // 自定义的一个标识,我定义成1private final String etcdKey = dirString + "/" + zoneId + "/" + serverName; // 这里就是发布的节点public EtcdUtil() {int nodeCount = Integer.parseInt(Property.getProperty("etcdGroupNodeCount"));URI[] uris = new URI[nodeCount]; // 对于集群,把所有集群节点地址加进来,etcd的代码里会轮询这些地址来发布节点,直到成功for (int iter = 0; iter < nodeCount; iter++) {String urlString = Property.getProperty("etcdHost" + new Integer(iter).toString());System.out.println(urlString);uris[iter] = URI.create(urlString);}client = new EtcdClient(uris);client.setRetryHandler(new RetryOnce(20)); //retry策略}public void regist() { // 注册节点,放在程序启动的入口try { // 用put方法发布一个节点EtcdResponsePromise<EtcdKeysResponse> p = client .putDir(etcdKey + "_" + Property.getProperty("serverIp") + "_" + Property.getProperty("serverPort")).ttl(60).send();p.get(); // 加上这个get()用来保证设置完成,走下一步,get会阻塞,由上面client的retry策略决定阻塞的方式new Thread(new GuardEtcd()).start(); // 启动一个守护线程来定时刷新节点} catch (Exception e) {// TODO: handle exceptionServerLogger.log("etcd Server not available.");}}public void destory() {try {EtcdResponsePromise<EtcdKeysResponse> p = client.deleteDir(etcdKey + "_" + Property.getProperty("serverIp") + "_" + Property.getProperty("serverPort")).recursive().send();p.get();client.close();} catch (IOException | EtcdException | EtcdAuthenticationException | TimeoutException e) {// TODO Auto-generated catch blocke.printStackTrace();}}private class GuardEtcd implements Runnable {@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {try {Thread.sleep(40*1000l);client.refresh(etcdKey + "_" + Property.getProperty("serverIp") + "_" + Property.getProperty("serverPort"),60).send();} catch (IOException | InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}

对于spring boot框架来说,可以实现CommandLineRunner来完成加载和销毁的主动调用

package com.seeplant;import javax.annotation.PreDestroy;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;import com.seeplant.etcd.EtcdUtil;
import com.seeplant.netty.RoomServer;
import com.seeplant.util.Property;import io.netty.channel.ChannelFuture;@SpringBootApplication
public class App implements CommandLineRunner{@Autowiredprivate RoomServer roomServer;@Autowiredprivate EtcdUtil etcdUtil;public static void main(String[] args) {SpringApplication.run(App.class, args);}@Beanpublic RoomServer roomServer() {return new RoomServer(Integer.parseInt(Property.getProperty("serverPort")));}@Overridepublic void run(String... args) throws Exception {etcdUtil.regist();ChannelFuture future = roomServer.start();Runtime.getRuntime().addShutdownHook(new Thread(){@Overridepublic void run() {roomServer.destroy();}});future.channel().closeFuture().syncUninterruptibly();}@PreDestroypublic void destory() {etcdUtil.destory();}
}

以上的retry策略是尝试一次就放弃,另外还写了一个retry策略是等待时间线性增长策略,仅供参考

package com.seeplant.etcd;import com.seeplant.util.ServerLogger;import mousio.client.ConnectionState;
import mousio.client.retry.RetryPolicy;/*** 为Etcd提供倍增的重试策略* @author yuantao**/
public class RetryDoublePolicy extends RetryPolicy {private final int timeSlot; // 步长private int stepTimes = 1; // 倍数public RetryDoublePolicy(int startRetryTime) {super(startRetryTime);// TODO Auto-generated constructor stubthis.timeSlot = startRetryTime;}@Overridepublic boolean shouldRetry(ConnectionState connectionState) {// TODO Auto-generated method stubstepTimes *= 2;connectionState.msBeforeRetry = stepTimes*timeSlot; // 重设时间System.out.println("try " + stepTimes);if (stepTimes > 128) {ServerLogger.log("etcd connection failed");stepTimes = 1;}return true;}}

以上是注册服务,对于服务管理、负载均衡方,只需要按照http://127.0.0.1:2379/v2/keys/roomServerList/1/ 这种方式get就可以得到节点内容。比如我的服务发布的节点通过get返回的内容如下:

{
  "action": "get",
  "node": {
    "key": "/roomServerList/1",
    "dir": true,
    "nodes": [
      {
        "key": "/roomServerList/1/roomServer0_127.0.0.1_9090",
        "dir": true,
        "expiration": "2017-09-04T05:10:21.214199005Z",
        "ttl": 42,
        "modifiedIndex": 202,
        "createdIndex": 202
      }
    ],
    "modifiedIndex": 36,
    "createdIndex": 36
  }
}

【Java】用etcd做服务注册和发现相关推荐

  1. 一个故事,一段代码告诉你如何使用不同语言(GolangC#)提供相同的能力基于Consul做服务注册与发现

    文章目录 引言 什么是微服务 传统服务 微服务 什么是服务注册与服务发现 为什么要使用不同的语言提供相同的服务能力 服务协调器 服务注册 Golang C#(.NetCore3.1) 服务发现 通过H ...

  2. etcd 访问 锁_在系统中用etcd实现服务注册和发现

    系统中实现服务注册与发现所需的基本功能有 服务注册:同一service的所有节点注册到相同目录下,节点启动后将自己的信息注册到所属服务的目录中. 健康检查:服务节点定时发送心跳,注册到服务目录中的信息 ...

  3. 在系统中用etcd实现服务注册和发现

    系统中实现服务注册与发现所需的基本功能有 服务注册:同一service的所有节点注册到相同目录下,节点启动后将自己的信息注册到所属服务的目录中. 健康检查:服务节点定时发送心跳,注册到服务目录中的信息 ...

  4. 用etcd实现服务注册和发现

    系统中实现服务注册与发现所需的基本功能有 服务注册:同一service的所有节点注册到相同目录下,节点启动后将自己的信息注册到所属服务的目录中. 健康检查:服务节点定时发送心跳,注册到服务目录中的信息 ...

  5. SpringBoot -- 服务注册与发现

    微服务 实践"微服务"自然要学习如何做服务注册与发现 基于SpringBoot来进行微服务的学习,自然选择了与之息息相关的SpringCloud;当然可以选择其他的技术进行,比如d ...

  6. go语言高并发与微服务实战_go-micro+gin+etcd微服务实战之服务注册与发现

    在构建微服务时,使用服务发现可以减少配置的复杂性,本文以go-micro为微服务框架,使用etcd作为服务发现服务,使用gin开发golang服务. 使用gin 的原因是gin能够很好的和go-mic ...

  7. Dubbo学习笔记001---分布式服务调用_Dubbo简介_依赖zookeeper做为注册中心进行服务注册与发现

    JAVA技术交流QQ群:170933152 Dubbo是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员 ...

  8. etcd学习和实战:4、Java使用etcd实现服务发现和管理

    etcd学习和实战:4.Java使用etcd实现服务发现和管理 文章目录 etcd学习和实战:4.Java使用etcd实现服务发现和管理 1. 前言 2. 代码 2.1 服务注册 2.2 服务发现 2 ...

  9. ETCD 十六 服务注册与发现

    微服务架构中的服务注册与发现 在微服务架构中,多个微服务间的通信需要依赖服务注册与发现组件获取指定服务实例的地址信息,才能正确地发起 RPC 调用,保证分布式系统的高可用.高并发.服务注册与发现主要包 ...

最新文章

  1. ffmpeg-20160526-git-bin
  2. Google guava cache源码解析1--构建缓存器(2)
  3. 学生课程表管理系统——stage 1
  4. java怎么通过ip地址查具体地址_制作通过IP 查询地址的java版程序
  5. 了解SQL和MySQL数据库
  6. oracle设置打印机,使用 Oracle Solaris 打印管理器设置网络连接的打印机
  7. 打破国外垄断,开发中国人自己的编程语言(1):编写解析表达式的计算器
  8. java开发软件怎么安装不了_java开发软件的安装
  9. 实测Maven上传jar包到私服的方法归纳
  10. 深度学习基础6(微分,偏导,梯度,链式法则)
  11. SQL面试题整理_数据库知识点
  12. 淘宝关键字搜索商品-v1
  13. Opencv-python 色相饱和度(HLS)
  14. CLIP论文笔记--《Learning Transferable Visual Models From Natural Language Supervision》
  15. typescript Type 'NodeListOfany' must have a '[Symbol.iterator]()' method that returns an iterato
  16. Apple Developer文档笔记(一)AppKit App Structure
  17. 微信分享功能,手机分享图片不显示
  18. 蓝桥杯真题 ——单词分析(python3)
  19. 迅睿CMS 万网虚拟主机无法连接数据库
  20. CSS实现可爱的BingDwenDwen

热门文章

  1. 双击鼠标HOOK学习
  2. Java面向对象习题
  3. layer介绍与使用
  4. c/c++判断NULL指针
  5. python一年365天、初始水平值_一年365天,初始水平值为1.0,每工作一天水平增加0.01,不工作时水平不下降,一周连续工作5天,请编写程序计算最终水平值。...
  6. 八字生助克泄耗数据生成
  7. 量子三体问题: Landau Fall
  8. IM即时通讯设计----聊天服务(附源码)
  9. 当米饭已被吃腻的时候[zt]
  10. java enum比较_Java枚举比较