专业的编程技术博客社区

网站首页 > 博客文章 正文

etcd,集群部署,一个用于配置共享和服务发现的键值存储系统

baijin 2024-11-16 17:05:14 博客文章 2 ℃ 0 评论

etcd简介

etcd

A distributed, reliable key-value store for the most critical data of a distributed system. 一个用于配置共享和服务发现的键值存储系统。

etcd是一个开源的、分布式的、强一致性的、可靠的键值存储系统。常用于存储分布式系统的关键数据。它可以在网络分区期间可以优雅地处理leader选举,并且可以容忍机器故障。

etcd的特点:简单、存储、Watch机制、安全通信、高性能和一致可靠。

官网:https://etcd.io/

etcd常用术语

  • etcd的V2.X和V3.X两个大版本,接口不一样,存储不一样,两个版本的数据互相隔离;
  • etcd是云原生架构中的存储基石,可以有效保证存储数据的一致性和可靠性;
  • etcd内部实现机制复杂,对外提供了简单直接的API接口。

etcd的应用场景

  1. 键值对存储;
  2. 服务注册与发现,基于Raft算法,强有力的保证分布式场景中的一致性;
  3. 消息发布与订阅,producer==>etcd==>consumer;
  4. 分布式通知与协调;
  5. 分布式锁,基于Raft算法,实现分布式集群的一致性;

etcd的核心架构

  • etcd server,用于接收和处理客户端请求;
  • gRPC server,etcd与其它etcd节点之间的通信和信息同步;
  • MVCC,多版本控制,etcd的存储模块,键值对的每一次操作行为会记录,存储在BoltDB数据库中;
  • WAL,预写式日志,etcd中的数据提交前都会记录到日志;
  • Snapshot,快照,以防WAL日志过多用于存储某一个时刻etcd的所有数据;
  • 通过etcdctl客户端命令行操作和访问etcd中的数据;
  • 通过HTTP API接口直接访问etcd;

etcd集群部署

部署说明

docker环境下集群部署。

部署脚本

#!/bin/bash

# 镜像名
image_name="bitnami/etcd:3.5.6"

#设置网络名
network_name="etcd_network"

#创建网络
docker network create --driver bridge --subnet=10.3.36.0/16 --gateway=10.3.1.1 ${network_name}

# 结点名1
node1="etcd_node1"
node1_ip=10.3.36.1
# 结点名2
node2="etcd_node2"
node2_ip=10.3.36.2
# 结点名3
node3="etcd_node3"
node3_ip=10.3.36.3

# 设置集群口令
cluster_token="etcd_cluster"


#创建节点1
docker run --name ${node1} \
  --network ${network_name} \
	--publish 12379:2379 \
	--publish 12380:2380 \
	--ip ${node1_ip} \
	--env ALLOW_NONE_AUTHENTICATION=yes \
	--env ETCD_NAME=${node1} \
	--env ETCD_ADVERTISE_CLIENT_URLS=http://${node1_ip}:2379 \
	--env ETCD_INITIAL_ADVERTISE_PEER_URLS=http://${node1_ip}:2380 \
	--env ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379 \
	--env ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380 \
	--env ETCD_INITIAL_CLUSTER_TOKEN=${cluster_token} \
	--env ETCD_INITIAL_CLUSTER=${node1}=http://${node1_ip}:2380,${node2}=http://${node2_ip}:2380,${node3}=http://${node3_ip}:2380 \
	--env ETCD_INITIAL_CLUSTER_STATE=new \
	-d $image_name

#创建节点2
docker run --name ${node2} \
	--network ${network_name} \
	--publish 22379:2379 \
	--publish 22380:2380 \
	--ip ${node2_ip} \
	--env ALLOW_NONE_AUTHENTICATION=yes \
	--env ETCD_NAME=${node2} \
	--env ETCD_ADVERTISE_CLIENT_URLS=http://${node2_ip}:2379 \
	--env ETCD_INITIAL_ADVERTISE_PEER_URLS=http://${node2_ip}:2380 \
	--env ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379 \
	--env ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380 \
	--env ETCD_INITIAL_CLUSTER_TOKEN=${cluster_token} \
	--env ETCD_INITIAL_CLUSTER=${node1}=http://${node1_ip}:2380,${node2}=http://${node2_ip}:2380,${node3}=http://${node3_ip}:2380 \
	--env ETCD_INITIAL_CLUSTER_STATE=new \
	-d $image_name

