springboot 集成 etcd

news2025/1/8 11:13:52

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地址

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云安全相关博客阅读(一)

2024-03-04 Cloudflare announces Firewall for AI 关注问题&#xff1a; 传统的WAF功能能够保护web和api安全&#xff0c;但是随着LLM等AI模型等出现&#xff0c;保护这些AI相关应用等安全是一个新出现的问题虽然AI应用是新的场景&#xff0c;但是以往的攻击方法也能够直接用…

2025年01月07日Github流行趋势

项目名称&#xff1a;khoj 项目地址url&#xff1a;https://github.com/khoj-ai/khoj项目语言&#xff1a;Python历史star数&#xff1a;20105今日star数&#xff1a;363项目维护者&#xff1a;debanjum, sabaimran, MythicalCow, aam-at, shantanuSakpal项目简介&#xff1a;你…

从零手写线性回归模型:PyTorch 实现深度学习入门教程

系列文章目录 01-PyTorch新手必看&#xff1a;张量是什么&#xff1f;5 分钟教你快速创建张量&#xff01; 02-张量运算真简单&#xff01;PyTorch 数值计算操作完全指南 03-Numpy 还是 PyTorch&#xff1f;张量与 Numpy 的神奇转换技巧 04-揭秘数据处理神器&#xff1a;PyTor…

【python】matplotlib(radar chart)

文章目录 1、功能描述和原理介绍2、代码实现3、效果展示4、完整代码5、多个雷达图绘制在一张图上6、参考 1、功能描述和原理介绍 基于 matplotlib 实现雷达图的绘制 一、雷达图的基本概念 雷达图&#xff08;Radar Chart&#xff09;&#xff0c;也被称为蛛网图或星型图&…

数据库环境安装(day1)

网址&#xff1a;MySQL 下载&#xff08;环境准备&#xff09;&#xff1a; &#xff08;2-5点击此处&#xff0c;然后选择合适的版本&#xff09; 1.linux在线YUM仓库 下载/安装: wget https://repo.mysql.com//mysql84-community-release-el9-1.noarch.rpm rpm -i https://r…

Fabric链码部署测试

参考链接&#xff1a;运行 Fabric 应用程序 — Hyperledger Fabric Docs 主文档 (hyperledger-fabric.readthedocs.io) &#xff08;2&#xff09;fabric2.4.3部署运行自己的链码 - 知乎 (zhihu.com) Fabric2.0测试网络部署链码 - 辉哥哥~ - 博客园 (cnblogs.com) 1.启动测试…

数据结构与算法之二叉树: LeetCode 107. 二叉树的层序遍历 II (Ts版)

二叉树的层序遍历 II https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/description/ 描述 给你二叉树的根节点 root &#xff0c;返回其节点值 自底向上的层序遍历 。 &#xff08;即按从叶子节点所在层到根节点所在的层&#xff0c;逐层从左向右遍历&a…

Python插件化开发实战:开发个图片浏览器

在本篇教程中&#xff0c;我将详细介绍如何使用Python开发一个基于插件架构的图片浏览器。这个项目将展示如何实现插件系统、如何处理图片显示,以及如何使用wxPython构建GUI界面。 “C:\pythoncode\pythonplugin\your_project\main_app.py” 项目概述 我们将开发一个具有以下…

根据python代码自动生成类图的实现方法[附带python源码]

概述 利用python库抽象语法树(AST)和类图描述语言(PlantUML),实现自动将python代码生成类图的目的。 环境 windowsvscodepythonplantuml ✒️网上好像大部分都是用Pyreverse库来实现的&#xff0c;但是我实际测试发现只能在一个文件中才能行&#xff0c;当然应该有解决方法…

下载b站高清视频

需要使用的edge上的一个扩展插件&#xff0c;所以选择使用edge浏览器。 1、在edge浏览器上下载 强力视频下载合并 扩展插件 2、在edge上打开b站&#xff0c;登录自己账号&#xff08;登录后才能下载到高清&#xff01;&#xff01;&#xff09;。打开一个视频&#xff0c;选择自…

