etcd

package com.zt.etcddemo;

import com.zt.etcddemo.config.EtcdConfig;
import io.etcd.jetcd.ByteSequence;
import io.etcd.jetcd.Client;
import io.etcd.jetcd.Election;
import io.etcd.jetcd.Election.Listener;
import io.etcd.jetcd.KV;
import io.etcd.jetcd.Lease;
import io.etcd.jetcd.Lock;
import io.etcd.jetcd.Watch;
import io.etcd.jetcd.election.CampaignResponse;
import io.etcd.jetcd.election.LeaderKey;
import io.etcd.jetcd.election.LeaderResponse;
import io.etcd.jetcd.kv.GetResponse;
import io.etcd.jetcd.kv.PutResponse;
import io.etcd.jetcd.lease.LeaseKeepAliveResponse;
import io.etcd.jetcd.lease.LeaseTimeToLiveResponse;
import io.etcd.jetcd.lock.LockResponse;
import io.etcd.jetcd.options.LeaseOption;
import io.etcd.jetcd.options.PutOption;
import io.grpc.stub.StreamObserver;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class EtcdDemoApplicationTests {

  @Autowired
  EtcdConfig etcdConfig;

  @Autowired
  Client client;

  @Test
  void contextLoads() {
    // client.get
  }

  public static void main(String[] args) {
    String endpoints = "http://122.9.65.138:2379,http://122.9.65.138:2379";
    // 需要参数自己可以添加认证
    try (Client etcdClient = Client.builder().endpoints(endpoints.split(",")).build()) {
      //<editor-fold desc="1.build">
      // 获取键值对client
      KV kv = etcdClient.getKVClient();
      // 获取租约client
      Lease lease = etcdClient.getLeaseClient();
      // 监听
      Watch watch = etcdClient.getWatchClient();
      // 选举
      Election election = etcdClient.getElectionClient();
      // 锁
      Lock lock = etcdClient.getLockClient();
      //</editor-fold>

      //<editor-fold desc="2.JETCD — KV 读写">
      ByteSequence key = ByteSequence.from("test-key", StandardCharsets.UTF_8);
      ByteSequence value = ByteSequence.from("test-value", StandardCharsets.UTF_8);

      //<editor-fold desc="3.event 事件监听">
      watch.watch(key, listener -> {
        listener.getEvents().forEach(event -> {
          switch (event.getEventType()) {
            case DELETE:
              // 当KEY被删除触发
              System.out.println("key被删除" + event);
              break;
            case PUT:
              // 当key推送触发
              System.out.println("key推送触发" + event);
              break;
            default:
              System.out.println("<UNK>" + event);
              break;
          }
        });
      });
      //</editor-fold>

      // 推送
      CompletableFuture<PutResponse> putFuture = kv.put(key, value);
      // 拉取
      CompletableFuture<GetResponse> getFuture = kv.get(key);
      try {
        String tmpValue = getFuture.get().getKvs().getFirst().getValue().toString(StandardCharsets.UTF_8);
      } catch (InterruptedException | ExecutionException e) {
        System.out.println(e);
      }

      try {
        PutResponse putResponse = putFuture.get();
        System.out.println(putResponse.getPrevKv());
      } catch (InterruptedException | ExecutionException e) {
        System.out.println(e);
      }
      // 删除
      kv.delete(key);
      //</editor-fold>

      //<editor-fold desc="3.Lease 续约">
      // 创建一个租约,存在60秒,创建开始倒计时
      long leaseId = 0L;
      try {
        leaseId = lease.grant(60).get().getID();
      } catch (InterruptedException | ExecutionException e) {
        // TODO Auto-generated catch block
        System.out.println(e);
      }
      // 参数构建
      LeaseOption leaseOption = LeaseOption.newBuilder().withAttachedKeys().build();
      CompletableFuture<LeaseTimeToLiveResponse> leaseFuture = lease.timeToLive(leaseId, leaseOption);
      try {
        // 获取绑定租约的对象
        List<ByteSequence> keys = leaseFuture.get().getKeys();
      } catch (InterruptedException | ExecutionException e) {
        System.out.println(e);
      }
      // 租约重新开始计数
      lease.keepAliveOnce(leaseId);
      // 长时间生效每次租约到期触发
      StreamObserver<LeaseKeepAliveResponse> observer = new StreamObserver<LeaseKeepAliveResponse>() {
        @Override
        public void onNext(LeaseKeepAliveResponse value) {
          System.out.println("租约时间到达");
        }

        @Override
        public void onError(Throwable t) {
        }

        @Override
        public void onCompleted() {
        }
      };
      lease.keepAlive(leaseId, observer);
      // KV使用租约到期删除
      PutOption option = PutOption.newBuilder().withLeaseId(leaseId).build();
      kv.put(key, value, option);
      // 撤销一个租约
      lease.revoke(leaseId);
      //</editor-fold>

      //<editor-fold desc="4. Election 选举">
      ByteSequence electionName = ByteSequence.from("electionName", StandardCharsets.UTF_8);
      ByteSequence proposal_1 = ByteSequence.from("proposal_1", StandardCharsets.UTF_8);
      ByteSequence proposal_2 = ByteSequence.from("proposal_2", StandardCharsets.UTF_8);
      Listener listener = new Listener() {
        @Override
        public void onNext(LeaderResponse response) {
          System.out.println(response.getKv().getValue().toString(StandardCharsets.UTF_8));
        }

        @Override
        public void onError(Throwable throwable) {
        }

        @Override
        public void onCompleted() {
        }
      };
      // 监听选举范围类当选者事件
      election.observe(electionName, listener);
      // 参与,租约到期,竞选者推出
      CompletableFuture<CampaignResponse> campaign = election.campaign(electionName, leaseId, proposal_1);
      try {
        // 阻塞获取领导权限
        LeaderKey leaderKey = campaign.get().getLeader();
        // 获取当选者
        CompletableFuture<LeaderResponse> leaderFuture = election.leader(electionName);
        String lead = leaderFuture.get().getKv().getValue().toString(StandardCharsets.UTF_8);
        System.out.println(lead);
        // 领导位置宣布给另一个;
        election.proclaim(leaderKey, proposal_2);
        // 辞退当选位置
        election.resign(leaderKey);
      } catch (InterruptedException | ExecutionException e) {
        System.out.println(e);
      }
      //</editor-fold>

      //<editor-fold desc="5.lock 锁 ">
      // 锁的使用要注意阻塞获取下锁,释放锁这个好像有点问题,还要等租约。使用请注意
      ByteSequence lock_key = ByteSequence.from("lock_key", StandardCharsets.UTF_8);
      // 加锁,租约到期释放
      CompletableFuture<LockResponse> lockFuture = lock.lock(lock_key, leaseId);
      try {
        // 阻塞获取锁
        String lockStr = lockFuture.get().getKey().toString(StandardCharsets.UTF_8);
      } catch (InterruptedException | ExecutionException e) {
        System.out.println(e);
      }
      // 释放锁
      lock.unlock(lock_key);
      //</editor-fold>
    }
  }
}

 

