springboot 集成 etcd

springboot 集成 etcd

往期内容

  • ETCD 简介
  • docker部署ETCD

前言

好久不见各位小伙伴们,上两期内容中,我们对于分布式kv存储中间件有了简单的认识,完成了docker-compose 部署etcd集群以及可视化工具 etcd Keeper,既然有了认识,完成了部署,那么当然要用起来啦

那么本期我们简单使用springboot 集成etcd 实现一些简单的数据操作


1-创建springboot工程

对于java开发的小伙伴来说,springboot项目的创建这块,我们不在过多赘述,简单贴一下我的版本依赖,我们直接跳转至下一环节

<properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>

2-集成依赖

简单的开发需要集成ETCD的依赖

那么直接pom.xml

<!-- https://mvnrepository.com/artifact/io.etcd/jetcd-core 主要依赖-->
        <dependency>
            <groupId>io.etcd</groupId>
            <artifactId>jetcd-core</artifactId>
            <version>0.7.5</version>
        </dependency>


        <!-- (可选依赖)->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.21</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.52</version>
        </dependency>

3-全局配置

application.yml

#etcd
etcd:
  host: http://XXXXXX #你自己的宿主机
  port: 12379  #etcd的宿主机port 上一节中我的容器中的2379映射到了宿主机上的12379 所以配置12379

增加全局配置文件读取yml配置信息

@Configuration
@Data
public class EtcdConfig {

    @Value("${etcd.host}")
    private String etcdHost;

    @Value("${etcd.port}")
    private int etcdPort;

}

创建etcd连接工厂

 @Bean
    public Client etcdFactory() {
        return Client.builder().endpoints(etcdHost + ":" + etcdPort).build();
    }

4-接入使用

创建service类进行简单的操作,这里简单的存储和redis一样,也是key-value的形式,不过多赘述

对于租约lease 而言类似一redis的键设置过期时间,过期时间内可以续期,过期时间之后etcd将会删除存储的内容

package com.jerry.springetcd.service;

import com.alibaba.fastjson2.JSON;
import io.etcd.jetcd.ByteSequence;
import io.etcd.jetcd.Client;
import io.etcd.jetcd.Lease;
import io.etcd.jetcd.kv.GetResponse;
import io.etcd.jetcd.kv.PutResponse;
import io.etcd.jetcd.lease.LeaseTimeToLiveResponse;
import io.etcd.jetcd.options.LeaseOption;
import io.etcd.jetcd.options.PutOption;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Service

public class EtcdService {

    @Resource
    private Client etcdClient;

    /***
     * Put a key-value pair to etcd
     * @param key
     * @param value
     * @return
     */
    public CompletableFuture<PutResponse> putValueWithOutLease(String key, String value) {
        ByteSequence keyByte = ByteSequence.from(key, StandardCharsets.UTF_8);
        ByteSequence valueByte = ByteSequence.from(value, StandardCharsets.UTF_8);

        return etcdClient.getKVClient().put(keyByte, valueByte);
    }

    /***
     * Get the value of a key from etcd
     * @param key
     * @return
     */
    public CompletableFuture<String> getValue(String key) {
        ByteSequence keyByte = ByteSequence.from(key, StandardCharsets.UTF_8);
        CompletableFuture<GetResponse> getFuture = etcdClient.getKVClient().get(keyByte);

        return getFuture.thenApply(getResponse -> {
            if (getResponse.getKvs().isEmpty()) {
                return null;
            }
            return getResponse.getKvs().get(0).getValue().toString(StandardCharsets.UTF_8);
        });
    }

    /***
     * Delete a key-value pair from etcd
     * @param key
     * @return
     */
    public CompletableFuture<Void> deleteValue(String key) {
        ByteSequence keyByte = ByteSequence.from(key, StandardCharsets.UTF_8);
        return etcdClient.getKVClient().delete(keyByte).thenAccept(deleteResponse -> {
        });
    }


