不做大哥好多年 不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核

逍遥子

不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核
  • MySQL

  • Redis

  • Elasticsearch

  • Kafka

  • Etcd

    • 01.etcd安装使用
      • 01.etcd
        • 1.1 mac安装etcd
        • 1.2 etcd基本命令
        • 1.3 watch监视值变化
        • 1.4 获取版本信息
        • 1.5 etcd事务
        • 1.6 lease租约
      • 02.go基本操作
        • 2.1 get和put
        • 2.2 watch操作
    • 02.etcd原理 ✅
    • 03.go操作etcd
    • 04.etcd服务发现
    • 05.grpc负载均衡
    • 06.grpc加权轮训
    • 07.分布式锁
    • 08.事务
  • MongoDB

  • TiDB

  • RabbitMQ

  • 数据库
  • Etcd
xiaonaiqiang
2022-01-10
目录

01.etcd安装使用

# 01.etcd

  • etcd官网 (opens new window)

# 1.1 mac安装etcd

// 用brew安装非常方便,没安装的自行安装Homebrew
brew install etcd
// 执行etcd即可启动服务
etcd
1
2
3
4

# 1.2 etcd基本命令

  • 基本操作
$  etcdctl put name zhangsan
$  etcdctl get name   # 获取key和value
$  etcdctl del name
$  etcdctl update name lisi
$  etcdctl get name --print-value-only  # 只获value,不获取key
1
2
3
4
5
  • 前缀获取
$  etcdctl put foo1 bar1
$  etcdctl put foo2 bar2
$  etcdctl put foo3 bar3
# 获取从foo到foo3的值,不包括foo3
$  etcdctl get foo foo3 --print-value-only 
bar1
bar2
# 获取前缀为foo的值
$  etcdctl get --prefix foo --print-value-only
bar1
bar2
bar3
# 获取符合前缀的前两个值
$ etcdctl get --prefix --limit=2 foo --print-value-only
bar
bar1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • 事务写入
etcdctl put user1 bad
etcdctl txn --interactive

compares:
value("user1") = "bad"      

success requests (get, put, delete):
del user1  

failure requests (get, put, delete):
put user1 good
1
2
3
4
5
6
7
8
9
10
11
  • 分布式锁
    • 通过指定的名字加锁
    • 注意,只有当正常退出且释放锁后,lock命令的退出码是0,否则这个锁会一直被占用直到过期(默认60秒)
    • 使用Ctrl+C正常退出lock命令,退出码为0,第二次能正常lock
    • 如果是系统命令 kill 的 ps aux|grep 'etcdctl lock' 退出码是非0的
$ etcdctl lock test
test/38015a3fd6795e04
$ echo $?
0
1
2
3
4

# 1.3 watch监视值变化

$  etcdctl watch name        // 使用watch指令监控name变化
$  etcdctl put name lisi     // 在另外一个终端修改,可以扛到watch打印信息
1
2

# 1.4 获取版本信息

  • etcd使用b+tree存放key的版本信息
$  etcdctl put test 1
$  etcdctl put test 2
$  etcdctl put test 3 
$  etcdctl get test -w json
{
    "header":{
        "cluster_id":14841639068965178418,
        "member_id":10276657743932975437,
        "revision":9,      // 版本号
        "raft_term":3
    },
    "kvs":[
        {
            "key":"dGVzdA==",
            "create_revision":7,
            "mod_revision":9,
            "version":3,
            "value":"Mw=="
        }
    ],
    "count":1
}
$ etcdctl get test --rev=9
test
3
$ etcdctl get test --rev=8
test
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 1.5 etcd事务

$ etcdctl put addr bj
$ etcdctl put addr sh
$ etcdctl get addr -w json
/*
内存中   B树     key对应revision     
磁盘中   B+树    revison 找到value
*/
{
    "header":{
        "cluster_id":14841639068965178418,
        "member_id":10276657743932975437,
        "revision":12,    // 全局版本号 64位整数,只要对etcd修改,版本号都会加一(只要修改任意一个key都会加一)
        "raft_term":4     // 任期 64位整数 全局单调递增(每个leader都会对应一个任期)
    },
    "kvs":[
        {
            "key":"YWRkcg==",
            "create_revision":11,  // 创建key时候的revision版本号(和上面revision对应的)
            "mod_revision":12,    // 修改key时候的revision版本号(和上面revision对应的)
            "version":2,
            "value":"c2g="
        }
    ],
    "count":1
}
$ etcdctl get addr --rev=12  // 获取版本号为12的值
addr
sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  • value("addr") 根据当前key的值来判断
$ etcdctl txn -i
compares:   // 判断条件
value("addr") = "sh"

success requests (get, put, del):  // 如果判断条件成功,走这里的语句
put addr gz
get addr

failure requests (get, put, del):  // 如果判断条件不成立,走这里的语句
del addr

SUCCESS   // 这里可以看到走的是成功块的语句
OK
addr
gz
$ etcdctl get addr
addr
gz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • mod(key) key的修改版本号