在Java中调用ETCD使用JETCD--API3 基础部分_jetcd-core-CSDN博客

前言

ETCD是用于共享配置和服务发现的分布式,一致性的KV存储系统。有很多使用场景,包括:配置管理、服务注册于发现、选主、应用调度、分布式队列和分布式锁。因此本文主要介绍JAVA中使用ETCD实现分布式管理。使用工具JETCD


一、ETCD简单介绍

etcd 是云原生架构中重要的基础组件,由 CNCF 孵化托管。etcd 在微服务和 Kubernates 集群中不仅可以作为服务注册于发现,还可以作为 key-value 存储的中间件。
ETCD使用Raft协议来维护集群内各个节点状态的一致性。简单说,ETCD集群是一个分布式系统,由多个节点相互通信构成整体对外服务,每个节点都存储了完整的数据,并且通过Raft协议保证每个节点维护的数据是一致的。
ETCD比较多的应用场景是用于服务发现,服务发现 (Service Discovery) 要解决的是分布式系统中最常见的问题之一,即在同一个分布式集群中的进程或服务如何才能找到对方并建立连接。etcd 有很多使用场景,包括:配置管理、服务注册发现、选主、应用调度、分布式队列和分布式锁的应用
具体了解:https://etcd.io/docs/v3.4/quickstart

二、JETCD简介

1.引入库

jetcd是etcd v3版本的官方java客户端工具,java项目通过该库可以对etcd执行各种操作,当前最新发布版本是0.5.7
jetcd官方github:https://github.com/etcd-io/jetcd

1.MAVEN 中引入依赖

<dependency>
  <groupId>io.etcd</groupId>
  <artifactId>jetcd-core</artifactId>
  <version>${jetcd-version}</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

2.构建JETCD链接ETCD

对应获取各个Clients:

String endpoints="http://127.0.0.1:2379,http://127.0.0.2:2379" ;
		//需要参数自己可以添加认证
		Client etcdClient=Client.builder().endpoints(endpoints.split(",")).build();
		//获取键值对client
		KV kv=etcdClient.getKVClient();
		//获取租约client
		Lease lease=etcdClient.getLeaseClient();
		//监听
		Watch watch =etcdClient.getWatchClient();
		//选举
		Election election =etcdClient.getElectionClient();
		//锁
		Lock lock=etcdClient.getLockClient();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