    /***
     * Put a key-value pair to etcd with a lease
     * @param key
     * @param value
     * @param leaseTime
     * @param timeout
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     * @throws TimeoutException
     */
    public CompletableFuture<PutResponse> putValueWithLease(String key, String value, long leaseTime, long timeout) throws ExecutionException, InterruptedException, TimeoutException {
        ByteSequence keyByte = ByteSequence.from(key, StandardCharsets.UTF_8);
        ByteSequence valueByte = ByteSequence.from(value, StandardCharsets.UTF_8);
        Lease leaseClient = etcdClient.getLeaseClient();
        long leaseId = leaseClient.grant(leaseTime).get(timeout, TimeUnit.SECONDS).getID();
        System.out.println("Lease ID: " + leaseId);
        PutOption putOption = PutOption.newBuilder().withLeaseId(leaseId).build();
        // put value with lease
        CompletableFuture<PutResponse> putResponse = etcdClient.getKVClient().put(keyByte, valueByte, putOption);
       return putResponse;
    }




    /***
     * 续租一个已存在的租约
     * @param leaseId
     * @return
     */
    public CompletableFuture<Void> renewLease(long leaseId) {
        Lease leaseClient = etcdClient.getLeaseClient();
        return leaseClient.keepAliveOnce(leaseId).thenAccept(keepAliveResponse -> {
            if (keepAliveResponse.getTTL() == -1) {
                // lease has expired
                System.out.println("Lease has expired");
            }else {
                System.out.println("Lease is renewed");
            }
        });
    }

    /***
     * 获取租约的信息
     * @param leaseId
     * @return
     */
    public CompletableFuture<LeaseTimeToLiveResponse> getLeaseInfo(long leaseId) throws ExecutionException, InterruptedException {
        Lease leaseClient = etcdClient.getLeaseClient();
        LeaseTimeToLiveResponse lTRes = leaseClient.timeToLive(leaseId, LeaseOption.newBuilder().withAttachedKeys().build()).get();
        return CompletableFuture.completedFuture(lTRes);
    }
}

创建简单的controller 进行请求尝试

//存 
@PostMapping("/putValueWithOutLease")
    public CompletableFuture<PutResponse> putValueWithOutLease(@RequestParam String key, @RequestParam String value) {
        return etcdService.putValueWithOutLease(key, value);
    }
//取
@GetMapping("/get")
    public CompletableFuture<String> getValueWithOutLease(@RequestParam String key) {
        return etcdService.getValue(key);
    }
//删除
 @DeleteMapping("/deleteValue")
    public CompletableFuture<Void> deleteValue(@RequestParam String key) {
        return etcdService.deleteValue(key);
    }
//带租约的存储
 @PostMapping("/putValueWithLease")
    public CompletableFuture<PutResponse> putValueWithLease(
            @RequestParam String key,
            @RequestParam String value,
            @RequestParam Long leaseTime,
            @RequestParam Long timeOut
    ) throws ExecutionException, InterruptedException, TimeoutException {
        return etcdService.putValueWithLease(key, value,leaseTime, timeOut);
    }
//顺序存储
 @PutMapping("/writeWithOutLease")
    public String writeValue(@RequestParam int num) {
        logger.info("write value to etcd");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("write");

        for (int i = 0; i < num; i++) {
            etcdService.putValueWithOutLease("/test/" + i, String.valueOf(i));
        }

        stopWatch.stop();
        logger.info("write value to etcd, time: " + stopWatch.prettyPrint());
        return "success";
    }
//查看租约状态
 @PostMapping("/viewLeaseDetail")
    public CompletableFuture<LeaseTimeToLiveResponse> getLeaseInfo(@RequestParam Long leaseId) throws ExecutionException, InterruptedException {
        return etcdService.getLeaseInfo(leaseId);
    }
//续租
 @PostMapping("/renewLease")
    public CompletableFuture<Void> renewLease(@RequestParam long leaseId) throws ExecutionException, InterruptedException, TimeoutException {
        return etcdService.renewLease(leaseId);
    }

5-接口模拟验证

使用apipost 进行接口调用,查看执行情况

  • 不带租约存储
    请添加图片描述

请添加图片描述

  • 不带租约查询

请添加图片描述

  • 手动删除key

