Etcd学习笔记

server/2025/3/13 14:14:26/

etcd的介绍与安装

  • 主要用于微服务的配置中心和服务发现,数据可靠性比redis更强

在对外api的应用中,如何知道order服务的rpc地址?

如果服务的ip地址变化了怎么办?在传统的配置文件模式,修改配置文件,应用程序是需要重启才能解决的,所以引入etcd

  • windows安装

    • etcd-v3.5.16-windows-amd64.zip

  • docker安装

    docker run --name etcd -d -p 2379:2379 -p 2380:2380 -e ALLOW_NONE_AUTHENTICATION=yes bitnami/etcd:3.3.11 etcd

安装完成后在下载路径启用cmd(因为未加环境变量)


  • etcd 链接:百度网盘 请输入提取码 提取码:7777 etcdkeeper 链接:百度网盘 请输入提取码 提取码:7777

  • etcd文档

  • etcd不同系统安装


基本命令

// 设置或更新值
etcdctl put name 张三
// 获取值
etcdctl get name
// 只要value
etcdctl get name --print-value-only
// 获取name前缀的键值对
etcdctl get name --prefix
// 删除键值对
etcdctl del name
// 监听键的变化
etcdctl watch name
// 例如
etcdctl put rpc.order 127.0.0.1:7001
etcdctl put rpc.user 127.0.0.1:7002
etcdctl get rpc --prefix
// ------------
etcdctl watch rpc.user 
// 另起一个cmd
etcdctl put rpc.user 127.0.0.1:7003

Go 操作 etcd

驱动包安装

不能直接 go get go.etcd.io/etcd/clientv3(官方提供驱动包)不然会报错的;因为 gRPC 版本过新的缘故;

这里我们需要指定 gRPC 的版本信息;

# 指定 gRPC 版本为 v1.26.0
go mod edit --require=google.golang.org/grpc@v1.26.0
# 下载安装 gRPC 驱动包
go get -u -x google.golang.org/grpc@v1.26.0
# 下载安装 etcd 驱动包
go get go.etcd.io/etcd/clientv3
go mod tidy

启动 etcd

  • 方式一:(etcd 的端口号只能在本地连)

    start /B etcd > start.log 2>&1  
    // /B表示在后台运行程序 >将输出重定向到文件 将标准错误重定向到标准输出
    netstat -an | findstr :2379 
    // 来验证端口是否被监听
    // 用于 Linux 或类 Unix 系统:etcd --listen-client-transport-port 2379
    nohup ./etcd > ./start.log 2>&1 &
    // 查看端口对外开放情况(etcd 默认端口为 2379)
    lsof -i:2379
  • 方式二:(如果 etcd 所在机器是公司内部机器,需要把安全组对应端口号放开,即需要放开 2379)

    start /B etcd.exe --listen-client-urls 'http://0.0.0.0:2379' --advertise-client-urls 'http://0.0.0.0:2379' > start.log 2>&1// 查看端口对外开放情况(etcd 默认端口为 2379)
    netstat -ano | findstr :2379
    nohup ./etcd --listen-client-urls 'http://0.0.0.0:2379' --advertise-client-urls 'http://0.0.0.0:2379' > ./start.log 2>&1 &
    ​
    // 查看端口对外开放情况(etcd 默认端口为 2379)
    lsof -i:2379

关闭etcd

// windows
tasklist | findstr etcd
taskkill /F /IM etcd.exe

putget 使用

package mainimport ("context""fmt""time""github.com/coreos/etcd/clientv3"
)func main() {// 创建连接cli, err := clientv3.New(clientv3.Config{ // 创建etcd客户端实例// Endpoints 是一个切片,可同时连接多个服务器Endpoints:   []string{"127.0.0.1:2379"},DialTimeout: 5 * time.Second, // 连接超时时间})if err != nil {panic(err)}// 程序执行结束前释放连接资源defer cli.Close()// 这里创建了一个带有超时的上下文ctx,用于控制Put操作的超时ctx, cancel := context.WithTimeout(context.Background(), time.Second)// 向etcd中写入数据,如果操作成功,cancel函数会被调用,取消上下文的超时控制_, err = cli.Put(ctx, "key", "mark")cancel()if err != nil { // 操作失败,服务终止panic(err)}// Get操作,有超时ctx, cancel = context.WithTimeout(context.Background(), time.Second)/*此处的 get 等同于在终端执行 ./etcdctl get key -w json输出结果:{"header":{"cluster_id":14841639068965178418,"member_id":10276657743932975437,"revision":17,"raft_term":7},"kvs":[{"key":"a2V5","create_revision":2,"mod_revision":15,"version":8,"value":"dmFsMjAyMw=="}],"count":1}*/resp, err := cli.Get(ctx, "key")cancel()if err != nil {panic(err)}for _, ev := range resp.Kvs { // 遍历etcd返回的结果fmt.Printf("%s:%s\n", ev.Key, ev.Value)}
}

watch 使用

