ETCD(四)读请求处理过程

客户端通过etcdctl执行get命令


etcdctl get name --endpoints localhost:12379,192.158.00.32:12379

client端

首先是client会解析这条命令,包括其中的get API方法,key值,请求server地址。解析完之后etcdctl会创建一个clientv3库对象,etcd clientv3会采用gRPC负载均衡机制来实现负载均衡策略向其中的一个服务端发送RPC请求。

ETCD负载均衡:默认是使用Round Robin策略。即按照server地址顺序一次次建立长连接,所有请求均匀分配到server连接中。这种算法的优点是简单易实现,能够平均分配请求到每个服务器上,但是它无法考虑服务器的实际负载情况,可能会导致某些服务器的负载过高,而其他服务器的负载过低。

除了Round Robin策略,gRPC还提供了其他负载均衡策略,如Least Connection、Random、Weighted Round Robin等。这些策略可以根据实际情况进行选择,以达到更好的负载均衡效果。在etcd clientv3中,可以通过配置选项来指定使用的负载均衡策略。

server端

服务器收到client发来的Range RPC请求后,会将请求发送到对应的handler函数上实现(根据serverName和RPC method来定位具体的handler执行函数)。在handler中,etcd通过拦截器提供了在执行请求前后的hook能力,保障数据安全。

串行读与线性读

虽然etcd能保证一致性,但是保证强一致性是需要消耗性能的,会牺牲部分吞吐量。因此当出现数据一致性问题时,这时就有串行读与线性读的区别了。数据一致性问题又是由于etcd只有leader节点能处理写请求写数据导致。

(1)当收到写请求时,leader节点先将请求内容持久化到WAL日志中,并且广播给所有follower节点;
(2)如果leader节点有收到一半以上节点的持久化成功消息,那么该请求对应的日志会被标识为已提交;
(3)各个节点的server会异步从raft模块获取已提交的日志条目,应用到状态机(boltdb)。

串行读

直接读取对应server状态机(boltdb)的数据,不会经过Raft协议与集群交互,具有低延迟、高吞吐量的特点,但是可能存在读取结果不一致的情况。

线性读

etcd默认的是线性读,在读取数据时会经过raft协议与集群交互保证数据一致,所以在延迟和吞吐量方面会比串行读有所降低。但是能保证数据的一致性。

线性读保证数据一致性的原理,离不开ReadIndex机制。

ReadIndex机制

ReadIndex机制就是实现线性读功能的重要机制,当server收到一个线性读请求时,
如果自己是leader节点,则会立即返回,如果自己是follower节点的话,则会向server节点发送一个readIndex请求来获取最新的已提交日志索引(committed index);
sever收到readIndex请求,还要向其他follower节点发送心跳来防止脑裂异常场景,一半以上节点确认leader节点身份后,leader才会把committed index返回给follower请求节点;
follower节点收到committed index后会和自己的applied index比较,如果applied index值大于committed index时,才表示自己的状态机数据是最新的,这是才会去通知读请求去状态机读取数据。

ETCD脑裂

ETCD是一个分布式键值存储系统,用于存储集群中的配置信息和元数据。ETCD脑裂是指在一个ETCD集群中,由于网络分区或其他原因,集群中的不同节点之间无法通信,导致集群分裂成两个或多个子集群的情况。这种情况下,每个子集群都认为自己是整个集群的唯一有效部分,可能会导致数据不一致和服务不可用等问题。

例如,如果一个ETCD集群由3个节点组成,其中两个节点之间的网络连接中断,这两个节点将形成一个子集群,而第三个节点将形成另一个子集群。此时,每个子集群都认为自己是整个集群的唯一有效部分,可能会导致数据不一致和服务不可用等问题。

ETCD读取旧数据

MVCC

etcd的多版本并发控制(MVCC)解决了etcd v2不支持历史版本、不支持多key事务问题。

ETCD的数据存储:

ETCD的键值存储以及版本信息涉及到一个B树treeIndex和一个B+树boltdb。

treeIndex的作用是作为辅助内存索引,加速对键的范围查询。treeIndex里面会存储key和对应的版本号。

boltdb里面保存了key的值以及历史版本信息。