请添加图片描述

  • 删除后重新查询,返回空值

请添加图片描述

  • 带租约存储值

设置key=/acc/test val=hello etcd 租约时间为2min的数据存储

请添加图片描述

请添加图片描述

  • 查询数据信息
    请添加图片描述

demo gitee地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/950784.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【递归与分治】Leetcode23:合并K个升序链表

一、题目描述 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 示例 1&#xff1a; 输入&#xff1a;lists [[1,4,5],[1,3,4],[2,6]] 输出&#xff1a;[1,1,2,3,4,4,5,6] 解释&#xff1a;链表数…

将分支A某一个commit合并到分支B

1.寻找A分支的commit 在分支B下&#xff0c;点击git找到分支A的历史提交记录,如图所示&#xff1a; 2.点击分支A的某个commit&#xff0c;进行合并到分支B 将这个commit&#xff0c;进行cherry-Pick&#xff0c;就可以把分支A的合并到分支B上的本地仓库中&#xff0c;然后就可…

如何快速上手一个鸿蒙工程

作为一名鸿蒙程序猿&#xff0c;当你换了一家公司&#xff0c;或者被交接了一个已有的业务。前辈在找你之前十分钟写了一个他都看不懂的交接文档&#xff0c;然后把一个鸿蒙工程交接给你了&#xff0c;说以后就是你负责了。之后几天你的状态大概就是下边这样的&#xff0c;一堆…

预训练语言模型——BERT

1.预训练思想 有了预训练就相当于模型在培养大学生做任务&#xff0c;不然模型初始化再做任务就像培养小学生 当前数据层面的瓶颈是能用于预训练的语料快被用完了 现在有一个重要方向是让机器自己来生成数据并做微调 1.1 预训练&#xff08;Pre - training&#xff09;vs. 传…

关于FPGA(现场可编程门阵列)工程技术人员的详细介绍

一、FPGA工程技术人员概述 FPGA工程技术人员是专注于现场可编程门阵列&#xff08;FPGA&#xff09;设计、开发、测试及优化的专业技术人员。他们利用FPGA的灵活性和可编程性&#xff0c;为各种应用创建高效、定制化的硬件解决方案。 二、主要工作任务 FPGA逻辑设计&#xf…

机器学习模型评估指标

模型的评估指标是衡量一个模型应用于对应任务的契合程度&#xff0c;常见的指标有&#xff1a; 准确率&#xff08;Accuracy&#xff09;: 正确预测的样本数占总样本数的比例。适用于类别分布均衡的数据集。 精确率&#xff08;Precision&#xff09;: 在所有被预测为正类的样…

基于html5实现音乐录音播放动画源码

源码介绍 基于html5实现音乐录音播放动画源码是一款类似Shazam的UI&#xff0c;点击按钮后&#xff0c;会变成为一个监听按钮。旁边会有音符飞入这个监听按钮&#xff0c;最后转换成一个音乐播放器。 效果预览 源码获取 基于html5实现音乐录音播放动画源码

基于深度学习的视觉检测小项目(六) 项目的信号和变量的规划

• 关于前后端分离 当前流行的一种常见的前后端分离模式是vueflask&#xff0c;vueflask模式的前端和后端之间进行数据的传递通常是借助 API&#xff08;应用程序编程接口&#xff09;来完成的。vue通过调用后端提供的 API 来获取或提交数据。例如&#xff0c;前端可能通过发送…

文件传输速查表:Windows 和 Linux

文件传输速查表&#xff1a;Windows 和 Linux 免责申明 本文章仅供网络安全相关学习与研究使用&#xff0c;旨在促进技术交流与安全知识普及&#xff0c;严禁将本文内容及相关工具用于未授权的渗透测试或任何违法活动。 重要声明&#xff1a; 由于传播、使用本文章所提供的信…

基于SpringBoot+Vue的“有光”摄影分享网站系统

基于SpringBootVue的“有光”摄影分享网站系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345…

课题推荐——基于GPS的无人机自主着陆系统设计

