etcd入门指南:分布式事务、分布式锁及核心API详解

etcd 是一个高可用、分布式的键值存储系统。主要用作分布式系统中的独立协调服务。旨在保存可完全放入内存中的少量数据。

Raft

etcd 基于 Raft 共识算法,保证了分布式环境下的数据一致性。
Raft是一种分布式一致性算法,用于在多个节点之间达成共识,确保分布式系统中的数据在不同节点间一致。

  • Leader Election(领导者选举)

在Raft 中,系统的节点分为三种状态:领导者(Leader)、跟随者(Follower)和候选者(Candidate)。其中,Leader 负责处理客户端请求并将日志条目复制到 Follower 节点。在集群启动时或当前 Leader 失效时,节点之间会进行一次选举,选举出一个新的 Leader。

etcd中的Learner(学习者)是只读成员,它不会参与投票或决策,但可以同步数据,适用于增量扩展或数据迁移过程中。当learner日志赶上leader日志时,可以通过member promote API提升为正式成员,Learner节点拒绝客户端读取和写入。

  • Log Replication(日志复制)

Leader Election完成后,所有客户端请求都会通过 Leader 处理,Leader 会将客户端请求以日志条目的形式记录下来,并将其复制到其他 Follower 节点。Follower 节点会接收并应用这些日志条目,确保每个节点的数据状态一致。

  • Safety

通过任期、投票、日志条目的提交机制,Raft 保证了系统的一致性,即使部分节点出现故障,也能通过 Leader 和日志复制机制维持系统的整体一致性。

etcd API

etcd proto结构定义

etcd client v3使用gRPC进行远程过程调用,定义了交互过程中protobuf数据结构

ResponseHeader(响应头)

message ResponseHeader {uint64 cluster_id = 1; //集群IDuint64 member_id = 2; //成员IDint64 revision = 3; // etcd 键值存储的版本uint64 raft_term = 4; //etcd集群Raft协议的任期号
}

KeyValue(键值对)

message KeyValue {bytes key = 1; //可以不能为空int64 create_revision = 2; //最后一次创建时的版本int64 mod_revision = 3; //最后一次修改时的版本int64 version = 4; //可以的版本,删除key,版本会重置为0,任何修改都会增加版本bytes value = 5; //int64 lease = 6; //租约,如果没有租约lease=0
}

Range(返回查询)

