Etcd 介绍

  • Post author:
  • Post category:其他




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来定位数据


系统中的服务注册和发现具有的基本功能:

  1. 服务注册:同一service的所有节点注册到相同的目录下、节点启动后将自己的信息注册到所属服务的目录中。
  2. 健康检查:服务节点定时发送心跳、注册到服务目录中的信息设置一个较短的TTL、运行正常的服务节点每隔一段时间会更新信息的TTL。
  3. 服务发现:通过名称能查询到服务提供外部访问的IP和端口号。例如反向代理服务器能及时发现服务中新增的节点、丢弃不可用的服务节点、同时各个服务间也能感知到对方的存在。

具有的特点:

  • 完全复制:集群中的每个节点都可以使用完整的文档
  • 高可用性: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会保证所有节点都会保存数据、并保证数据的一致性和正确性。


通信端口:

  1. 2379:提供HTTP-API服务、为客户端操作提供api接口服务
  2. 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集群配置

  • 创建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"



版权声明:本文为JineD原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。