读取数据时,先从treeIndex中获取key的版本号,再以版本号作为boltdb的key,从boltdb中得到具体的value的信息。

实际读取数据时,还涉及到一个buffer缓冲区,在读取数据时,并非所有请求都要经过boltdb。在访问boltdb前,ETCD会先从buffer中查找是否有key对应的值。如果有就可以直接返回而不用经过boltdb。ETCD通过buffer可以实现一部分的性能提高和数据一致性问题解决。因为buffer是将数据暂存在内存中,可以减少boltdb处理中对磁盘的读写操作;另外buffer会暂未提交的数据,此时可能boltdb里面没有,但是在buffer里面可以提前拿到。
在这里插入图片描述

### etcd 作为内存型数据库的特点 etcd 是一个分布式的、可靠的键值存储系统,其设计目标是为了配置共享和服务发现。作为一个内存型数据库,etcd 的特点如下: - **高性能取**:由于大部分操作都在内存中完成,因此能够提供非常高的性能[^1]。 - **强一致性模型**:通过 Raft 算法实现了一致性协议,确保所有节点上的数据保持一致[^3]。 - **多版本并发控制 (MVCC)**:每次更新都会创建一个新的版本,并保留旧版本的历史记录,这有助于支持时间旅行查询和其他高级功能。 - **持久化能力**:尽管主要工作是在内存中进行,但是为了防止崩溃后的数据丢失,所有的变更也会被写入磁盘中的 WAL 文件以及定期生成的快照(snapshot)。 ### 使用场景 考虑到上述特性,etcd 主要适用于以下几种使用场景: - **服务发现与注册**:应用程序可以在启动时向 etcd 注册自己,并允许其他应用查找它们的位置和状态信息。 - **分布式锁管理**:利用 etcd 提供的原子 CAS(Compare And Swap)指令来构建跨多个进程或机器间的互斥锁定机制。 - **动态配置管理**:可以将系统的全局设置保存在 etcd 中,当需要调整参数时只需修改一处即可生效于整个集群内。 - **选举领导者**:在一个分布式环境中选出唯一的协调者负责特定的任务分配或其他决策过程。 ### 架构概述 etcd 的整体架构围绕着几个关键组件展开: #### gRPC Server 这是 etcd 对外暴露的主要接口之一,用来接收来自客户端的各种请求并返回响应结果。它还承担着与其他 etcd 成员之间相互通信的角色,从而维持集群内部的一致性和健康状况。 #### MVCC 存储引擎 该模块实现了多版本并发控制逻辑,使得每一个键都可以拥有不同的历史版本。每当有新的写入发生时,不会覆盖现有的条目而是新增一条带有不同版本号的数据项。这种做法不仅提高了并发度同时也简化了事务处理流程。 #### BoltDB 数据库 作为底层的实际物理存储介质,BoltDB 负责承载由上层产生的实际键值对及其元数据。值得注意的是,在正常运行期间大多数交互都是针对内存缓存来进行优化过的;只有涉及到持久化的部分才会触及到底层文件系统层面的操作。 #### Write-Ahead Log (WAL) 预写式日志用于保障即使遇到意外断电等情况也能安全恢复之前未完全提交的变化。每笔交易先记入此日记账本然后再正式应用于内存结构之中。 #### Snapshot 快照 为了避免 WAL 日志无限增长占用过多空间,会周期性的制作全量备份即所谓的“快照”。一旦有了最新的快照之后就可以清理掉那些过期的日志片段以释放资源。 ```go // 示例 Go 客户端连接至 Etcd 并执行简单 Key/Value 操作 package main import ( "context" "fmt" clientv3 "go.etcd.io/etcd/client/v3" ) func main() { cli, err := clientv3.New(clientv3.Config{ Endpoints: []string{"localhost:2379"}, }) if err != nil { panic(err) } defer cli.Close() ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) _, err = cli.Put(ctx, "key", "value") cancel() if err != nil { fmt.Println("Put failed:", err) return } resp, _ := cli.Get(ctx, "key") for _, ev := range resp.Kvs { fmt.Printf("%s : %s\n", ev.Key, ev.Value) } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aries_Ro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值