Etcd介绍
Etcd是一个高可用的开源的、分布式的Key/value存储系统、提供共享配置、服务的注册和发现、提供了数据TTL失效、数据改变监视、多值、目录监听、分布式原子锁操作等功能。
Etcd相关词汇介绍:
- Raft:etcd采用的保证分布式系统强一致性的算法
- Node:一个Raft状态机实例
- Member:一个etcd实例、管理着一个None、并且可以为客户端提供请求服务
- Cluster:由多个Member构成可以协同工作的etcd集群
- Peer:对同一个etcd集群中另一个Member的称呼
- Client:向etcd集群发送http请求的客户端
- WAL:预写式日志、etcd用于持久化存储的日志格式
- Snapshot:etcd防止WAL文件过多而设置的快照、存储etcd数据状态
- Proxy:etcd的一种模式、为etcd集群提供反向代理服务
- Leader:Raft算法中通过竞选而产生的处理所有数据提交的节点
- Follower:竞选失败的节点作为Raft中的从属节点、为算法提供强一致性保证
- Candidate:当Follower超过一定时间接收不到Leader的心跳时转变为Candidate开始竞选
- Term:某个节点成为Leader到下一次竞选的时间,称为一个Term
- Index:数据项编号、Raft中通过Term和Index来定位数据
系统中的服务注册和发现具有的基本功能:
- 服务注册:同一service的所有节点注册到相同的目录下、节点启动后将自己的信息注册到所属服务的目录中。
- 健康检查:服务节点定时发送心跳、注册到服务目录中的信息设置一个较短的TTL、运行正常的服务节点每隔一段时间会更新信息的TTL。
- 服务发现:通过名称能查询到服务提供外部访问的IP和端口号。例如反向代理服务器能及时发现服务中新增的节点、丢弃不可用的服务节点、同时各个服务间也能感知到对方的存在。
相似项目:zookeeper和consul
具有的特点:
- 完全复制:集群中的每个节点都可以使用完整的文档
- 高可用性:Etcd可用于避免硬件的单点故障或网络问题
- 一致性:每次读取都会返回跨多主机的最新写入
- 简单:包含一个定义良好、面向用户的API(GRPC)
- 安全:实现了带有可选的客户端证书身份验证的自动化TLS
- 快速:每秒1万次的写入基准速度
- 可靠:使用Raft算法实现了强一致性、高可用的服务存储目录
应用场景:
1、服务发现:解决在同一个分布式集群中的进程或服务、如何找到对方并建立链接
2、配置中心:将配置信息放到etcd上面进行集中管理
使用方式:应用在启动的时候主动从etcd获取一次配置、同时在etcd节点上注册一个watcher并等待、每次配置更新的时候、etcd都会实时通知订阅者。
3、分布式锁:两种使用方式,保持独占和控制时序
- 保持独占即所有获取锁的用户最终只有一个可以得到。etcd为此提供了一套实现分布式原子操作CAS(CompareAndSwap)的API。通过设置preExist的值、可以保证在多个节点同时去创建某个目录时、只有一个成功,而创建成功的用户可以认为是获得了锁。
- 获得时序即所有想要获得锁的用户都会被安排执行,但是获得锁的顺序也是全局唯一的,同时决定了执行的顺序。etcd为此提供了一套API(自动创建有续键),对一个目录建值时指定为POST动作、这样etcd会自动在目录下生成一个的当前最大的值为键,存储这个新的值(客户端编号)。同时还可以使用API按顺序累出所有当前目录下的键值。此时这些键的值就是客户端的时许,而这些键中存储的值可以是代表客户端的编号。
Etcd安装:支持单点部署、但是在生产环境中推荐使用集群方式部署、一般etcd节点数会选择3,5,7等奇数个。etcd会保证所有节点都会保存数据、并保证数据的一致性和正确性。
通信端口:
- 2379:提供HTTP-API服务、为客户端操作提供api接口服务
- 2380:提供集群数据通信、为集群间的数据同步提供服务
单点部署:下载源码包、编译为可执行文件(使用build脚本构建会在当前项目的bin目录下面生成etcd和etcdctl可执行程序、etcd是etcd Server服务程序、etcdctl是链接etcd的客户端程序使用命令行操作进行和服务端的交互)
git clone https://github.com/etcd-io/etcd.git cd etcd ./build
查看版本号
./bin/etcd --version
启动etcd服务
./bin/etcd
Linux-Systemd服务创建
/etc/systemd/system/etcd.service
[Unit] Description=Etcd Server
Documentation=https://github.com/coreos/etcd
After=network.target
[Service]
User=root
Type=notify
EnvironmentFile=-/opt/etcd/config/etcd.conf
ExecStart=~/workspace/etcd/bin
Restart=on-failure
RestartSec=10s
LimitNOFILE=40000
[Install]
WantedBy=multi-user.target
服务启动和重启
systemctl daemon-reload && systemctl enable etcd && systemctl start etcd
```json
Etcd的V2版本-http-api
注意点:使用`etcd --enable-v2`此命令参数启动运行服务端
1. 获取etcd服务的版本信息
```json
GET:http://127.0.0.1:2379/version
response: { "etcdserver": "3.4.15", "etcdcluster": "3.4.0" }
- 获取etcd服务的健康状态
GET:http://127.0.0.1:2379/health
response: { "health": "true" }
- key的新增
PUT:http://127.0.0.1:2379/v2/keys/message
requestBody:content-type:form-data或application/x-www-form-urlencoded 。 {"value":value}
response: { "action": "set", // 行为 "node": { 。 // 节点 "key": "/message", // 键名 "value": "", // 键值 "modifiedIndex": 34,//修改坐标 "createdIndex": 34 // 创建坐标 }, "prevNode": { 。 // 上一次的值 "key": "/message", // 键名 "value": "", // 键值 "modifiedIndex": 33, // 修改坐标 "createdIndex": 33 // 创建坐标 } }
- key的查看
GET:http://127.0.0.1:2379/v2/keys/message
response: { "action": "get", // 行为 "node": { // 节点 "key": "/message",// 键名 "value": "world233",// 键值 "modifiedIndex": 35,//修改坐标 "createdIndex": 35 // 创建坐标 } }
- key的更新-同key的新增、没有键名则新增有则更新
PUT:http://127.0.0.1:2379/v2/keys/message
requestBody:content-type:form-data或application/x-www-form-urlencoded 。 {"value":value2}
response: { "action": "set", "node": { "key": "/message", "value": "worldchange", "modifiedIndex": 39, "createdIndex": 39 }, "prevNode": { "key": "/message", "value": "world233", "modifiedIndex": 35, "createdIndex": 35 } }
- key的删除
DELETE:http://127.0.0.1:2379/v2/keys/message
response: { "action": "delete", "node": { "key": "/message", "modifiedIndex": 40, "createdIndex": 39 }, "prevNode": { "key": "/message", "value": "worldchange", "modifiedIndex": 39, "createdIndex": 39 } }
- 创建带有ttl的键
PUT:http://127.0.0.1:2379/v2/keys/message
requestBody:content-type:form-data或application/x-www-form-urlencoded 。 {"value":value3,"ttl":number}
response: { "action": "set", "node": { "key": "/message", "value": "worldchange", "expiration": "2021-04-06T01:09:06.62982Z", //过期时间 "ttl": 3, //存活时间 "modifiedIndex": 45, "createdIndex": 45 } }
- 取消key的ttl
PUT:http://127.0.0.1:2379/v2/keys/message
requestBody:content-type:form-data或application/x-www-form-urlencoded {"value":value3,"prevExist":true}
response: { "action": "update", "node": { "key": "/msg", "value": "worldchange", "modifiedIndex": 38, "createdIndex": 37 }, "prevNode": { "key": "/msg", "value": "worldchange", "expiration": "2021-04-07T02:28:29.933757Z", "ttl": 112, "modifiedIndex": 37, "createdIndex": 37 } }
- 重置key的ttl
PUT:http://127.0.0.1:2379/v2/keys/message
requestBody:content-type:form-data或application/x-www-form-urlencoded 。 {"value":value3,"ttl":number,"refresh":true}
response: { "action": "set", "node": { "key": "/msg", "value": "worldchange", "expiration": "2021-04-06T02:14:31.677307Z", // 更新后的时间 "ttl": 60, "modifiedIndex": 33, "createdIndex": 33 }, "prevNode": { "key": "/msg", "value": "worldchange", "expiration": "2021-04-06T02:14:17.772133Z", // 更新前的时间 "ttl": 47, "modifiedIndex": 32, "createdIndex": 32 } }
- 创建目录
PUT:http://127.0.0.1:2379/v2/keys/dirname requestBody:content-type:form-data或application/x-www-form-urlencoded 。 {"value":value3,"ttl":number,"refresh":true}
response: { "action": "set", "node": { "key": "/dirname", "dir": true, "modifiedIndex": 35, "createdIndex": 35 } }
- 查看目录
GET:http://127.0.0.1:2379/v2/keys/dirname
response: { "action": "get", "node": { "key": "/dirname", "dir": true, "modifiedIndex": 35, "createdIndex": 35 } }
- 在目录下创建有序键
POST:http://127.0.0.1:2379/v2/keys/dir
requestBody:content-type:form-data或application/x-www-form-urlencoded 。 {"value":value3}
response: { "action": "create", "node": { "key": "/dir/00000000000000000040", "value": "worldchange", "modifiedIndex": 40, "createdIndex": 40 } }
- 按顺序列出目录下的键-不显示子目录下的键
GET:http://127.0.0.1:2379/v2/keys/dir?sorted=true
response: { "action": "get", "node": { "key": "/dir", "dir": true, "nodes": [ { "key": "/dir/00000000000000000040", "value": "worldchange", "modifiedIndex": 40, "createdIndex": 40 }, { "key": "/dir/00000000000000000041", "value": "worldchange2", "modifiedIndex": 41, "createdIndex": 41 }, { "key": "/dir/00000000000000000042", "value": "worldchange3", "modifiedIndex": 42, "createdIndex": 42 }, { "key": "/dir/00000000000000000043", "dir": true, "modifiedIndex": 43, "createdIndex": 43 }, { "key": "/dir/worldchange3", "dir": true, "modifiedIndex": 44, "createdIndex": 44 } ], "modifiedIndex": 39, "createdIndex": 39 } }
- 按顺序列出目录下所有的键-含子目录下的键
GET:http://127.0.0.1:2379/v2/keys/dir?sorted=true&recursive=true
response: { "action": "get", "node": { "key": "/dir", "dir": true, "nodes": [ { "key": "/dir/00000000000000000040", "value": "worldchange", "modifiedIndex": 40, "createdIndex": 40 }, { "key": "/dir/00000000000000000041", "value": "worldchange2", "modifiedIndex": 41, "createdIndex": 41 }, { "key": "/dir/00000000000000000042", "value": "worldchange3", "modifiedIndex": 42, "createdIndex": 42 }, { "key": "/dir/00000000000000000043", "dir": true, "modifiedIndex": 43, "createdIndex": 43 }, { "key": "/dir/worldchange3", "dir": true, "nodes": [ { "key": "/dir/worldchange3/00000000000000000044", "value": "worldchange", "modifiedIndex": 44, "createdIndex": 44 }, { "key": "/dir/worldchange3/00000000000000000045", "value": "worldchangesub", "modifiedIndex": 45, "createdIndex": 45 } ], "modifiedIndex": 44, "createdIndex": 44 } ], "modifiedIndex": 39, "createdIndex": 39 } }
- 删除目录-默认情况下只允许删除空目录、删除空目录需要使用dir=true或recursive=true两个参数中至少一个、删除非空目录必须使用recursive=true
DELETE:http://127.0.0.1:2379/v2/keys/dir?dir=true&recursive=true
response: { "action": "delete", "node": { "key": "/dir", "dir": true, "modifiedIndex": 46, "createdIndex": 39 }, "prevNode": { "key": "/dir", "dir": true, "modifiedIndex": 39, "createdIndex": 39 } }
- 创建定时删除目录
PUT:http://127.0.0.1:2379/v2/keys/dir2
requestBody:content-type:form-data或application/x-www-form-urlencoded 。 {"ttl":number,"dir":true}
response: { "action": "set", "node": { "key": "/dir2", "dir": true, "expiration": "2021-04-07T03:16:23.225804Z", "ttl": 120, "modifiedIndex": 47, "createdIndex": 47 } }
- 更新或删除目录超时时间-ttl参数设置或刷新ttl,ttl为空时取消ttl、-prevExist
PUT:http://127.0.0.1:2379/v2/keys/dir2
requestBody:content-type:form-data或application/x-www-form-urlencoded 。 {"ttl":number,"dir":true,"prevExist":true}
response: { "action": "update", "node": { "key": "/dir2", "dir": true, "expiration": "2021-04-07T03:39:42.967762Z", "ttl": 1200, "modifiedIndex": 51, "createdIndex": 49 }, "prevNode": { "key": "/dir2", "dir": true, "modifiedIndex": 49, "createdIndex": 49 } }
- 创建隐藏节点-命名时名字以下划线_开头的key或目录,默认为隐藏键
PUT:http://127.0.0.1:2379/v2/keys/_message
requestBody:content-type:form-data或application/x-www-form-urlencoded 。 {"value":value3}
response: { "action": "set", "node": { "key": "/_message", "value": "worldchangesub", "modifiedIndex": 52, "createdIndex": 52 } }
- Statistics统计接口-etcd集群记录大量的数据数据、包括延时、宽带和正常运行时间
GET:http://127.0.0.1:2379/v2/stats/self
response: { "name": "default", "id": "8e9e05c52164694d", "state": "StateLeader", "startTime": "2021-04-07T09:54:11.057627+08:00", "leaderInfo": { "leader": "8e9e05c52164694d", "uptime": "1h1m16.267333067s", "startTime": "2021-04-07T09:54:12.062102+08:00" }, "recvAppendRequestCnt": 0, "sendAppendRequestCnt": 0 }
Etcd V3版本API-GRPC网关将http/json请求转换为gRPC消息
注意点:启动Etcd服务端,使用etcd
开启服务
- 新增键或更新键-不存在键则新建,存在键则更新键值
POST:http://127.0.0.1:2379/v3/kv/put
requestBody:content-type-application/json 。 {"key": "Zm9v", "value": "YmFy"}
response: { "header": { "cluster_id": "14841639068965178418", "member_id": "10276657743932975437", "revision": "16", "raft_term": "5" } }
- 获取键
POST:http://127.0.0.1:2379/v3/kv/put
requestBody:content-type-application/json 。 {"key":"Zm9v"}
response: { "header": { "cluster_id": "14841639068965178418", "member_id": "10276657743932975437", "revision": "16", "raft_term": "5" }, "kvs": [ { "key": "Zm9v", "create_revision": "2", "mod_revision": "13", "version": "11", "value": "YmFy" } ], "count": "1" }
Etcd集群配置
1、创建etcd配置文件
* ETCD_NAME:节点名称、集群中唯一
* ETCD_DATA_DIR:数据目录
* ETCD_LISTEN_PEER_URLS:集群通信监听地址
* ETCD_LISTEN_CLIENT_URLS:客户端访问地址
* ETCD_INITIAL_ADVERTISE_PEER_URLS:集群通告地址
* ETCD_ADVERTISE_CLIENT_URLS:客户端通告地址
* ETCD_INITIAL_CLUSTER:集群节点地址
* ETCD_INITIAL_CLUSTER_TOKEN:集群token
* ETCD_INITIAL_CLUSTER_STATE:加入集群的当前状态、new是新集群、existing表示加入已有集群
#[Member] ETCD_NAME="etcd-1" ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.31.71:2380" ETCD_LISTEN_CLIENT_URLS="https://192.168.31.71:2379" #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.31.71:2380" ETCD_ADVERTISE_CLIENT_URLS="https://192.168.31.71:2379" ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.31.71:2380,etcd-2=https://192.168.31.72:2380,etcd-3=https://192.168.31.73:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" ETCD_INITIAL_CLUSTER_STATE="new"