热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

go与etcd

go与etcd,Go语言社区,Golang程序员人脉社

etcd

高可用的分布式key-value存储,可用于配置共享和服务发现,类似项目有zookeeper

提供restful的http接口,使用简单。基于raft算法(主从、选举等)的强一致性,高可用的服务存储目录

应用场景:服务发现和服务注册,配置中心,分布式锁,master选举

参考:

https://coreos.com/etcd/docs/latest/demo.html

https://github.com/etcd-io/etcd


 Windows命令行使用etcd(本地单台机器)

1、环境变量设置ETCDCTL_API=3

2、启动etcd:

./etcd.exe

提示已在指定ip和端口启动

3、通过使用 etcdctl 来和已经启动的集群交互:

./etcdctl.exe --write-out=table --endpoints=localhost:2379 member list

多台机器集群参考http://etcd.doczh.cn/documentation/op-guide/clustering.html

 

 go操作etcd

快速入门

启动etcd.exe后

package main import ( "context" "fmt" "go.etcd.io/etcd/clientv3" "log" "strconv" "time" ) func main() { config := clientv3.Config{ Endpoints: []string{"127.0.0.1:2379"}, DialTimeout: 10 * time.Second, } cli, err := clientv3.New(config) if err != nil { panic(err) } defer cli.Close() go put(cli) rch := cli.Watch(context.Background(), "foo", clientv3.WithPrefix()) for wresp := range rch { for _, ev := range wresp.Events { fmt.Printf("%s %q : %qn", ev.Type, ev.Kv.Key, ev.Kv.Value) } } } func put(cli *clientv3.Client) { num := 1 for { time.Sleep(time.Second) ctx, cancel := context.WithTimeout(context.Background(), time.Second) _, err := cli.Put(ctx, "foo", strconv.Itoa(num)) cancel() if err != nil { log.Fatal(err) } num += 1 } } //output //PUT "foo" : "1" //PUT "foo" : "2" //PUT "foo" : "3" //PUT "foo" : "4" //。。。

其他细节 

type KV interface { Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error) Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error) Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error) Compact(ctx context.Context, rev int64, opts ...CompactOption) (*CompactResponse, error) Do(ctx context.Context, op Op) (OpResponse, error) Txn(ctx context.Context) Txn }

kv

//put操作 ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) _, err = cli.Put(ctx, "sample_key", "sample_value") cancel() if err != nil { log.Fatal(err) } ---------- //处理put的错误情况 ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) _, err = cli.Put(ctx, "", "sample_value") cancel() if err != nil { switch err { case context.Canceled: fmt.Printf("ctx is canceled by another routine: %vn", err) case context.DeadlineExceeded: fmt.Printf("ctx is attached with a deadline is exceeded: %vn", err) case rpctypes.ErrEmptyKey: fmt.Printf("client-side error: %vn", err) default: fmt.Printf("bad cluster endpoints, which are not etcd servers: %vn", err) } } // Output: client-side error: etcdserver: key is not provided ---------- //get操作 ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) resp, err := cli.Get(ctx, "foo") cancel() if err != nil { log.Fatal(err) } for _, ev := range resp.Kvs { fmt.Printf("%s : %sn", ev.Key, ev.Value) } // Output: foo : bar ---------- //get某key的某个历史版本 //presp.Header.Revision是int64类型,可以直接填入int64(1)、int64(2)等等获取对应历史版本 presp, err := cli.Put(context.TODO(), "foo", "bar1") if err != nil { log.Fatal(err) } _, err = cli.Put(context.TODO(), "foo", "bar2") if err != nil { log.Fatal(err) } ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) resp, err := cli.Get(ctx, "foo", clientv3.WithRev(presp.Header.Revision)) cancel() if err != nil { log.Fatal(err) } for _, ev := range resp.Kvs { fmt.Printf("%s : %sn", ev.Key, ev.Value) } // Output: foo : bar1 ---------- //排序取出 for i := range make([]int, 3) { ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) _, err = cli.Put(ctx, fmt.Sprintf("key_%d", i), "value") cancel() if err != nil { log.Fatal(err) } } ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) //获得以"key"为前缀的所有key,并以key为排序依据逆序取出 resp, err := cli.Get(ctx, "key", clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortDescend)) cancel() if err != nil { log.Fatal(err) } for _, ev := range resp.Kvs { fmt.Printf("%s : %sn", ev.Key, ev.Value) } // Output: // key_2 : value // key_1 : value // key_0 : value ---------- //delete // count keys about to be deleted gresp, err := cli.Get(ctx, "key", clientv3.WithPrefix()) if err != nil { log.Fatal(err) } // delete the keys dresp, err := cli.Delete(ctx, "key", clientv3.WithPrefix()) if err != nil { log.Fatal(err) } fmt.Println("Deleted all keys:", int64(len(gresp.Kvs)) == dresp.Deleted) // Output: // Deleted all keys: true ---------- //compact,删除某版本之前的历史修改 ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) resp, err := cli.Get(ctx, "foo") cancel() if err != nil { log.Fatal(err) } compRev := resp.Header.Revision // 选择一个版本,删除其之前的版本 ctx, cancel = context.WithTimeout(context.Background(), requestTimeout) _, err = cli.Compact(ctx, compRev) cancel() if err != nil { log.Fatal(err) } ---------- //txn,将几个请求放入一个事务中执行 kvc := clientv3.NewKV(cli) _, err = kvc.Put(context.TODO(), "key", "xyz") if err != nil { log.Fatal(err) } ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) _, err = kvc.Txn(ctx). If(clientv3.Compare(clientv3.Value("key"), ">", "abc")). Then(clientv3.OpPut("key", "XYZ")). // 因为"xyz" > "abc"所以执行了这一条,修改为"XYZ" Else(clientv3.OpPut("key", "ABC")). // 不执行 Commit() cancel() if err != nil { log.Fatal(err) } ---------- //do,不采用事务,执行多条指令 ops := []clientv3.Op{ clientv3.OpPut("put-key", "123"), clientv3.OpGet("put-key"), clientv3.OpPut("put-key", "456")} for _, op := range ops { if _, err := cli.Do(context.TODO(), op); err != nil { log.Fatal(err) } }