package mainimport ("context""fmt""github.com/coreos/etcd/clientv3"
)func main() {// 创建etcd客户端实例cli, err := clientv3.NewFromURL("127.0.0.1:2379")if err != nil {panic(err)}defer cli.Close()// 监听key 的操作//watch := cli.Watch(context.Background(), "key")// 创建了一个监听器来监听名为"key"的键或大于"key"的所有键的变化// clientv3.WithFromKey()选项表示监听的范围从"key"开始watch := cli.Watch(context.Background(), "key", clientv3.WithFromKey())for resp := range watch { // 循环监听for _, ev := range resp.Events { // 循环事件// 打印事件类型、键、值fmt.Printf("Type: %s Key: %s Value: %s\n", ev.Type, ev.Kv.Key, ev.Kv.Value)}}
}

执行上述代码后会阻塞等待其它用户操作 etcd,如下所示:

1)在终端执行 etcd 操作

img

2)在 go 客户端查看监听情况

img

lease 使用

package mainimport ("context""fmt""github.com/coreos/etcd/clientv3"
)func main() {// 创建连接cli, err := clientv3.NewFromURL("127.0.0.1:2379")if err != nil {panic(err)}defer cli.Close() // 关闭连接// 创建租约lease, err := cli.Grant(context.Background(), 5) // 5秒的租约if err != nil {panic(err)}fmt.Println("lease id", lease.ID) // 打印租约ID// 把 key-val 绑定到租约_, err = cli.Put(context.Background(), "key", "mark", clientv3.WithLease(lease.ID))if err != nil {panic(err)}// 续租:长期续租、短期续租, 续约到期删除键值对// 长期续租:不停的续租if true {ch, err := cli.KeepAlive(context.Background(), lease.ID)if err != nil {panic(err)}for {recv := <-ch                          // 接收续租结果fmt.Println("time to live", recv.TTL) // 打印剩余租期}}// 短期续租:只续租一次if false {res, err := cli.KeepAliveOnce(context.Background(), lease.ID)if err != nil {panic(err)}fmt.Println("time to live", res.TTL) // 打印剩余租期}
}

lock 使用

package mainimport ("context""fmt""github.com/coreos/etcd/clientv3""github.com/coreos/etcd/clientv3/concurrency"
)func main() {// 创建连接cli, err := clientv3.New(clientv3.Config{Endpoints: []string{"127.0.0.1:2379"},})if err != nil {panic(err)}defer cli.Close()// 创建了第一个会话 s1,并设置了一个 TTL为 10 秒s1, err := concurrency.NewSession(cli, concurrency.WithContext(context.Background()), concurrency.WithTTL(10))if err != nil {panic(err)}defer s1.Close()// 使用会话 s1 创建了一个名为 "lock" 的互斥锁m1 := concurrency.NewMutex(s1, "lock")// 创建了第二个会话 s2,没有设置 TTL,将一直保持活跃,直到显式关闭s2, err := concurrency.NewSession(cli, concurrency.WithContext(context.Background()))if err != nil {panic(err)}defer s2.Close()// 为 session2 创建锁m2 := concurrency.NewMutex(s2, "lock")// 对 session1 加锁if err := m1.Lock(context.Background()); err != nil {panic(err)}fmt.Println("s1 acquired lock")// 创建管道m2ch := make(chan struct{})// 开启协程,对 session2 加锁,但由于已经被 session1 锁住,所以 session2 的加锁操作,阻塞等待go func() {defer close(m2ch)if err := m2.Lock(context.Background()); err != nil {panic(err)}}()// session1 释放锁if err := m1.Unlock(context.Background()); err != nil {panic(err)}fmt.Println("s1 released lock")// 通知 session2 session1 已经释放锁,此时 session2 可执行加锁操作<-m2chfmt.Println("s2 acquired lock")
}

etcd 存储原理及读写机制

etcd 为每个 key 创建一个索引;一个索引对应着一个 B+ 树;B+ 树 key 为 revision,B+ 树节点存储的值为 value;B+ 树存储着 key 的版本信息从而实现了 etcdmvccetcd 不会任由版本信息膨胀,通过定期的 compaction 来清理历史数据;

etcd 为了加速索引数据,在内存中维持着一个 B 树;B 树 key 为 key-val 中的 key,value 为该 key 的 revision;示意图如下:

img

etcd不同命令执行流程:

  • etcd get 命令执行流程:etcd 在执行 get 获取数据时,先从内存中的 B 树中寻找,如果找不到,再从 B+ 树中寻找,从 B+ 树中找到数据后,将其缓存到 B 树并输出到客户端;

  • etcd put 命令执行流程:etcd 在执行 put 插入或修改数据时,先从内存中的 B 树中寻找,如果找到了,则对其进行修改并将其写入到 B+ 树;

问题:mysqlmvcc 是通过什么实现的?

答:undolog

问题:mysql B+ 树存储什么内容?

答:具体分为聚簇索引和二级索引;

问题:mysql 为了加快索引数据,采用什么数据结构?

答:MySQL采用自适应 hash 来加速索引;

