检查etcd服务列表
使用 etcdctl.exe member list 命令查看集群列表:
D:\etcd\etcd-v3.3.25-windows-amd64>etcdctl.exe member list 19ac17627e3e396f: name=etcd03 peerURLs=http://127.0.0.1:2382 clientURLs=http://127.0.0.1:4379 isLeader=false bf9071f4639c75cc: name=etcd01 peerURLs=http://127.0.0.1:2380 clientURLs=http://127.0.0.1:2379 isLeader=true e7b968b9fb1bc003: name=etcd02 peerURLs=http://127.0.0.1:2381 clientURLs=http://127.0.0.1:3379 isLeader=false
如果出现如下的信息,代表可能etcd启动过程阻塞住了,只要在cmd窗口里按下回车键就ok了
D:\etcd\etcd-v3.3.25-windows-amd64>etcdctl.exe member list client: etcd cluster is unavailable or misconfigured; error #0: dial tcp 127.0.0.1:4001: connectex: No connection could be made because the target machine actively refused it. ; error #1: client: endpoint http://127.0.0.1:2379 exceeded header timeout
或者使用curl访问或网页输入查看http://127.0.0.1:2379/v2/members:
curl http://127.0.0.1:2379/v2/members
返回以下结果(3个节点):
{ "members": [{ "id": "19ac17627e3e396f", "name": "etcd03", "peerURLs": ["http://127.0.0.1:2382"], "clientURLs": [] }, { "id": "bf9071f4639c75cc", "name": "etcd01", "peerURLs": ["http://127.0.0.1:2380"], "clientURLs": ["http://127.0.0.1:2379"] }, { "id": "e7b968b9fb1bc003", "name": "etcd02", "peerURLs": ["http://127.0.0.1:2381"], "clientURLs": ["http://127.0.0.1:3379"] }] }
在任意节点执行健康检查,查看集群状态:
(注:仅etcdctl 有v2和v3两种api,注意区别),关于v3 api的用法,参见etcdctl的使用[v3版本]:
https://blog.csdn.net/huwh_/article/details/80225902
v2下;
etcdctl cluster-health
v3下:
etcdctl endpoint health --endpoints=$ENDPOINTS etcdctl endpoint health --cluster=true
etcd的go客户端的简单操作:
package main import ( "context" "fmt" "time" "github.com/coreos/etcd/clientv3" ) func main() { //客户端配置 config := clientv3.Config{ Endpoints: []string{"127.0.0.1:2379"}, DialTimeout: 5 * time.Second, } //建立连接 client, err := clientv3.New(config) defer client.Close() if err != nil { fmt.Println(err) return } fmt.Println("connect success") //控制超时 ctx, cancel := context.WithTimeout(context.Background(), time.Second) //1. 增-存值 _, err = client.Put(ctx, "/demo/demo1_key", "demo1_value") //操作完毕,cancel掉 cancel() if err != nil { fmt.Println("put failed, err:", err) return } //2. 查-获取值, 也设置超时 ctx, cancel = context.WithTimeout(context.Background(), time.Second) resp, err := client.Get(ctx, "/demo/demo1_key") // Get查询还可以增加WithPrefix选项,获取某个目录下的所有子元素 //eg: resp, err := client.Get(ctx, "/demo/", clientv3.WithPrefix()) cancel() if err != nil { fmt.Println("get failed err:", err) return } for _, item := range resp.Kvs { //Kvs 返回key的列表 fmt.Printf("%s : %s \n", item.Key, item.Value) } //3. 改-修改值 ctx, _ = context.WithTimeout(context.Background(), time.Second) _,err = client.Put(ctx, "/demo/demo1_key", "update_value", clientv3.WithPrevKV()) if err != nil { fmt.Println("get failed err: ", err) } //fmt.Println(string(resp.PrevKv.Value)) //4. 删-删除值 ctx, _ = context.WithTimeout(context.Background(), time.Second) _, err = client.Delete(ctx, "/demo/demo1_key") if err != nil { fmt.Println(err) } //fmt.Println(resp.PrevKvs) }
zRPC的简单使用
zRPC来自于最近比较火的一个微服务框架go-zero。go-zero是一个集成了各种工程实践的包含了Web和RPC协议的功能完善的微服务框架,zRPC是其中的一个可独立使用的模块。
zRPC地址:https://github.com/tal-tech/go-zero/tree/master/zrpc
zRPC底层依赖gRPC,内置了服务注册、负载均衡、拦截器等模块,其中还包括自适应降载,自适应熔断,限流等微服务治理方案,是一个简单易用的可直接用于生产的企业级RPC框架。
zRPC支持直连和基于etcd服务发现两种方式,我们以基于etcd做服务发现为例演示zRPC的基本使用:
配置
创建hello.yaml配置文件,配置如下:
Name: hello.rpc // 服务名 ListenOn: 127.0.0.1:9090 // 服务监听地址 Etcd: Hosts: - 127.0.0.1:2379 // etcd服务地址 Key: hello.rpc // 服务注册key
注意文件编码必须为utf-8,格式也要正确。
创建hello.proto文件,并生成对应的go代码。
生成go代码:
protoc --go_out=plugins=grpc:. hello.proto
protoc的安装,https://github.com/protocolbuffers/protobuf/releases
从 Protobuf Releases 下载最先版本的发布包安装即可,可放到go的bin目录内全局使用。
下载protobuf编译器所需插件
用git下载protoc在go下运行所需插件(执行): go get github.com/golang/protobuf(gopath的bin目录会生成protoc-gen-go.exe)
proto文件标量类型
proto类型 | go类型 | 备注 | proto类型 | go类型 | 备注 |
double | float64 | float | float32 | ||
int32 | int32 | int64 | int64 | ||
uint32 | uint32 | uint64 | uint64 |
sint32 | int32 | 适合负数 | sint64 | int64 | 适合负数 |
fixed32 | uint32 | 固长编码,适合大于2^28的值 | fixed64 | uint64 | 固长编码,适合大于2^56的值 |
sfixed32 | int32 | 固长编码 | sfixed64 | int64 | 固长编码 |
bool | bool | string | string | UTF8 编码,长度不超过 2^32 | |
bytes | []byte | 任意字节序列,长度不超过 2^32 |
标量类型如果没有被赋值,则不会被序列化,解析时,会赋予默认值。
- strings:空字符串
- bytes:空序列
- bools:false
- 数值类型:0
简单示例:
syntax = "proto3"; package pb; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
服务端:
Server端代码:
package main import ( "context" "flag" "log" "testzrpc/msgs/zrpc/pb" "github.com/tal-tech/go-zero/core/conf" "github.com/tal-tech/go-zero/zrpc" "google.golang.org/grpc" ) type Config struct { zrpc.RpcServerConf } var cfgFile = flag.String("f", "./hello.yaml", "cfg file") func main() { flag.Parse() var cfg Config conf.MustLoad(*cfgFile, &cfg) srv, err := zrpc.NewServer(cfg.RpcServerConf, func(s *grpc.Server) { pb.RegisterGreeterServer(s, &Hello{}) }) if err != nil { log.Fatal(err) } srv.Start() } type Hello struct{} func (h *Hello) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { return &pb.HelloReply{Message: "server say,hello " + in.Name}, nil }
需要注意的是:
需要更改下go.mod文件中的grpc版本号。默认最新的1.34,启动服务端会报错的,可改为使用v1.29.1
etcd/clientv3库跟最新的grpc版本不兼容,需要降低 grpc
版本,如1.26.0。
客户端:
package main import ( "context" "log" "testzrpc/msgs/zrpc/pb" "github.com/tal-tech/go-zero/core/discov" "github.com/tal-tech/go-zero/zrpc" ) func main() { client := zrpc.MustNewClient(zrpc.RpcClientConf{ Etcd: discov.EtcdConf{ Hosts: []string{"127.0.0.1:2379"}, Key: "hello.rpc", }, }) conn := client.Conn() hello := pb.NewGreeterClient(conn) reply, err := hello.SayHello(context.Background(), &pb.HelloRequest{Name: "go-zero aaaa"}) if err != nil { log.Fatal(err) } log.Println(reply.Message) }
多个微服务如何使用?如何实现负载均衡和容灾。做个试验,把server.go复制一份,改为server1.go,
把hello.yaml复制一份改为hello1.yaml,改hello1.yaml中的ListenOn,端口变为9091,这时候把server.go和server1.go同时运行起来,看一下:
此时,运行下客户端,发现输出为:
再把server1.go服务停掉,运行下客户端试试输出为:
综上,使用zRPC挺简单的,并且zRPC内置了服务注册、负载均衡、拦截器等模块。
其中还包括自适应降载,自适应熔断,限流等微服务治理方案,是一个简单易用的可直接用于生产的企业级RPC框架。