golang工程 grpc resovler简介

resovler 服务名称解析

grpc微服务部署的时候,访问对应服务肯定不可能用ip的形式去访问,尤其云环境下,ip经常变动。采用resovler可以让我们客户端动态的去获取服务的地址去访问rpc服务。可以搭配服务中心来使用。具体框架图如下

在这里插入图片描述

resolver

例子如下,nameServer部分可以替换成地址数组即可,实际环境中就是向另一个服务器拿服务的地址

name_resolver.go

package client

import (
	"context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/resolver"
	"grpc/name"
	"log"
	"time"
)

const (
	MySchema = "myschema"
	MyServiceName = "myecho"
)

//var adddrs = []string{"localhost:50053", "localhost:50054", "localhost:50055"}

type MyResolverBuilder struct {
}



func GetNameResolver(ns *NameServer) grpc.DialOption {
	nameServer = ns
	return grpc.WithResolvers(&MyResolverBuilder{})
}

func (*MyResolverBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
	r := &MyResolver{
		target: target,
		cc: cc,
		addrsStore: map[string][]string{MyServiceName: nameServer.getAddressByServiceName(MyServiceName)},
	}
	r.start()
	return r, nil
}

func (r *MyResolver) start() {
	// 集合地址 转resolver addrs
	log.Println("resolver start")
	addrStrs := r.addrsStore[r.target.Endpoint()]
	addrs := make([]resolver.Address, len(addrStrs))
	for i,s := range addrStrs {
		addrs[i] = resolver.Address{
			Addr: s,
		}
	}
	// 更新客户端连接地址
	r.cc.UpdateState(resolver.State{
		Addresses: addrs,
	})
}

func (*MyResolverBuilder) Scheme() string {
	return MySchema
}

type MyResolver struct {
	target resolver.Target
	cc resolver.ClientConn
	addrsStore map[string][]string
}

func (r *MyResolver)ResolveNow(o resolver.ResolveNowOptions) {
	log.Println("resolver now")
	// 在服务,连接中断的时候,做一次名称解析
	log.Println(r.cc)
	// 重新获取可用的服务地址
	r.addrsStore = map[string][]string{MyServiceName: nameServer.getAddressByServiceName(MyServiceName)}
	// 更新连接状态
	r.start()
	log.Println("update:", r.cc)
}

func (r *MyResolver) Close() {
	nameServer.Close()
}

type NameServer struct {
	conn *grpc.ClientConn
}

var nameServer *NameServer
// NewNameServer 创建连接名称服务器连接
func NewNameServer(addr string) *NameServer {
	defer func() {
		if err := recover(); err != nil {
			log.Println(err)
		}
	}()
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))

	if err != nil {
		log.Fatalln(err)
	}

	return &NameServer{
		conn: conn,
	}
}

func (ns *NameServer) Close() {
	defer func() {
		if err := recover(); err != nil {
			log.Println(err)
		}
	}()
	ns.conn.Close()

}
func (ns *NameServer) RegisterName(serviceName, address string) {
	defer func() {
		if err := recover(); err != nil {
			log.Println(err)
		}
	}()
	client := name.NewNameClient(ns.conn)
	in := &name.NameRequest{
		ServiceName: serviceName,
		Address: []string{address},
	}

	_, err := client.Register(context.Background(), in)
	if err != nil {
		log.Fatalln(err)
	}
}

func (ns *NameServer) DeleteName(serviceName, address string) {
	defer func() {
		if err := recover(); err != nil {
			log.Println(err)
		}
	}()
	client := name.NewNameClient(ns.conn)
	in := &name.NameRequest{
		ServiceName: serviceName,
		Address: []string{address},
	}

	_, err := client.Delete(context.Background(), in)
	if err != nil {
		log.Fatalln(err)
	}
}

func (ns *NameServer) Keepalive(serviceName, address string) {
	defer func() {
		if err := recover(); err != nil {
			log.Println(err)
		}
	}()
	client := name.NewNameClient(ns.conn)
	in := &name.NameRequest{
		ServiceName: serviceName,
		Address: []string{address},
	}

	stream, err := client.Keepalive(context.Background())
	if err != nil {
		log.Fatalln(err)
		return
	}

	for {
		err := stream.Send(in)
		if err != nil {
			log.Fatalln(err)
		}
		time.Sleep(time.Second * 2)
	}

}

func (ns *NameServer) getAddressByServiceName(serviceName string) []string {
	defer func() {
		if err := recover(); err != nil {
			log.Println(err)
		}
	}()

	client := name.NewNameClient(ns.conn)
	in := &name.NameRequest{
		ServiceName: serviceName,
	}

	res, err := client.GetAddress(context.Background(), in)
	if err != nil {
		log.Println(err)
		return []string{}
	}
	log.Println(res.Address)
	return res.Address
}

client.go

package main

import (
    "flag"
    "fmt"
    "google.golang.org/grpc"
    "grpc/echo"
    "grpc/echo-client-practice/client"
    "log"
    "time"
)


func getDiaOption() []grpc.DialOption {
    dialOptions := make([]grpc.DialOption, 0)
    dialOptions = append(dialOptions, client.GetMTlsOpt())

    dialOptions = append(dialOptions, grpc.WithUnaryInterceptor(client.UnaryInterceptor))
    dialOptions = append(dialOptions, grpc.WithStreamInterceptor(client.StreamInterceptor))
    dialOptions = append(dialOptions, client.GetAuth(client.FetchToken()))
    dialOptions = append(dialOptions, client.GetKeepAliveOpt())
    
    // 服务名称配置
    dialOptions = append(dialOptions, client.GetNameResolver(client.NewNameServer("localhost:60051")))
    return dialOptions
}

func main() {
    flag.Parse()


    // 根据协议+服务名 通过服务名称解析 访问服务器
    conn, err := grpc.Dial(fmt.Sprintf("%s:///%s", client.MySchema, client.MyServiceName), getDiaOption()...)

    if err != nil {
        log.Fatal(err)
    }

    defer conn.Close()
    c := echo.NewEchoClient(conn)
    fmt.Println("1")
    client.CallUnary(c)
    time.Sleep(5 * time.Second)
    fmt.Println("2")
    client.CallUnary(c)
    time.Sleep(5 * time.Second)
    fmt.Println("3")
    client.CallUnary(c)
    time.Sleep(5 * time.Second)
    fmt.Println("4")
    client.CallUnary(c)
    //client.CallServerStream(c)
    //client.CallClientSteam(c)
    //client.CallBidirectional(c)
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值