3.JETCD 的使用

3.1 JETCD — KV
	ByteSequence key=ByteSequence.from("test-key",StandardCharsets.UTF_8);
	ByteSequence value=ByteSequence.from("test-value",StandardCharsets.UTF_8);
	//推送
	CompletableFuture<PutResponse> putFuture = kv.put(key, value);
	//拉取
	CompletableFuture<GetResponse> getFuture = kv.get(key);
	try {
		String tmpValue=getFuture.get().getKvs().get(0).getValue().toString(StandardCharsets.UTF_8);
	} catch (InterruptedException | ExecutionException e) {
		e.printStackTrace();
	}
	//删除
	kv.delete(key);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
3.2 JETCD — Watch
watch.watch(key, listener ->{
			listener.getEvents().forEach(event->{
				switch (event.getEventType()) {
				case DELETE:
					//当KEY被删除触发
					break;
				case PUT:
					//当key推送触发
					break;
				default:
					break;
				}
			});;
		});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
3.3 JETCD — Lease
		
		//创建一个租约,存在60秒,创建开始倒计时
		long leaseId=0L;
		try {
			leaseId = lease.grant(60).get().getID();
		} catch (InterruptedException | ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//参数构建
		LeaseOption leaseOption=LeaseOption.newBuilder().withAttachedKeys().build();
		CompletableFuture<LeaseTimeToLiveResponse> leaseFuture= lease.timeToLive(leaseId, leaseOption);
		try {
			//获取绑定租约的对象
		List<ByteSequence> keys = leaseFuture.get().getKeys();
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
		//租约重新开始计数
		lease.keepAliveOnce(leaseId);
		//长时间生效每次租约到期触发
		StreamObserver<LeaseKeepAliveResponse> observer =new StreamObserver<LeaseKeepAliveResponse>() {
			@Override
			public void onNext(LeaseKeepAliveResponse value) {
				System.out.println("租约时间到达");
			}
			@Override
			public void onError(Throwable t) {
			}
			@Override
			public void onCompleted() {
			}
		};
		lease.keepAlive(leaseId, observer);
		//KV使用租约到期删除
		PutOption option=PutOption.newBuilder().withLeaseId(leaseId).build();
		kv.put(key, value, option);
		//撤销一个租约
		lease.revoke(leaseId);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
3.4 JETCD — Election
		ByteSequence electionName=ByteSequence.from("electionName",StandardCharsets.UTF_8);
		ByteSequence proposal_1=ByteSequence.from("proposal_1",StandardCharsets.UTF_8);
		ByteSequence proposal_2=ByteSequence.from("proposal_2",StandardCharsets.UTF_8);
		Listener listener=new Listener() {
			@Override
			public void onNext(LeaderResponse response) {
				System.out.println(response.getKv().getValue().toString(StandardCharsets.UTF_8));
			}
			@Override
			public void onError(Throwable throwable) {
			}			
			@Override
			public void onCompleted() {
			}
		};
		//监听选举范围类当选者事件
		election.observe(electionName, listener);
		//参与,租约到期,竞选者推出
		CompletableFuture<CampaignResponse> campaign = election.campaign(electionName, leaseId, proposal_1);
		try {
			//阻塞获取领导权限
			LeaderKey leaderKey = campaign.get().getLeader();
			//获取当选者
			CompletableFuture<LeaderResponse> leaderFuture = election.leader(electionName);
			String lead= leaderFuture.get().getKv().getValue().toString(StandardCharsets.UTF_8);
			System.out.println(lead);
			//领导位置宣布给另一个;
			election.proclaim(leaderKey, proposal_2);
			//辞退当选位置
			election.resign(leaderKey);
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
3.5 JETCD — lock

锁的使用要注意阻塞获取下锁,释放锁这个好像有点问题,还要等租约。使用请注意

    ByteSequence lock_key=ByteSequence.from("lock_key",StandardCharsets.UTF_8);
   	//加锁,租约到期释放
   	CompletableFuture<LockResponse> lockFuture = lock.lock(lock_key, leaseId);
   	try {
   		//阻塞获取锁
   		String lockStr=lockFuture.get().getKey().toString(StandardCharsets.UTF_8);
   	} catch (InterruptedException | ExecutionException e) {
   		e.printStackTrace();
   	}
   	//释放锁
   	lock.unlock(lock_key);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

总结

以上是在JAVA 中使用JETCD的基础操作方法。
后续会使用这些API去实现相应的场景的代码说明。

posted @ 2025-04-27 16:56  CharyGao  阅读(27)  评论(0)    收藏  举报