go操作etcd

etcd

etcd简介

  • go开发的开源的、分布式的、高可用的kv存储系统
  • 可用于配置共享
  • 可用于服务的注册和发现

特点:

  • 完全复制:集群中每个节点都可以使用完整的存档
  • 高可用: etcd可避免点点问题可网络故障
  • 一致性:每次读取都会返回跨多主机的最新写入
  • 简单:包括一个定义良好、面向用户的api(grpc)
  • 安全:实现了可选的客户端证书身份验证的自动化TLS
  • 可靠:使用raft算法实现了强一致性、高可用的服务存储目录

1、put与get

package main
import (
"context"
    "fmt"
 clientv3 "go.etcd.io/etcd/client/v3"
)

func main(){
    cli,_:= clientv3.New(clientv3.Config{
        Endpoints:[]string{"127.0.0.1:2379"}
    })
    defer cli.Close()
    //添加kv
    _,_=cli.Put(context.TODO,"张三","DSHHASDAS")
    //根据key获取value
    resp,_:=cli.Get(context.TODO,"张三")
    for _,kv:=resp.Kvs{
        fmt.Printf("%s->%s\n",kv.Key,kv.Value)
    }
}

2、watch

package main


func main(){
     cli,_:= clientv3.New(clientv3.Config{
        Endpoints:[]string{"127.0.0.1:2379"}
    })
    defer cli.Close()
    _,_=cli.Put(context.TODO(),"张三","DSHHASDAS")
    resp,_:=cli.Watch(context.TODO,"张三")
    
}

3、设置一个租约

package main
import(
	"context"
    "fmt"
    clientv3 "go.etcd.io/etcd/client/v3"
)
func main(){
    cli,_:=clientv3.New(clientv3.Config{
        Endpoints:[]string{127.0.0.1:2379}
    })
    //设置一个租约
    lease,_:=cli.Grant(context.TODO,5)
    //将租约与kv绑定,租约到期kv失效
    _,_=cli.Put(context.TODO(),"ll","value",clientv3.WithLease(lease.ID))
    resp,_:=cli.Get(context.TODO(),"ll")
    for v:=range resp.Kvs{
        fmt.Println(v.Key,v.Value)
    }
}

4、keepAlive

package main
import(
	"context"
    "fmt"
	clientv3 "go.etcd.io/etcd/client/v3"
)
func main(){
    cli,_:=clientv3.New(clientv3.Config{
        Endpoints:[]string{"127.0.0.1:2379"}
    })
    //创建一个租期
    lease,_:=cli.Grant(context.TODO(),5)
    respch,_:=cli.KeepAlive(context.TODO(),lease.ID)
    for{
        v:=<-respch
        fmt.Println(v.ID)
    }
}

5、分布式锁

package main

import (
	"context"
	"fmt"

	"go.etcd.io/etcd/client/v3/concurrency"

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

func main() {
    cli, err := clientv3.New(clientv3.Config{
		Endpoints: []string{"123.249.105.59:2379"},
	})
	if err != nil {
		// handle error!
		fmt.Printf("connect to etcd failed, err:%v\n", err)
		return
	}
    _, _ = cli.Put(context.TODO(), "key", "value")
	session1, _ := concurrency.NewSession(cli)
	mutex1 := concurrency.NewMutex(session1, "key")
	session2, _ := concurrency.NewSession(cli)
	mutex2 := concurrency.NewMutex(session2, "key")
	_ = mutex1.Lock(context.TODO())
	ch := make(chan struct{})
	go func() {
		defer close(ch)
		//等待session1释放锁
		err2 := mutex2.Lock(context.TODO())
		if err2 != nil {
			fmt.Println("mutex2 lock failed")
		}
	}()
	err = mutex1.Unlock(context.TODO())
	if err != nil {
		fmt.Println("mutex1 unlock failed")
	}
	fmt.Println("mutex1 unlock")
	<-ch
	// session1的锁不释放,session2的上锁会一直阻塞
}

6、服务的naming与discovery

proto

syntax="proto3";
package nuts.echo.v1;
message EchoRequest {
  string request=1;
}
message EchoResponse {
  string response=1;
}

service EchoService{
  rpc Echo(EchoRequest)returns(EchoResponse){}
}

register

package main

import (
	"context"
	"fmt"
	"net"

	clientv3 "go.etcd.io/etcd/client/v3"

	"go.etcd.io/etcd/client/v3/naming/endpoints"

	"google.golang.org/grpc"

	echov1 "github.com/nuts/etcd_test/proto/service/nuts/echo/v1"
)

type Ser struct {
	echov1.UnimplementedEchoServiceServer
}

func (receiver Ser) Echo(ctx context.Context, request *echov1.EchoRequest) (*echov1.EchoResponse, error) {
	fmt.Printf("recv %s\n", request.GetRequest())
	return &echov1.EchoResponse{Response: "hello!" + request.GetRequest()}, nil
}

func main() {
	conn, err := net.Listen("tcp", ":8080")
	if err != nil {
		fmt.Println("create conn failed")
		return
	}

	defer conn.Close()
	server := grpc.NewServer()
	//注册服务
	echov1.RegisterEchoServiceServer(server, &Ser{})
	cli, err := clientv3.New(clientv3.Config{
		Endpoints: []string{"127.0.0.1:2379"},
	})
	if err != nil {
		fmt.Println("create etcd client failed!")
		return
	}
	defer cli.Close()
	//向etcd注册一个服务终端
	mg, err := endpoints.NewManager(cli, "nuts/v1/EchoService")
	if err != nil {
		fmt.Println("create terminal failed!")
		return
	}
	err = mg.AddEndpoint(context.TODO(), "nuts/v1/EchoService/echo", endpoints.Endpoint{Addr: "127.0.0.1:8080"})
	if err != nil {
		fmt.Println(" add endpoint to etcd failed!")
		return
	}
	_ = server.Serve(conn)
}

discovery

package main

import (
	"context"
	"fmt"

	"google.golang.org/grpc/credentials/insecure"

	echov1 "github.com/nuts/etcd_test/proto/service/nuts/echo/v1"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/client/v3/naming/resolver"
	"google.golang.org/grpc"
)
func main() {

	cli, _ := clientv3.NewFromURL("127.0.0.1:2379")
	etcdResolver, err := resolver.NewBuilder(cli)
	if err != nil {
		fmt.Println("create resolver failed!")
		return
	}
	conn, err := grpc.Dial("etcd:///nuts/v1/EchoService",
		grpc.WithResolvers(etcdResolver),
		//grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		fmt.Println("create grpc client failed!")
		return
	}
	client := echov1.NewEchoServiceClient(conn)
	resp, _ := client.Echo(context.TODO(), &echov1.EchoRequest{Request: "张三"})
	fmt.Println(resp.GetResponse())
}

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值