关于“基于GPS的无人机自主着陆系统设计”的详细展开&#xff0c;包括项目背景、具体内容、实施步骤和创新点。如需帮助&#xff0c;或有导航、定位滤波相关的代码定制需求&#xff0c;请点击文末卡片联系作者 文章目录 项目背景具体内容实施步骤相关例程MATLAB例程python例程 …

腾讯云AI代码助手编程挑战赛-凯撒密码解码编码器

作品简介 在CTFer选手比赛做crypto的题目时&#xff0c;一些题目需要自己去解密&#xff0c;但是解密的工具大部分在线上&#xff0c;而在比赛过程中大部分又是无网环境&#xff0c;所以根据要求做了这个工具 技术架构 python语言的tk库来完成的GUI页面设计&#xff0c;通过…

《机器学习》集成学习之随机森林

目录 一、集成学习 1、简介 2、集成学习的代表 3、XGBoost和随机森林的对比 相同点&#xff1a; 不同点&#xff1a; 二、Bagging之随机森林 1、简介 2、随机森林的核心思想 3、随机森林生成步骤 4、随机森林的优点 5、随机森林的缺点 三、随机森林的代码实现 1、…

四、VSCODE 使用GIT插件

VSCODE 使用GIT插件 一下载git插件与git Graph插件二、git插件使用三、文件提交到远程仓库四、git Graph插件 一下载git插件与git Graph插件 二、git插件使用 git插件一般VSCode自带了git&#xff0c;就是左边栏目的图标 在下载git软件后vscode的git插件会自动识别当前项目 …

JS进阶--JS听到了不灭的回响

作用域 作用域&#xff08;scope&#xff09;规定了变量能够被访问的“范围”&#xff0c;离开了这个“范围”变量便不能被访问 作用域分为局部和全局 局部作用域 局部作用域分为函数和块 那 什么是块作用域呢&#xff1f; 在 JavaScript 中使用 { } 包裹的代码称为代码块…

《自动驾驶与机器人中的SLAM技术》ch1:自动驾驶

目录 1.1 自动驾驶技术 1.2 自动驾驶中的定位与地图 1.1 自动驾驶技术 1.2 自动驾驶中的定位与地图 L2 在技术实现上会更倾向于实时感知&#xff0c;乃至可以使用感知结果直接构建鸟瞰图&#xff08;bird eye view, BEV&#xff09;&#xff0c;而 L4 则依赖离线地图。 高精地…

【合作原创】使用Termux搭建可以使用的生产力环境(九)

前言 在上一篇【合作原创】使用Termux搭建可以使用的生产力环境&#xff08;八&#xff09;-CSDN博客中我们讲到了如何安装IDEA社区版&#xff0c;并在Termux中安装VNC服务器&#xff0c;在proot-distro的Debian中启动xfce桌面&#xff0c;并通过这个方式解决了IDEA社区版中无…

生成模型:变分自编码器-VAE

1.基本概念 1.1 概率 这里有&#xff1a; x为真实图像&#xff0c;开源为数据集, 编码器将其编码为分布参数 x ^ \hat{x} x^为生成图像, 通过解码器获得 p ( x ) ^ \hat{p(x)} p(x)^​: 观测数据的分布, 即数据集所构成的经验分布 p r e a l ( x ) p_{real}(x) preal​(x): …

中国省级产业结构高级化及合理化数据测算(2000-2023年)

一、数据介绍 数据名称&#xff1a;中国省级产业结构高级化、泰尔指数 数据年份&#xff1a;2000-2023年 数据范围&#xff1a;31个省份 数据来源&#xff1a;中国统计年鉴、国家统计局 数据整理&#xff1a;内含原始版本、线性插值版本、ARIMA填补版本 数据说明&#xf…

高级数据库系统 复习提纲

第一章 数据库技术的回顾与发展 简述三代数据库的发展历史及其对应特点&#xff1a; 新型数据库在“数据模型”上的创新&#xff1a; 简述数据库和什么相关技术结合&#xff0c;产生了什么新型数据库&#xff1f; 1. 数据库和并行处理技术结合&#xff0c;产生“并行数据库”…