GO —— PUT, GET, watch,lease,keepalive,分布式锁 实现

package main

import (
	"fmt"
	"context"
	"time"
	"github.com/coreos/etcd/clientv3"
    // "github.com/coreos/etcd/clientv3/concurrency"
	"log"
)

func main(){
		cli, err := clientv3.New(clientv3.Config{
			Endpoints: []string{"10.228.23.144:20004"},
			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
		// fmt.Println("on watch ...")
		// rch := cli.Watch(context.Background(), "aaa")
		// 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)
		// 	}
		// }

		// lease
		// fmt.Println("create lease put")
		// resp, err := cli.Grant(context.TODO(), 10)
		// if err != nil {
		// 	fmt.Printf("create lease err: %v", err)
		// }
		// kkk, err := cli.Put(context.TODO(), "/zzz/", "wl", clientv3.WithLease(resp.ID))
		// if err != nil{
		// 	fmt.Printf("put lease err: %v", err)
		// }
		// fmt.Println("put result: ", kkk)

		// keepalive
		// fmt.Println("lease keepalive")
		// ch, keer := cli.KeepAlive(context.TODO(), resp.ID)
		// if keer != nil {
		// 	fmt.Printf("keepalive lease err: %v", keer)
		// }
		// fmt.Println("keepalive lease ...")
		// for {
		// 	ka := <- ch
		// 	fmt.Println("ttl:", ka.TTL)
		// }

		// 分布式锁

		// // 创建两个单独的会话 锁竞争
		// s1, err := concurrency.NewSession(cli)
		// if err != nil{
		// 	log.Fatal("s1 err: %v", err)
		// }
		// defer s1.Close()
		// m1 := concurrency.NewMutex(s1, "/my_lock/")
		
		// s2, err := concurrency.NewSession(cli)
		// if err != nil{
		// 	log.Fatal("s2 err: %v", err)
		// }
		// defer s2.Close()
		// m2 := concurrency.NewMutex(s2, "/my_lock/")

		// // 会话 s1 获取锁
		// if err := m1.Lock(context.TODO()); err != nil{
		// 	log.Fatal("s1 lock err: %v", err)
		// }
		// fmt.Println("acquired lock for s1")

		// go func(){
		// 	// 直到 s1 释放 /my_lock/ 锁
		// 	if err := m2.Lock(context.TODO());err != nil{
		// 		log.Fatal("s2 lock err: %v", err)
		// 	}
		// }()

		// if err := m1.Unlock(context.TODO());err != nil {
		// 	log.Fatal("m1 unlock err: %v", err)
		// }
		// fmt.Println("realeased lock for s1")

		// fmt.Println("acquired lock for s2")

		// // 带租约的分布式锁
		// res, err := cli.Grant(context.Background(),20)
		// if err != nil{
		// 	log.Fatal(err)
		// }
		// fmt.Println("s1 wait lock...")
		//  // ss1, err := concurrency.NewSession(cli,  concurrency.WithTTL(1))给创建的session一个1s的alive时期,即如果task1所在的进程挂掉,则ss1会被server在1s后关掉,这样task2就能立即获取成功锁
		// // concurrency.WithContext(context.Background())使用该参数生成session会默认在task1所在的进程挂掉,则ss1会被server在60s后关掉,这样task2就能立即获取成功锁.
		// // 所以若想让task2立即获取锁则应该使用
		// // ss1, err := concurrency.NewSession(cli,  concurrency.WithTTL(1))
		// s1, err := concurrency.NewSession(cli, concurrency.WithLease(res.ID))
		// if err != nil{
		// 	log.Fatal(err)
		// }
		// m1 := concurrency.NewMutex(s1, "/kkk/")
		// if err := m1.Lock(context.Background()); err != nil{
		// 	log.Fatal(err)
		// }
		// fmt.Println("s1 get lock")
		// s1.Orphan()  // 直到租约到期,才释放锁

		// fmt.Println("s2 wait lock...")

		// s2, err := concurrency.NewSession(cli)
		// if err != nil {
		// 	log.Fatal(err)
		// }
		// m2 := concurrency.NewMutex(s2, "/kkk/")
		// // 获取锁使用context.Background()会一直获取锁直到获取成功
		// // 如果这里使用context.WithTimeout(context.Background(), 10*time.Second)
		// // 表示获取锁10s如果没有获取成功则返回error。
		// if err := m2.Lock(context.Background()); err != nil{
		// 	log.Fatal(err)
		// }
		// fmt.Println("s2 get lock")

		// PUT GET
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		put_r, err := cli.Put(ctx, "/abc/", "abc")
		fmt.Println(put_r)
		fmt.Println(cancel)
		cancel()
		if err != nil{
			log.Fatal(err)
		}
		ctx, cancel = context.WithTimeout(context.Background(), time.Second)
		resp, err := cli.Get(ctx, "/abc/")
		cancel()
		if err != nil{
			log.Fatal(err)
		}
		for i, ev := range resp.Kvs{
			fmt.Println(i,string(ev.Key),string(ev.Value))
		}
		/*
		1. context包的WithTimeout()函数接受一个 Context 和超时时间作为参数,返回其子Context和取消函数cancel
		2. 若不调用cancel函数,到了原先创建Contetx时的超时时间,它也会自动调用cancel()函数,即会往子Context的Done通道发送消息
		*/
}

参考链接:https://www.topgoer.com/数据库操作/go操作etcd/操作etcd.html
参考链接:https://www.jianshu.com/p/aaefc8e1ffcb
参考链接:https://blog.csdn.net/yzf279533105/article/details/107292247

posted @ 2022-01-14 17:45  pythoner_wl  阅读(90)  评论(0编辑  收藏  举报