铁匠 铁匠
首页
golang
java
架构
常用算法
  • Java
  • nginx
  • 系统运维
  • 系统安全
  • mysql
  • redis
参考文档
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

铁匠

不予评判的专注当下
首页
golang
java
架构
常用算法
  • Java
  • nginx
  • 系统运维
  • 系统安全
  • mysql
  • redis
参考文档
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • golang 入门学习指南
  • go-kit

    • go-kit学习指南 - 基础概念和架构
    • go-kit学习指南 - 多协议支持
    • go-kit学习指南 - 中间件
    • go-kit开发微服务 - 服务注册与发现
      • 介绍
      • 实现步骤
        • 准备工作
        • 服务注册(服务端)
        • 服务发现(客户端)
  • go
  • go-kit
fengjx
2024-04-19
目录

go-kit开发微服务 - 服务注册与发现

# 介绍

go-kit 内置了多种注册中心支持,包括:

  • consul (opens new window)
  • dnssrv (opens new window)
  • etcd (opens new window)
  • eureka (opens new window)
  • zookeeper (opens new window)

以下以etcd3为例,实现服务注册与发现功能。

# 实现步骤

# 准备工作

安装 etcd:https://etcd.io/docs/v3.5/install/ (opens new window)

# 服务注册(服务端)

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/go-kit/kit/endpoint"
	kitlog "github.com/go-kit/kit/log"
	"github.com/go-kit/kit/sd/etcdv3"
	httptransport "github.com/go-kit/kit/transport/http"
)

func main() {
	var (
		etcdServer = "192.168.1.200:2379"
		prefix     = "/services/greetsv/"
		instance   = "192.168.1.164:8080"
		key        = prefix + instance
		value      = "http://" + instance
		ctx        = context.Background()
	)
	// 创建 etcd 客户端连接
	options := etcdv3.ClientOptions{
		DialTimeout:   time.Second,
		DialKeepAlive: time.Second * 30,
	}
	cli, err := etcdv3.NewClient(ctx, []string{etcdServer}, options)
	if err != nil {
		log.Panic(err)
	}
	// 创建日志记录器
	var logger kitlog.Logger
	logger = kitlog.NewLogfmtLogger(os.Stderr)
	logger = kitlog.With(logger, "ts", kitlog.DefaultTimestampUTC)
	// 创建注册与发现中间件
	r := etcdv3.NewRegistrar(cli, etcdv3.Service{
		Key:   key,
		Value: value,
	}, logger)
	r.Register()
	defer r.Deregister()

	svc := greetService{}
	satHelloHandler := httptransport.NewServer(
		makeHelloEndpoint(svc),
		decodeRequest,
		encodeResponse,
	)

	http.Handle("/say-hello", satHelloHandler)
	log.Println("http server start")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

type helloReq struct {
	Name string `json:"name"`
}

type helloResp struct {
	Msg string `json:"msg"`
}

type greetService struct {
}

func (svc greetService) SayHi(_ context.Context, name string) string {
	return fmt.Sprintf("hi: %s", name)
}

func makeHelloEndpoint(svc greetService) endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (interface{}, error) {
		req := request.(*helloReq)
		msg := svc.SayHi(ctx, req.Name)
		return helloResp{
			Msg: msg,
		}, nil
	}
}

func decodeRequest(_ context.Context, r *http.Request) (interface{}, error) {
	name := r.URL.Query().Get("name")
	req := &helloReq{
		Name: name,
	}
	return req, nil
}

func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
	data := map[string]any{
		"status": 0,
		"msg":    "ok",
		"data":   response,
	}
	return json.NewEncoder(w).Encode(data)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

启动服务

go run main.go
1

# 服务发现(客户端)

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/go-kit/kit/endpoint"
	kitlog "github.com/go-kit/kit/log"
	"github.com/go-kit/kit/sd"
	"github.com/go-kit/kit/sd/etcdv3"
	"github.com/go-kit/kit/sd/lb"
	httptransport "github.com/go-kit/kit/transport/http"
)

func main() {
	var (
		etcdServer = "192.168.1.200:2379"
		prefix     = "/services/greetsvc/"
		ctx        = context.Background()
	)
	// 创建 etcd 客户端连接
	options := etcdv3.ClientOptions{
		DialTimeout:   time.Second,
		DialKeepAlive: time.Second * 30,
	}
	cli, err := etcdv3.NewClient(ctx, []string{etcdServer}, options)
	if err != nil {
		log.Panic(err)
	}

	logger := kitlog.NewNopLogger()
	instancer, err := etcdv3.NewInstancer(cli, prefix, logger)
	if err != nil {
		panic(err)
	}

	factory := func(instance string) (endpoint.Endpoint, io.Closer, error) {
		u, err := url.Parse(instance)
		if err != nil {
			return nil, nil, err
		}
		httpcli := httptransport.NewClient(http.MethodPost, u, encodeRequest, decodeResponse)
		return httpcli.Endpoint(), nil, nil
	}

	endpointer := sd.NewEndpointer(instancer, factory, logger)
	balancer := lb.NewRoundRobin(endpointer)
	retry := lb.Retry(3, 3*time.Second, balancer)

	req := &helloReq{
		Name: "fengjx",
	}
	resp, err := retry(ctx, req)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("resp: %v", resp)
}

type helloReq struct {
	Name string `json:"name"`
}

type helloResp struct {
	Msg string `json:"msg"`
}

type Data[T any] struct {
	Status int    `json:"status"`
	Msg    string `json:"msg"`
	Data   T      `json:"data"`
}

func encodeRequest(_ context.Context, r *http.Request, request interface{}) error {
	req := request.(*helloReq)
	r.Method = http.MethodGet
	r.URL.Path = "/say-hello"
	q := r.URL.Query()
	q.Set("name", req.Name)
	r.URL.RawQuery = q.Encode()
	return nil
}

func decodeResponse(_ context.Context, response *http.Response) (interface{}, error) {
	if response.StatusCode != 200 {
		return nil, fmt.Errorf("response code: %d\r\n", response.StatusCode)
	}
	data := &Data[helloResp]{}
	err := json.NewDecoder(response.Body).Decode(data)
	if err != nil {
		return nil, err
	}
	return data.Data.Msg, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

请求服务端接口

$ go run cli/main.go
2024/04/21 17:33:32 resp: hi: fengjx
1
2
#go-kit
Last Updated: 2024/05/12, 15:25:49
go-kit学习指南 - 中间件

← go-kit学习指南 - 中间件

最近更新
01
go-kit学习指南 - 多协议支持
04-19
02
go-kit学习指南 - 中间件
04-19
03
go-kit学习指南 - 基础概念和架构
04-18
更多文章>
Theme by Vdoing | Copyright © 2016-2024 铁匠 | 粤ICP备15021633号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式