Etcd教程 — 第八章 Etcd之Compact、Watch和Lease API_etcd compact

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注go)
img

正文

监视流

Watch API 提供了一个基于事件的接口,用于异步监视键的更改。etcd 监视程序通过从给定的修订版本(当前版本或历史版本)连续监视来等待密钥更改,并将密钥更新流回客户端。

监视持续运行,并使用 gRPC 来流式传输事件数据。监视流是双向的,客户端写入流以建立监视事件,并读取以接收监视事件。单个监视流可以通过使用每个观察器标识符标记事件来复用许多不同的观察。这种多路复用有助于减少 etcd 群集上的内存占用量和连接开销。

Watch 事件具有如下三个特性:

  • 有序,事件按修订顺序排序;如果事件早于已发布的事件,它将永远不会出现在列表上。
  • 可靠,事件序列永远不会丢弃任何事件子序列;如果按时间顺序为 a < b < c 三个事件,那么如果 Watch 接收到事件 a 和 c,则可以保证接收到 b。
  • 原子,保证事件清单包含完整的修订版;同一修订版中通过多个键进行的更新不会拆分为多个事件列表。

Watch service 定义
在 rpc.proto 中 Watch service 定义如下:
在这里插入图片描述

service Watch {
rpc Watch(stream WatchRequest) returns (stream WatchResponse) {}
}

Watch 观察将要发生或者已经发生的事件。输入和输出都是流;输入流用于创建和取消观察,而输出流发送事件。一个观察 RPC 可以在一次性在多个 key 范围上观察,并为多个观察流化事件。整个事件历史可以从最后压缩修订版本开始观察。

WatchService 只有一个 Watch 方法。

请求的消息体 WatchRequest 定义如下:

message WatchRequest {
oneof request_union {
WatchCreateRequest create_request = 1;
WatchCancelRequest cancel_request = 2;
}
}

request_union 要么是创建新的观察者的请求,要么是取消一个已经存在的观察者的请求。创建新的观察者的请求 WatchCreateRequest:

message WatchCreateRequest {
// key 是注册要观察的 key
bytes key = 1;

bytes range_end = 2;

// start_revision 是可选的开始(包括)观察的修订版本。不设置 start_revision 则表示 “现在”.
int64 start_revision = 3;

bool progress_notify = 4;

enum FilterType {
// 过滤掉 put 事件
NOPUT = 0;

// 过滤掉 delete 事件
NODELETE = 1;
}

// 过滤器,在服务器端发送事件给回观察者之前,过滤掉事件。
repeated FilterType filters = 5;

// 如果 prev_kv 被设置,被创建的观察者在事件发生前获取上一次的KV。
// 如果上一次的KV已经被压缩,则不会返回任何东西
bool prev_kv = 6;
}

  • range_end 是要观察的范围 [key, range_end) 的终点。如果 range_end 没有设置,则只有参数 key 被观察;如果 range_end 等同于 ‘\0’, 则大于等于参数 key 的所有 key 都将被观察;如果 range_end 比给定 key 大1, 则所有以给定 key 为前缀的 key 都将被观察。
  • progress_notify 设置,这样如果最近没有事件,etcd 服务器将定期的发送不带任何事件的 WatchResponse 给新的观察者。当客户端希望从最近已知的修订版本开始恢复断开的观察者时有用。etcd 服务器将基于当前负载决定它发送通知的频率。

取消已有观察者的 WatchCancelRequest:

message WatchCancelRequest {
int64 watch_id = 1;
}

watch_id 是要取消的观察者的id,这样就不再有更多事件传播过来了。

应答的消息体 WatchResponse:

message WatchResponse {
ResponseHeader header = 1;
// watch_id 是和应答相关的观察者的ID
int64 watch_id = 2;

bool created = 3;

bool canceled = 4;

int64 compact_revision = 5;

// cancel_reason 指出取消观察者的理由.
string cancel_reason = 6;

repeated mvccpb.Event events = 11;
}

  • 如果应答是用于创建观察者请求的,则 created 设置为 true。客户端应该记录 watch_id 并期待从同样的流中为创建的观察者接收事件。所有发送给被创建的观察者的事件将附带同样的 watch_id;如果应答是用于取消观察者请求的,则 canceled 设置为true。不会再有事件发送给被取消的观察者。
  • compact_revision 被设置为最小 index,如果观察者试图观察被压缩的 index。当在被压缩的修订版本上创建观察者或者观察者无法追上键值对存储的进展时发生。客户端应该视观察者为被取消,并不应该试图再次创建任何带有相同 start_revision 的观察者。

3 Lease 服务

Lease service 提供租约的支持。Lease 是一种检测客户端存活状况的机制。集群授予具有生存时间的租约。如果Etcd集群在给定的 TTL 时间内未收到 keepAlive,则租约到期。

为了将租约绑定到键值上,每个 key 最多可以附加一个租约。当租约到期或被撤销时,该租约所附的所有 key 都将被删除。每个过期的密钥都会在事件历史记录中生成一个删除事件。

在 rpc.proto 中 Lease service 定义的接口如下:

service Lease {

rpc LeaseGrant(LeaseGrantRequest) returns (LeaseGrantResponse) {}

rpc LeaseRevoke(LeaseRevokeRequest) returns (LeaseRevokeResponse) {}

rpc LeaseKeepAlive(stream LeaseKeepAliveRequest) returns (stream LeaseKeepAliveResponse) {}

rpc LeaseTimeToLive(LeaseTimeToLiveRequest) returns (LeaseTimeToLiveResponse) {}
}

  • LeaseGrant:创建租约
  • LeaseRevoke:撤销租约
  • LeaseKeepAlive:维持租约
  • LeaseTimeToLive:获取租约信息

