• 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

  • 相关阅读:
    字符串编码之一:字符串语法
    PHP进阶学习系列1:字符串编码提纲
    关于技术成长的一些反思
    Yii2学习笔记002---Yii2的控制器和视图
    PHP5.3--PHP7 新特性总结
    计算机软考笔记之《数据库基础》
    计算机软考笔记之《文件结构》
    计算机软考笔记之《抽象数据类型(ADT)》
    计算机软考笔记之《数据压缩》
    计算机软考笔记之《数据结构与算法》
  • 原文地址:https://www.cnblogs.com/pythonwl/p/15802868.html
Copyright © 2020-2023  润新知