message RangeRequest {enum SortOrder {NONE = 0; // default, no sortingASCEND = 1; // lowest target value firstDESCEND = 2; // highest target value first}enum SortTarget {KEY = 0;VERSION = 1;CREATE = 2;MOD = 3;VALUE = 4;}bytes key = 1; //请求起始keybytes range_end = 2; //请求结束key 和key组成范围int64 limit = 3;  //限制返回的key数量int64 revision = 4; //期望的revisionSortOrder sort_order = 5; //指定返回结果排序SortTarget sort_target = 6; //指定排序目标字段bool serializable = 7; //设置为 true,则请求线性化的一致性读取,即在读取之前,所有之前的写入都已经被持久化。serizlized可有由任何节点读取,因为数据已经序列化。相反线性一致性读取(Linearized Read)只能从领导者读取bool keys_only = 8; //设置为 true,则只返回键,不返回值bool count_only = 9; //设置为 true,则只返回匹配范围内的键值对数量,不返回键或值int64 min_mod_revision = 10; //指定返回的键值对的最小修改修订号。只有修改修订号大于或等于这个值的键值对会被返回。int64 max_mod_revision = 11;  //定返回的键值对的最大修改修订号。只有修改修订号小于或等于这个值的键值对会被返回。int64 min_create_revision = 12; //指定返回的键值对的最小创建修订号。只有创建修订号大于或等于这个值的键值对会被返回int64 max_create_revision = 13; //指定返回的键值对的最大创建修订号。只有创建修订号小于或等于这个值的键值对会被返回。
}message RangeResponse {ResponseHeader header = 1;repeated mvccpb.KeyValue kvs = 2; //与范围请求匹配的键值对列表,如果设置了Count_only,kvs为空bool more = 3; //如果设置了limit 用于判断是否有更多的键int64 count = 4; //满足range request的key数量
}

Put(设置操作)

message PutRequest {bytes key = 1; bytes value = 2;int64 lease = 3;bool prev_kv = 4; //如果设置为true,则返回存储操作之前的键值对bool ignore_value = 5; //如果设置为true,会更新key,忽略value。如果key不存在返回errorbool ignore_lease = 6; //如果设置为true,会更新key,忽略lease(不会更新租约)。如果key不存在返回error
}message PutResponse {ResponseHeader header = 1;mvccpb.KeyValue prev_kv = 2; //prev_kv设置为true时,返回更新前的key-value
}

Delete Range(删除操作)

message DeleteRangeRequest {bytes key = 1;bytes range_end = 2;bool prev_kv = 3; //设置true时,返回删除的key-value
}message DeleteRangeResponse {ResponseHeader header = 1;int64 deleted = 2; //删除的key数量repeated mvccpb.KeyValue prev_kvs = 3; //删除的键值对列表
}

v3 API

Cluster

  • MemberList 列出当前集群成员
  • MemberAdd 将新成员添加到集群中
  • MemberAddAsLearner 添加一个新的learner到集群中
  • MemberRemove 移除成员
  • MemberUpdate 更新成员配置信息
  • MemberPromote 将一个 “学习者” 节点提升为正式的 etcd 集群成员

KV

  • Put 设置键值对
  • Get 默认从 etcd 存储中获取一个键的值,如果有传key范围,可以取key范围的值
  • Delete 删除一个key或一个范围的key
  • Compact 压缩 etcd 存储的历史版本,以减少存储空间
  • Do 通用操作接口,便于扩展和组合操作
  • Txn 创建一个事务

Lease

  • Grant 创建一个新的租约 ,返回LeaseGrantResponse
  • Revoke 撤销租约
  • TimeToLive 给定一个LeaseID,查询某个Lease的剩余有效时间及相关信息
  • Leases 列出所有租约信息
  • KeepAlive 通过定期心跳,保持租约的有效性
  • KeepAliveOnce 仅续租一次
  • Close 关闭租约相关的连接和资源

Watcher

  • Watch 监听某个键或键范围的变化
  • RequestProgress 用于请求 Watcher 发送当前进度通知。这个方法允许客户端检查 Watcher 进度是否已经追踪到最新的变化。
  • Close 关闭 Watcher,并释放其资源。

Auth

  • Authenticate 对用户进行认证,检查提供的用户名和密码是否有效
  • AuthEnable 启用认证机制
  • AuthDisable 禁用认证
  • AuthStatus 获取集群认证机制状态
  • UserAdd 添加一个新用户
  • UserAddWithOptions 添加一个新用户,并提供一些额外的选项,如用户角色等。
  • UserDelete 删除用户
  • UserChangePassword 修改密码
  • UserGrantRole 给 etcd 集群中的用户授予一个角色
  • UserGet 获取用户信息
  • UserList 获取用户列表
  • UserRevokeRole 撤销 etcd 集群中用户的角色
  • RoleAdd 添加角色
  • RoleGrantPermission 给角色授权
  • RoleGet 获取角色
  • RoleList 获取角色列表
  • RoleRevokePermission 撤销角色权限
  • RoleDelete 删除角色

Maintenance

  • AlarmList 列出集群所有的告警
  • AlarmDisarm 解除某个节点的告警
  • Defragment 对 etcd 节点的存储文件进行碎片整理
  • Status 返回特定 etcd 节点的状态信息
  • HashKV 计算 etcd 集群中键值存储的历史哈希值,这个命令可以用于检查集群成员之间数据的一致性。
  • Snapshot 创建 etcd 集群的快照
  • MoveLeader 将 etcd 集群的 leader 角色转移到指定的成员

事务(Transaction)

proto 结构

message RequestOp {// request is a union of request types accepted by a transaction.oneof request {RangeRequest request_range = 1;PutRequest request_put = 2;DeleteRangeRequest request_delete_range = 3;}
}message TxnRequest {repeated Compare compare = 1;repeated RequestOp success = 2;repeated RequestOp failure = 3;
}message TxnResponse {ResponseHeader header = 1;bool succeeded = 2;  // 如果compare结果是true 返回true,否则返回false repeated ResponseOp responses = 3; //  包含事物中每个操作的响应结果。如果Succeeded=true,那么包含Then所有操作的响应。否则包含Else所有操作的响应
}message ResponseOp {oneof response {RangeResponse response_range = 1;PutResponse response_put = 2;DeleteRangeResponse response_delete_range = 3;}
}

etcd client v3 事务接口

type Txn interface {//如果所有比较成功,执行Then方法,否则执行Else方法。用于检查 etcd 键值存储中的特定条件是否满足。If(cs ...Cmp) Txn// 比较成功时执行Then(ops ...Op) Txn// 失败是执行Else(ops ...Op) Txn//提交事物Commit() (*TxnResponse, error)
}

代码示例

func main() {cli, err := clientv3.New(clientv3.Config{Endpoints:   []string{"127.0.0.1:2379"},DialTimeout: 3 * time.Second,})error.FailOnError(err, "Failed to connect to etcd")defer cli.Close()// 构建事务txn := cli.Txn(context.Background()).If(clientv3.Compare(clientv3.Value("/txn/accountA"), "=", "100")).Then(clientv3.OpPut("/txn/accountA", "90"), clientv3.OpPut("/txn/accountB", "110")).Else(clientv3.OpGet("/txn/accountA"))// 提交事务txnResp, err := txn.Commit()error.FailOnError(err, "Txn Commit failed")// 打印事务结果if txnResp.Succeeded {fmt.Printf("Txn succeeded : %v", txnResp.Responses)} else {getResp := txnResp.Responses[0].GetResponseRange()if len(getResp.Kvs) > 0 {fmt.Printf("Txn failed : %v", string(getResp.Kvs[0].Value))}}}

Mutex 分布式锁

etcd client v3版本内置了分布式锁的实现。

内置方法

  • TryLock 尝试获取锁,如果获取失败,立即返回
  • Lock 阻塞调用,直到获得锁或取消
  • Unlock 释放锁
  • IsOwner 检查当前会话是否是锁的持有者
  • Key 返回锁的key
  • Header 返回最近一次成功获取锁的响应头信息

使用示例

func main() {cli, err := clientv3.New(clientv3.Config{Endpoints:   []string{"127.0.0.1:2379"},DialTimeout: 3 * time.Second,})errorHandle.FailOnError(err, "Failed to connect to etcd")defer cli.Close()//创建会话s, err := concurrency.NewSession(cli)failOnError(err, "Failed to create session")//执行结束,撤销lease,释放锁defer s.Close()m := concurrency.NewMutex(s, "/mutex/lock")ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)defer cancel()if err := m.Lock(ctx); err != nil {log.Fatal(err)}fmt.Printf("锁获取成功,当前锁的key,%v \n", m.Key())if err := m.Unlock(ctx); err != nil {log.Fatal(err)}fmt.Println("释放锁")}

实现原理

etcd的分布式锁主要利用了Revision机制、租约(Lease)机制及事务(txn)、Watch机制等特性。

etcd mutex基于给定的锁前缀加上每个会话的leaseId创建kv,最先创建的kv所在的会话为锁的获得者。其他没有获得锁的会话通过Watch机制监听锁的key的删除事件,来尝试获取锁。

部分源码

func (m *Mutex) tryAcquire(ctx context.Context) (*v3.TxnResponse, error) {s := m.sclient := m.s.Client()m.myKey = fmt.Sprintf("%s%x", m.pfx, s.Lease())//如果key revision 为 0,当前会话还没创建keycmp := v3.Compare(v3.CreateRevision(m.myKey), "=", 0)// put self in lock waiters via myKey; oldest waiter holds lockput := v3.OpPut(m.myKey, "", v3.WithLease(s.Lease()))// reuse key in case this session already holds the lockget := v3.OpGet(m.myKey)// fetch current holder to complete uncontended path with only one RPC//取锁前缀下 第一个key的创建信息(根据Revision排序)getOwner := v3.OpGet(m.pfx, v3.WithFirstCreate()...)resp, err := client.Txn(ctx).If(cmp).Then(put, getOwner).Else(get, getOwner).Commit()if err != nil {return nil, err}m.myRev = resp.Header.Revisionif !resp.Succeeded {m.myRev = resp.Responses[0].GetResponseRange().Kvs[0].CreateRevision}//返回锁信息return resp, nil
}

基准测试

官方提供Benchmarking etcd v3

reading one single key

key size in bytesnumber of clientsread QPS90th Percentile Latency (ms)
256127160.4
25664166236.1
2562561662221.7

The performance is nearly the same as the one with empty server handler.

reading one single key after putting

key size in bytesnumber of clientsread QPS90th Percentile Latency (ms)
256122690.5
25664135828.6
2562561326247.5

The performance with empty server handler is not affected by one put. So the performance downgrade should be caused by storage package.

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

硬件工程师笔试面试——存储器件

目录 16、存储器件 16.1 基础 存储器件实物图 16.1.1 概念 16.1.2 常见的存储器件及其特点 16.2 相关问题 16.2.1 不同类型的存储器件在成本和性能上有哪些具体的差异 16.2.2 如何根据应用需求选择合适的存储器件? 16.2.3 存储器件的耐用性和可靠性是如何影响其在不同…

数据结构不再难懂:带你轻松搞定图

数据结构入门学习(全是干货)——图 1 图 1.1 什么是图 图是一种用于表示多对多关系的数学模型。它由一组顶点和一组边构成,用于描述事物之间的复杂关联。 顶点:通常用 V (Vertex) 表示,代表事物或对象。边&#xf…

uniapp+renderJS+google map开发安卓版APP非小程序

背景需求 需要在uniapp中接入google地图,研究了一番,都没有找到合适的,现在说一下教程。 效果图 前期工作 这两点缺一不可,否则你啥也看不到。 1、电脑安装L-O-U梯 用于访问G-OO-G-LE的API或者创建google map key。 2、手机安装L-O-U梯 用于显示google地图。我就是手…

Linux中的进程入门

冯诺依曼体系结构 操作系统(Operator System) 进程控制块(PCB) struct task_struct{//该进程的所有属性//该进程对应的代码和属性地址struct task_struct* next; }; struct task_struct 内核结构体——>创建内核结构体对象(task_struct)…

LinuxC高级作业2

1.整理思维导图 2.做一套笔试题 一: 1.cd .. mkdir dir1 cd dir1 touch file1 2.cp ~/mnt/dir1/ -r * ~/home/dir2/ 3.pwd 4.ls -l 5.ifconfig 6.top 10.find /usr -type f -name "*name*" 11.:wq 13.df -h 14.tar -xzvf tmp.tar.gz 15.sudo c…

登录校验(令牌,过滤器,拦截器使用详解)

文章目录 前言一、会话技术1. Cookie2. Session3. 令牌 二、JWT令牌1. 简介 二、过滤器Filter1. 简介2. 快速入门3. 执行流程4. 使用示例5. 为什么自定义的Filter类不需要使用Component 四、拦截器Interceptor1. 介绍2. 入门程序3. Interceptor详解 前言 该篇详细对SpringBoot…

串口助手的qt实现思路

要求实现如下功能&#xff1a; 获取串口号&#xff1a; foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) {qDebug() << "Port: " << serialPortInfo.portName(); // e.g. "COM1"qDebug() <<…

GeoPandas在地理空间数据分析中的应用

GeoPandas是一个开源的Python库&#xff0c;专门用于处理和分析地理空间数据。它建立在Pandas库的基础上&#xff0c;扩展了Pandas的数据类型&#xff0c;使得用户能够在Python中方便地进行GIS操作。GeoPandas的核心数据结构是GeoDataFrame&#xff0c;它是Pandas的DataFrame的…

射击靶标检测系统源码分享

射击靶标检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

VScode开发GD32移植(标准库通用),保姆级!!!!!!!

VScode开发GD32移植(标准库通用)&#xff0c;保姆级&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 文章目录 VScode开发GD32移植(标准库通用)&#xff0c;保姆级&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#…

哪个牌子的麦克风好用?无线麦克风避坑指南:五大常见问题

随着短视频行业的兴起&#xff0c;和视频拍摄有关的外设也被推到了风口浪尖上&#xff0c;而麦克风作为视频拍摄或者现场直播使用的主要拾音工具&#xff0c;自然成为了大家非常关注的一个摄影外设工具&#xff0c;毕竟一款好的拾音工具能够给视频创作者或者直播博主带来更好的…

基于PHP的CRM管理系统源码/客户关系管理CRM系统源码/php源码/附安装教程

源码简介&#xff1a; 这是一款基于PHP开发的CRM管理系统源码&#xff0c;全称客户关系管理CRM系统源码&#xff0c;它是由php源码开发的&#xff0c;还附带了一整套详细的安装教程哦&#xff01; 功能亮点&#xff1a; 1、公海管理神器&#xff1a;不仅能搞定公海类型&…

OpenCV特征检测(6)对初步检测到的角点位置进行亚像素级别的精炼函数cornerSubPix()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 细化角点的位置。 该函数迭代以找到角点或径向鞍点的亚像素级准确位置&#xff0c;如 93中所述&#xff0c;并如下图所示。 亚像素级准确的角点…

Linux:虚拟文件系统/proc和self进程

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 /proc目录 在Linux操作系统中&#xff0c;目录/proc是一个虚拟文件系统&#xff0c;称为procfc&#xff0c;用于访问内核和系统的实时状态信息。这个文件系统不同于常规…

SpringMVC1~~~

快速入门 spring容器文件 在src下就是applicationContext-mvc.xml&#xff0c;需要在web.xml指定<init-param>&#xff0c;给DispatcherServlet指定要去操作的spring容器文件 在WEB-INF下就是xxx-servlet.xml&#xff0c;不需要在web.xml指定<init-param>,如果我们…

Qt:智能指针QScopedPointer 的使用(以及如何写一个QScopedPointer )

前言 本文讲述QScopedPointer 的使用&#xff0c;以及自己如何写一个QScopedPointer . 正文 QScopedPointer 的常用方法 以下是 QScopedPointer 的一些常用方法及其详细说明&#xff1a; 构造函数&#xff1a; QScopedPointer<T> ptr(new T);用于创建一个 QScopedPoi…

使用 Elasticsearch Reindex API 迁移数据

使用 Elasticsearch Reindex API 迁移数据 在 Elasticsearch 中&#xff0c;随着需求的变化&#xff0c;可能需要对索引进行重建或更新。这通常涉及创建新索引、迁移数据等步骤。本文介绍如何使用 Reindex API 将旧索引中的数据迁移到新索引中 一、步骤概述 创建新索引&#…

R18 NES 之SSB-less SCell operation for inter-band CA

在TR 21.918 Summary of Rel-18 Work Items 中可以看到SSB-less SCell operation for inter-band CA 是Network energy savings for NR 的一部分,其中还包括cell DTX/DRX 等等其他内容。 网络节能是 5G/NR 成功的关键,可以减少对环境的影响(温室气体排放)并节省运营成本。R…

『功能项目』伤害数字UI显示【53】

我们打开上一篇52眩晕图标显示的项目&#xff0c; 本章要做的事情是在Boss受到伤害时显示伤害数字 首先打开Boss01预制体空间在Canvas下创建一个Text文本 设置Text文本 重命名为DamageUI 设置为隐藏 编写脚本&#xff1a;PlayerCtrl.cs 运行项目 本章做了怪物受伤血量的显示UI…

详细分析Java中的ObjectMapper基本知识(附Demo)

目录 1. 基本知识2. 基本操作2.1 转换Java对象为JSON2.2 转换JSON为Java对象 3. 拓展 1. 基本知识 ObjectMapper 是 Jackson 数据处理库中的核心类之一&#xff0c;主要用于将 Java 对象转换为 JSON 和将 JSON 转换为 Java 对象 Jackson 是当前最流行的 JSON 处理库之一&…