3.1 LeaseGrant 方法

LeaseGrant 方法创建一个租约。当服务器在给定 time to live 时间内没有接收到 keepAlive 时租约过期。如果租约过期则所有附加在租约上的 key 将过期并被删除。每个过期的 key 在事件历史中生成一个删除事件。

方法定义如下:

rpc LeaseGrant(LeaseGrantRequest) returns (LeaseGrantResponse) {}

请求的消息体是 LeaseGrantRequest:

message LeaseGrantRequest {
int64 TTL = 1;

int64 ID = 2;
}

TTL 建议以秒为单位的 time-to-live。ID 是租约的请求 ID,如果 ID 设置为 0,则出租人(也就是 etcd server)选择一个 ID。

应答的消息体 LeaseGrantResponse 定义如下:

message LeaseGrantResponse {
ResponseHeader header = 1;

int64 ID = 2;

int64 TTL = 3;
string error = 4;
}

ID 是承认的租约的 ID。TTL 是服务器选择的以秒为单位的租约 time-to-live。

3.2 LeaseRevoke 方法

LeaseRevoke 撤销一个租约,此时所有附加到租约的 key 将过期并被删除。

rpc LeaseRevoke(LeaseRevokeRequest) returns (LeaseRevokeResponse) {}

请求的消息体 LeaseRevokeRequest 定义如下:

message LeaseRevokeRequest {

int64 ID = 1;
}

ID 是要取消的租约的 ID。当租约被取消时,所有关联的 key 将被删除。

应答的消息体 LeaseRevokeResponse 定义如下:

message LeaseRevokeResponse {
ResponseHeader header = 1;
}

LeaseRevokeResponse 中只有一个通用的响应头字段。

3.3 LeaseKeepAlive 方法

LeaseKeepAlive 方法维持一个租约。LeaseKeepAlive 通过从客户端到服务器端的流化的 keep alive 请求和从服务器端到客户端的流化的 keep alive 应答来维持租约。

rpc LeaseKeepAlive(stream LeaseKeepAliveRequest) returns (stream LeaseKeepAliveResponse) {}

请求的消息体 LeaseKeepAliveRequest 定义如下:

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

请求的消息体 LeaseKeepAliveRequest 定义如下:

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-2Wvo5b0t-1713301940447)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Etcd是一个高可用的键值存储系统,用于分布式系统中的服务发现和配置共享。而gRPC则是一种高性能、开源和通用的RPC框架,可以在任何环境中连接多种语言开发的应用程序。将Etcd与gRPC结合起来,可以实现高效的微服务治理。 在Python中,可以使用etcd3库与Etcd进行通信,使用grpc库实现gRPC服务。具体实现步骤如下: 1. 安装etcd3和grpc库 ```sh pip install etcd3 grpcio grpcio-tools ``` 2. 启动Etcd服务 可以使用Docker容器启动Etcd服务: ```sh docker run --rm -p 2379:2379 -p 2380:2380 --name etcd quay.io/coreos/etcd:v3.3.8 /usr/local/bin/etcd --advertise-client-urls http://0.0.0.0:2379 --listen-client-urls http://0.0.0.0:2379 --listen-peer-urls http://0.0.0.0:2380 ``` 3. 编写服务代码 首先,定义.proto文件,声明gRPC服务: ```protobuf syntax = "proto3"; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; } ``` 然后,使用grpc_tools.protoc工具生成Python代码: ```sh python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. helloworld.proto ``` 编写服务实现代码: ```python import grpc import helloworld_pb2 import helloworld_pb2_grpc class Greeter(helloworld_pb2_grpc.GreeterServicer): def SayHello(self, request, context): return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) server.add_insecure_port('[::]:50051') server.start() server.wait_for_termination() ``` 最后,编写Etcd服务注册和发现代码: ```python import etcd3 class EtcdRegistry(object): def __init__(self, etcd_host, etcd_port, service_name, service_addr): self.etcd = etcd3.client(host=etcd_host, port=etcd_port) self.service_name = service_name self.service_addr = service_addr self.lease_id = None def register(self, ttl=10): self.lease_id = self.etcd.lease(ttl) self.etcd.put('/{}/{}/{}'.format(self.service_name, self.service_addr, self.lease_id), str(self.service_addr), lease=self.lease_id) self.etcd.refresh_lease(self.lease_id) def unregister(self): if self.lease_id: self.etcd.revoke_lease(self.lease_id) ``` 在服务启动时,调用register()方法注册服务,停止时调用unregister()方法注销服务。 最后,通过Etcdwatch方法,实现服务发现: ```python import etcd3 class EtcdDiscovery(object): def __init__(self, etcd_host, etcd_port, service_name): self.etcd = etcd3.client(host=etcd_host, port=etcd_port) self.service_name = service_name def watch(self): for event in self.etcd.watch_prefix('/{}'.format(self.service_name)): if event.event_type == 'PUT': yield event.key.decode(), event.value.decode() ``` 在客户端中,调用watch()方法监听服务节点的变化,获取可用的服务列表。 以上就是将Etcd和gRPC应用于Python微服务的基本步骤。通过Etcd提供的服务注册和发现功能,可以实现高效的微服务治理,提高微服务的可用性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值