flutter 专题二十四 Flutter性能优化在携程酒店的实践

Flutter性能优化在携程酒店的实践 一 、前言 携程酒店业务使用Flutter技术开发的时间快接近两年&#xff0c;这期间有列表页、详情页、相册页等页面使用了Flutter技术栈进行了跨平台整合&#xff0c;大大提高了研发效率。在开发过程中&#xff0c;也遇到了一些性能相关问题和…

UE5 打包要点

------------------------- 1、需要环境 win sdk &#xff0c;大约3G VS&#xff0c;大约10G 不安装就无法打包&#xff0c;就是这么简单。 ----------------------- 2、打包设置 编译类型&#xff0c;开发、调试、发行 项目设置-地图和模式&#xff0c;默认地图 项目…

vulnhub靶场【DC系列】之5

前言 靶机&#xff1a;DC-5&#xff0c;IP地址为192.168.10.4 攻击&#xff1a;kali&#xff0c;IP地址为192.168.10.2 都采用VMWare&#xff0c;网卡为桥接模式 对于文章中涉及到的靶场以及工具&#xff0c;我放置网盘中https://pan.quark.cn/s/2fcf53ade985 主机发现 使用…

双模态视觉特征流用于医学报告生成|文献速递-视觉大模型医疗图像应用

Title 题目 Dual-modality visual feature flow for medical report generation 双模态视觉特征流用于医学报告生成 01 文献速递介绍 医学报告生成是一项新兴的跨模态文本生成任务&#xff08;X. Zeng et al., 2020&#xff1b;Najdenkoska et al., 2022&#xff1b;Li et…

基于Fluent和深度学习算法驱动的流体力学计算与应用

物理模型与深度学习的融合&#xff1a;研究如何将传统的物理模型与深度学习算法相结合&#xff0c;以提高流体力学问题的预测准确性和计算效率。复杂流动模拟&#xff1a;利用深度学习技术对复杂流动现象进行模拟和分析&#xff0c;包括湍流、多相流、非牛顿流体等&#xff0c;…

记PasteSpider部署工具的Windows.IIS版本开发过程之草稿-动态表单(2)

接1的内容&#xff0c;那么有这么一个需求&#xff01; 需求分析 需要修改某一个配置的时候 1.从对应的api中读取消息&#xff0c;消息内容为Json格式的 2.基于当前的Json渲染成表单提供给管理端的客户呈现 3.管理端的用户可以基于这个表单的内容进行修改&#xff0c;然后提交…

pycharm-pyspark 环境安装

1、环境准备&#xff1a;java、scala、pyspark、python-anaconda、pycharm vi ~/.bash_profile export SCALA_HOME/Users/xunyongsun/Documents/scala-2.13.0 export PATH P A T H : PATH: PATH:SCALA_HOME/bin export SPARK_HOME/Users/xunyongsun/Documents/spark-3.5.4-bin…

Clisoft SOS设置Workarea

Clisoft SOS设置Workarea 本人也是刚刚接触这个软件&#xff0c;可能有些方面不够完善&#xff0c;欢迎大佬指点。 这里就不演示创建创建Server和Project&#xff0c;可以参考Clisoft SOS设置Server和Project 创建Workarea 创建好目录并设置好权限 # 创建组 [bhlumaster ~]$…

数据结构:LinkedList与链表—无头双向链表(二)

目录 一、什么是LinkedList&#xff1f; 二、LinkedList的模拟实现 1、display()方法 2、addFirst(int data)方法 3、addLast(int data)方法 4、addIndex(int index,int data)方法 5、contains(int key)方法 6、remove(int key)方法 7、removeAllKey(int key)方法 8、…

基于SpringBoot实现的保障性住房管理系统

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;欢迎留言讨论 &#x1f525;&#x1f525;&…