扩展:B-树和 B+ 树区别?

  • B-树和 B+ 树都是多路平衡搜索树;采用中序遍历的方式会得到一个有序的结构;都是通过 key 的方式来维持树的有序性;

  • B-树一个节点中 n 个元素对应着 n+1 个指针;而 B+ 树一个节点中 n 个元素对应着 n 个指针;

  • B-树每个节点都存储节点信息,B+ 树只有叶子节点存储节点信息,非叶子节点只存储索引信息;

  • B+ 树叶子节点之间通过双向链表连接,对于范围查询速度更快,这样减少了磁盘 io

读写机制


etcd 是串行写(避免不必要的加锁),并发读;

并发读写时(读写同时进行),读操作是通过 B+ 树 mmap 访问磁盘数据;写操作走日志复制流程;可以得知如果此时读操作走 B 树出现脏读幻读问题;通过 B+ 树访问磁盘数据其实访问的事务开始前的数据,由 mysql 可重复读隔离级别下MVCC 读取规则可智能避免脏读和幻读问题;

并发读时,可走内存 B 树;

注:由于 etcd 写的时候是先写到内存中的 B 树,然后再写到磁盘上的 B+ 树,因此并发读写时需要读 B+ 树数据,否则容易出现脏读幻读问题;

关闭etcd监听

# 使用 tasklist 命令来查找 etcd 相关的进程
tasklist | findstr etcd
# 使用 taskkill 命令结束 /F 表示强制结束进程,/IM 后面跟上进程的名称
taskkill /F /IM etcd.exe
# 通过服务的方式来启动 etcd (如:etcd.exe --service)
net stop etcd
# 使用 netstat 命令检查端口是否还在监听
netstat -an | findstr :2379

http://www.ppmy.cn/server/174639.html

相关文章

优化 NFS 挂载参数以提升可靠性与容错性

在现代 IT 基础设施中&#xff0c;NFS&#xff08;网络文件系统&#xff09;被广泛用于共享文件和存储。虽然 NFS 提供了便利&#xff0c;但在某些情况下&#xff0c;挂载失败或网络问题可能导致挂载操作不稳定。为了提高挂载的可靠性和容错性&#xff0c;我们可以通过优化 NFS…

Benewake(北醒) 快速实现TF-NOVA IIC接口与电脑通信的操作说明

目录 1. 概述2. 测试准备2.1 工具准备 3. IIC通讯测试3.1 引脚说明3.2 测试步骤3.2.1 TF-NOVA 与 PC 建立连接3.2.2 获取测距值 更新记录 1. 概述 通过本文档的概述&#xff0c;能够让初次使用测试者快速了解测试 IIC 通信协议需要的工具以及查看哪些对应的 IIC 协议说明书&am…

基于腾讯云高性能HAI-CPU的跨境电商客服助手全链路解析

跨境电商的背景以及痛点 根据Statista数据&#xff0c;2025年全球跨境电商市场规模预计达6.57万亿美元&#xff0c;年增长率保持在12.5% 。随着平台规则趋严&#xff08;如亚马逊封店潮&#xff09;&#xff0c;更多卖家选择自建独立站&#xff0c;2024年独立站占比已达35%。A…

[C语言]内存函数的使用和模拟实现

一、memcpy函数的使用与实现 前面我们学习了字符串函数&#xff0c;里面的strcpy函数和strncpy函数是实现拷贝字符串的功能&#xff0c;不同的是前者是将整个字符串拷贝&#xff0c;后者是可以指定拷贝的字符个数。但是我们的数据类型有多种&#xff0c;那么当我们需要拷贝的对…

STL —— 核心组成部分和特性概述

C 标准模板库&#xff08;Standard Template Library, STL&#xff09;是 C 标准库的核心组成部分&#xff0c;提供了一系列通用、高效的模板化数据结构和算法。它的设计基于泛型编程思想&#xff0c;通过高度解耦的组件实现了代码复用和灵活性。以下是 STL 的核心组成部分和特…

《鸿蒙系统下AI模型训练加速:时间成本的深度剖析与优化策略》

在当今数字化浪潮中&#xff0c;鸿蒙系统凭借其独特的分布式架构与强大的生态潜力&#xff0c;为人工智能的发展注入了新的活力。随着AI应用在鸿蒙系统上的日益普及&#xff0c;如何有效降低模型训练的时间成本&#xff0c;成为了开发者与研究者们亟待攻克的关键课题。这不仅关…

洗鞋小程序(源码+文档+讲解+演示)

引言 随着生活水平的提高&#xff0c;人们对洗鞋服务的需求日益增长。洗鞋小程序作为一个智能化平台&#xff0c;为用户提供了便捷、高效的洗鞋服务。本文将详细介绍该小程序的功能、技术架构以及其在提升用户体验中的优势。 系统概述 洗鞋小程序采用前后端分离的架构设计&a…

Zookeeper相关面试题

以下是150道Zookeeper相关面试题&#xff1a; Zookeeper基础概念 1. Zookeeper是什么&#xff1f; Zookeeper是一个开源的分布式协调服务&#xff0c;用于管理分布式系统中的配置、命名、分布式锁等功能。 2. Zookeeper的主要功能有哪些&#xff1f; • 配置管理 • 分布式…