# 1.6 lease租约

  • 类似 Redis expire

  • 大量key过期会导致性能下降,这时候可以将相同过期时间的key绑定到同一个对象中

  • 只要对象过期,这些可以就过期,这个对象就是租约

// 1)新建一个过期时间为120s的租约
# etcdctl lease grant 120
lease 018f6d7bb11aba0d granted with TTL(120s)
// 2)查看新建的租约信息
# etcdctl lease list
found 1 leases
018f6d7bb11aba0d
// 3)新建key,并为该key指定租约
# etcdctl put name alice --lease="018f6d7bb11aba0d"
// 4)查看当前租约绑定了哪些key
# etcdctl lease timetolive 018f6d7bb11aba0d --keys  
// 5)等到租约过期后,再次查看租约已经过期,对应的key也已经被自动删除
# etcdctl lease timetolive 018f6d7bb11aba0d --keys
lease 018f6d7bb11aba0d already expired
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 续租
// 1)新建租约并赋予key值
# etcdctl lease grant 30
lease 018f6d7bd032c117 granted with TTL(30s)
# etcdctl put name alice --lease=018f6d7bd032c117
// 2)在租约即将过期时进行续约,命令不会自动结束,会一直显示该窗口
# etcdctl lease keep-alive 018f6d7bd032c117
lease 018f6d7bd032c117 keepalived with TTL(30)
lease 018f6d7bd032c117 keepalived with TTL(30)
lease 018f6d7bd032c117 keepalived with TTL(30)
// 3)重新打开一个窗口,查看该租约续约信息,可以看到该租约会自动续约,相应key值也不会被删除
# etcdctl lease timetolive 018f6d7bd032c117 --keys
lease 018f6d7bd032c117 granted with TTL(30s), remaining(23s), attached keys([name])
# etcdctl lease timetolive 018f6d7bd032c117 --keys
lease 018f6d7bd032c117 granted with TTL(30s), remaining(22s), attached keys([name])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 回收租约:自动删除与该租约关联的key
// 1)回收租约
# etcdctl lease revoke 018f6d7bd032c117
// 2)可以看到租约已经过期
# etcdctl lease timetolive 018f6d7bd032c117 --keys
lease 018f6d7bd032c117 already expired
1
2
3
4
5

# 02.go基本操作

# 2.1 get和put

package main

import (
	"context"
	"fmt"
	"time"

	"go.etcd.io/etcd/clientv3"
)

func main() {
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   []string{"127.0.0.1:2379"},
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		fmt.Printf("connect to etcd failed, err:%v\n", err)
		return
	}
	fmt.Println("connect to etcd success")
	defer cli.Close()
	// put
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	_, err = cli.Put(ctx, "lmh", "lmh")
	cancel()
	if err != nil {
		fmt.Printf("put to etcd failed, err:%v\n", err)
		return
	}
	// get
	ctx, cancel = context.WithTimeout(context.Background(), time.Second)
	resp, err := cli.Get(ctx, "lmh")
	cancel()
	if err != nil {
		fmt.Printf("get from etcd failed, err:%v\n", err)
		return
	}
	fmt.Println(resp)
	for _, ev := range resp.Kvs {
		fmt.Printf("%s:%s\n", ev.Key, ev.Value)
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 2.2 watch操作

  • watch用来获取未来更改的通知。
package main

import (
	"context"
	"fmt"
	"time"
	"go.etcd.io/etcd/clientv3"
)

func main() {
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   []string{"127.0.0.1:2379"},
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		fmt.Printf("connect to etcd failed, err:%v\n", err)
		return
	}
	fmt.Println("connect to etcd success")
	defer cli.Close()
	// watch key:lmh change
	rch := cli.Watch(context.Background(), "lmh") // <-chan WatchResponse
	for wresp := range rch {
		for _, ev := range wresp.Events {
			fmt.Printf("Type: %s Key:%s Value:%s\n", ev.Type, ev.Kv.Key, ev.Kv.Value)
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  • 将上面的代码保存编译执行,此时程序就会等待etcd中lmh这个key的变化。

  • 例如:我们打开终端执行以下命令修改、删除、设置lmh这个key。

etcd> etcdctl.exe --endpoints=http://127.0.0.1:2379 put lmh "lmh1"
OK
etcd> etcdctl.exe --endpoints=http://127.0.0.1:2379 del lmh
1
etcd> etcdctl.exe --endpoints=http://127.0.0.1:2379 put lmh "lmh2"
OK
1
2
3
4
5
6
  • 上面的程序都能收到如下通知
watch>watch.exe
connect to etcd success
Type: PUT Key:lmh Value:lmh1
Type: DELETE Key:lmh Value:
Type: PUT Key:lmh Value:lmh2
1
2
3
4
5
上次更新: 2024/10/15 16:27:13
12.golang操作kafka
02.etcd原理 ✅

← 12.golang操作kafka 02.etcd原理 ✅→

最近更新
01
04.数组双指针排序_子数组
03-25
02
08.动态规划
03-25
03
06.回溯算法
03-25
更多文章>
Theme by Vdoing | Copyright © 2019-2025 逍遥子 技术博客 京ICP备2021005373号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式