watch

func Example() { config := clientv3.Config{ Endpoints:[]string{"127.0.0.1:2379"}, DialTimeout:10*time.Second, } cli,err := clientv3.New(config) if err != nil {panic(err)} defer cli.Close() ------------------------------------------------------ //watch基本操作,监控对key的put、delete操作,并返回新值。put的值和之前相同也会返回 rch := cli.Watch(context.Background(), "foo") //返回一个channel类型 for wresp := range rch { //阻塞直到rch有值,然后等待下一个操作 for _, ev := range wresp.Events { fmt.Printf("%s %q : %qn", ev.Type, ev.Kv.Key, ev.Kv.Value) } } // PUT "foo" : "bar" } ---------- //watch以"foo"为前缀的key rch := cli.Watch(context.Background(), "foo", clientv3.WithPrefix()) for wresp := range rch { for _, ev := range wresp.Events { fmt.Printf("%s %q : %qn", ev.Type, ev.Kv.Key, ev.Kv.Value) } } ---------- // watche在['foo1', 'foo4')范围内的key。具体为foo1、foo2、foo3。 rch := cli.Watch(context.Background(), "foo1", clientv3.WithRange("foo4")) for wresp := range rch { for _, ev := range wresp.Events { fmt.Printf("%s %q : %qn", ev.Type, ev.Kv.Key, ev.Kv.Value) } } ---------- //ProgressNotify rch := cli.Watch(context.Background(), "foo", clientv3.WithProgressNotify()) wresp := <-rch fmt.Printf("wresp.Header.Revision: %dn", wresp.Header.Revision) fmt.Println("wresp.IsProgressNotify:", wresp.IsProgressNotify()) // wresp.Header.Revision: 0 // wresp.IsProgressNotify: true // IsProgressNotify returns true if the WatchResponse is progress notification

其他

func Examples() { cli, err := clientv3.New(clientv3.Config{ Endpoints:[]string{"127.0.0.1:2379"}, DialTimeout: dialTimeout, }) if err != nil { log.Fatal(err) } defer cli.Close() //cluster操作 --------------- resp, err := cli.MemberList(context.Background()) if err != nil { log.Fatal(err) } fmt.Println("members:", len(resp.Members)) // Output: members: 3 --------------- peerURLs := endpoints[2:] mresp, err := cli.MemberAdd(context.Background(), peerURLs) if err != nil { log.Fatal(err) } fmt.Println("added member.PeerURLs:", mresp.Member.PeerURLs) // added member.PeerURLs: [http://localhost:32380] -------------- resp, err := cli.MemberList(context.Background()) if err != nil { log.Fatal(err) } _, err = cli.MemberRemove(context.Background(), resp.Members[0].ID) if err != nil { log.Fatal(err) } ------------- resp, err := cli.MemberList(context.Background()) if err != nil { log.Fatal(err) } peerURLs := []string{"http://localhost:12380"} _, err = cli.MemberUpdate(context.Background(), resp.Members[0].ID, peerURLs) if err != nil { log.Fatal(err) } ------------------------------------------------------------- //lease,超时过期的key ------------- // minimum lease TTL is 5-second resp, err := cli.Grant(context.TODO(), 5) if err != nil { log.Fatal(err) } // after 5 seconds, the key 'foo' will be removed _, err = cli.Put(context.TODO(), "foo", "bar", clientv3.WithLease(resp.ID)) if err != nil { log.Fatal(err) } ------------- //不必等超时,立即使和resp.ID相关的key无效 _, err = cli.Revoke(context.TODO(), resp.ID) if err != nil { log.Fatal(err) } ------------- // 与resp.ID关联的key永久有效 ch, kaerr := cli.KeepAlive(context.TODO(), resp.ID) if kaerr != nil { log.Fatal(kaerr) } } ------------------------------------------------------------- //maintenance,维护 ------------- resp, err := cli.Status(context.Background(), "127.0.0.1:2379") if err != nil { log.Fatal(err) } fmt.Printf("endpoint: %s / Leader: %vn", "127.0.0.1:2379", resp.Header.MemberId == resp.Leader) //输出:endpoint: 127.0.0.1:2379 / Leader: true ------------- //删除大量key之后可以用此去除垃圾空间 if _, err = cli.Defragment(context.TODO(), 127.0.0.1:2379); err != nil { log.Fatal(err) } ------------------------------------------------------------ //metrics //待续。。。

 


推荐阅读
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 20211101CleverTap参与度和分析工具功能平台学习/实践
    1.应用场景主要用于学习CleverTap的使用,该平台主要用于客户保留与参与平台.为客户提供价值.这里接触到的原因,是目前公司用到该平台的服务~2.学习操作 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
author-avatar
红颜内
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有