一、安装
1.1 安装ETCD包
python3 -m pip install etcd3
1.2 问题解决
直接安装完成后,在使用过程中可能会出现一些问题,作以记录如下。
1.2.1 protos 问题
在使用过程中,可能会遇到下述报错:
......
If this call came from a _pb2.py file, your generated code is out of date and must be regenerated with protoc >= 3.19.0.
If you cannot immediately regenerate your protos, some other possible workarounds are:
1. Downgrade the protobuf package to 3.20.x or lower.
2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will use pure-Python parsing and will be much slower).
意思是 protoc 这个玩意儿版本低了,调用有问题。你要是不能重新生成,可以通过两个步骤解决此问题:
- protobuf 使用3.20.x 版本或者更低的版本:
python3 -m pip install protobuf==3.20.1
- 设置一个环境变量:
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
环境变量建议设置在~/.bashrc
或者/etc/profile
1.2.2 UNAUTHENTICATED 问题
......
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
status = StatusCode.UNAUTHENTICATED
details = "Established channel does not have a sufficient security level to transfer call credential."
......
此问题是grpc的认证问题,在高版本的grpc中要求安全的通讯信道,比如SSL。
如果不能对ETCD服务设置SSL,那么可以通过降低grpc版本解决。参考:etcd3 and python: UNAUTHENTICATED: Established channel does not have a sufficient security level to transfer call credential · Issue #29643 · grpc/grpc (github.com)
执行下述安装即可,会卸载当前版本的grpcio,安装指定版本:
python3 -m pip install grpcio==1.44.0
二、获取数据
使用可以参考:API Usage — python-etcd3 0.8.1 documentation
正常的Get、Put直接操作即可,如果通过 get_prefix 获取,可能会遇到如下错误:
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
status = StatusCode.RESOURCE_EXHAUSTED
details = "Received message larger than max (135558824 vs. 4194304)"
意思是获取的消息内容太大,超过了grpc设置。此时我们可以通过在etcd创建的时候指定grpc设置,来修改消息内容上限:
etcd_client = etcd3.client(host="127.0.0.1", port=2379,
grpc_options={
"grpc.max_send_message_length": 1024*1024*1024, # 设置发送消息的尺寸上限
"grpc.max_receive_message_length": 1024*1024*1024, # 设置接受消息的尺寸上限
}.items()
)
上述代码在etcd客户端初始化时设置了发送和接受消息的大小上限。可以缓解 “Received message larger than max” 错误。
如果改到足够大的尺寸,还是不能缓解问题,则需要通过其他手段限制获取的内容大小。比如,使用 get_range
方法分段获取所需内容。下述代码是通过 get_range
获取所有ETCD内容:
start_key = "/" # 起始 key
end_key = "\0" # 结束 key,若没有,则应设为 \0,此处不设置结束 key,以便获取所有 key
limit_per_get = 1000 # 每次获取的最大数量
while True:
items = etcd_client.get_range(range_start=start_key,
range_end=end_key,
limit=limit_per_get)
count = 0 # 记录本次获取数量
for item in items:
count += 1
#
# 这里可以对 item 进行处理
#
# 重设起始 key
start_key = item[1].key
# 若本次获取小于 limit_per_get,则说明已经获取完毕
if count < limit_per_get:
break
通过控制每次获取的key的数量控制响应内容的大小,虽然多次获取会影响效率,但是比报错要好点儿。