#创建节点3
docker run --name ${node3} \
	--network ${network_name} \
	--publish 32379:2379 \
	--publish 32380:2380 \
	--ip ${node3_ip} \
	--env ALLOW_NONE_AUTHENTICATION=yes \
	--env ETCD_NAME=${node3} \
	--env ETCD_ADVERTISE_CLIENT_URLS=http://${node3_ip}:2379 \
	--env ETCD_INITIAL_ADVERTISE_PEER_URLS=http://${node3_ip}:2380 \
	--env ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379 \
	--env ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380 \
	--env ETCD_INITIAL_CLUSTER_TOKEN=${cluster_token} \
	--env ETCD_INITIAL_CLUSTER=${node1}=http://${node1_ip}:2380,${node2}=http://${node2_ip}:2380,${node3}=http://${node3_ip}:2380 \
	--env ETCD_INITIAL_CLUSTER_STATE=new \
	-d $image_name

etcd客户端

键值对存储
# 查看版本
etcdctl version
---
etcdctl version: 3.5.6
API version: 3.5

# 写入数据【key:/test/foo value:hello etcd (双引号可去掉)】
etcdctl put /test/foo "hello etcd" 
# 获取数据
etcdctl get /test/foo
# 只获取值
etcdctl get /test/foo --print-value-only
# 获取前缀为/test的值
etcdctl get --prefix /test --print-value-only
# 获取符合前缀的前两个值
etcdctl get --prefix --limit=2 /test --print-value-only

# 删除(可删除多个,空格分割)
etcdctl del /test
# 删除key前缀为/test
etcdctl del --prefix /test

监视值变化

# 监视foo单个key
etcdctl watch foo
# 另一个控制台执行 
etcdctl put foo bar

# 监视多个key
etcdctl watch -i
watch foo
watch zoo
# 另一个控制台执行 
etcdctl put foo bar
etcdctl put zoo val

# 监视前缀key
etcdctl watch --prefix foo
# 另一个控制台执行 
etcdctl put foo1 bar1
etcdctl put fooz1 barz1

设置租约(GRANT LEASES)

当一个key被绑定到一个租约上时,它的生命周期与租约的生命周期绑定。

# 设置60秒后过期时间
etcdctl lease grant 60
---
lease 5a2284ec1ff9d80c granted with TTL(60s)
# 把键和租约绑定,设置成60秒后过期
etcdctl put --lease=5a2284ec1ff9d80c foo bar
# 获取值(60秒后,获取不到)
etcdctl get foo

主动撤销租约(REVOKE LEASES)

通过租赁ID撤销租约,撤销租约将删除其所有绑定的key。

# 设置60秒后过期时间
etcdctl lease grant 60
---
lease 5a2284ec1ff9d819 granted with TTL(60s)
# 把键和租约绑定,设置成60秒后过期
etcdctl put foo bar --lease=5a2284ec1ff9d819
# 主动撤销租约
etcdctl lease revoke 5a2284ec1ff9d819
---
lease 5a2284ec1ff9d819 revoked
# 返回空内容
etcdctl get foo

续租约(KEEP LEASES ALIVE)

# 设置60秒后过期租约
etcdctl lease grant 60
---
lease 5a2284ec1ff9d81e granted with TTL(60s)
# 把键和租约绑定,设置成60秒后过期
etcdctl put foo bar --lease=5a2284ec1ff9d81e
# 续租约,自动定时执行续租约,续约成功后每次租约为60秒
etcdctl lease keep-alive 5a2284ec1ff9d81e
---
lease 5a2284ec1ff9d81e keepalived with TTL(60)

# 查看租约信息
etcdctl lease timetolive --keys 5a2284ec1ff9d81e
---
lease 5a2284ec1ff9d81e granted with TTL(60s), remaining(26s), attached keys([foo])

# 查看租约信息
etcdctl lease timetolive --keys 5a2284ec1ff9d81e
---
lease 5a2284ec1ff9d81e already expired

总结:当一个租约只绑定了一个key时,想删除这个key,最好的办法是撤销它的租约,而不是直接删除这个key。

etcd总结

etcd与redis差异

etcd和redis都支持键值存储,也支持分布式特性,redis支持的数据格式更加丰富,但是他们两个定位和应用场景不一样,关键差异如下:

  • redis在分布式环境下不是强一致性的,可能会丢失数据,或者读取不到最新数据;
  • redis的数据变化监听机制没有etcd完善;
  • etcd强一致性保证数据可靠性,导致性能上要低于redis;
  • etcd和ZooKeeper是定位类似的项目,跟redis定位不一样;

etcd和ZooKeeper比较,ZooKeeper的缺点

  1. 复杂:ZooKeeper的部署维护复杂,管理员需要掌握一系列的知识和技能;而Paxos强一致性算法也是素来以复杂难懂而闻名于世;
    另外,ZooKeeper的使用也比较复杂,需要安装客户端,官方只提供了Java和C两种语言的接口。
  2. 难以维护:Java偏向于重型应用,引入大量的依赖,运维人员普遍希望保持强一致、高可用的机器集群尽可能简单,维护起来也不易出错。
  3. 发展缓慢:Apache 基金会项目特有的“Apache Way”在开源界饱受争议,其中一大原因就是由于基金会庞大的结构以及松散的管理导致项目发展缓慢。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表