kit是一个能够自动生成基于go-kit组件的框架,可以帮助我们快速创建微服务,而让我们只关注自己的业务逻辑和中间件实现。

仓库地址 github.com/kujtimiihoxha/kit

1 生成命令

// 1. 创建一个service模板
kit new service hello //kit n s hello
------
// 2. 编辑hello/pkg/service/service.go添加service
type HelloService interface {// Add your methods here// e.x: Foo(ctx context.Context,s string)(rs string, err error)Foo(ctx context.Context, s string) (rs string, err error)Test(ctx context.Context, s string, i int64) (string, error)
}
// 3. 创建transport、endpoint、service层
kit g s hello --dmw
//生成service目录结构
hello
├── cmd
│   ├── service
│   │   ├── service.go
│   │   └── service_gen.go
│   └── main.go
└── pkg├── endpoint //endpoint layer│   ├── endpoint.go│   ├── endpoint_gen.go│   └── middleware.go├── http //transport layer│   ├── handler.go│   └── handler_gen.go└── service //service layer├── middleware.go└── service.go
// 4. 生成client library
kit g c hello
// 生成client目录结构
hello
└── client└── http└── http.go  //client library

2 代码解释(http)

主要讲讲kit生成的transport层、endpoint层、service层分别是怎么实现的,又是怎么协同工作的。最后解释下service/middleware endpoint/middleware的工作原理。

go-kit的调用关系:
client访问微服务http server;经过transport层是decode获得http包request数据;然后交个endpoint处理,endpoint在go-kit是一个重要的概念,代表了一个可执行的服务,表现形式是一个函数type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error);endpoint将request传给业务函数处理,返回response,最后在一层层返回给client。

这里顺便解释下middleware,endpoint的middleware会在endpoint调用业务函数之前处理,service的middleware由service逻辑自己决定。

clientserver

decode
encode
call
return
host:port/request
response
client
transport
endpoint
service

下面的解释基于上面服务里面的两个业务:Foo/Test

transport层

http通过ListenAndServer监听连接,连接产生时转交给http.Handler处理,transport的核心就是将endpoint、decodeReq、encodeResp告诉http.Handler

比如下面的代码,处理路由为/foo的业务,"github.com/go-kit/kit/transport/http".NewServer创建一个server,里面包含一个http.Handler的实现。

// makeFooHandler creates the handler logic
func makeFooHandler(m *http.ServeMux, endpoints endpoint.Endpoints, options []http1.ServerOption) {m.Handle("/foo", http1.NewServer(endpoints.FooEndpoint, decodeFooRequest, encodeFooResponse, options...))
}

http.Handler的实现

在文件/go-kit/kit/transport/http/server.go 中的ServeHTTP(w http.ResponseWriter, r *http.Request),核心代码为:

// Server wraps an endpoint and implements http.Handler.
type Server struct {e            endpoint.Endpointdec          DecodeRequestFuncenc          EncodeResponseFuncbefore       []RequestFuncafter        []ServerResponseFuncerrorEncoder ErrorEncoderfinalizer    []ServerFinalizerFunclogger       log.Logger
}// ServeHTTP implements http.Handler.
func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {ctx := r.Context() //request.Contextrequest, err := s.dec(ctx, r) //decode requestresponse, err := s.e(ctx, request) //endpoint function calls.enc(ctx, w, response) //encode response
}

endpoint层

endpoint本质是一个处理函数类型,代表了一个RPC方法,每个服务需要针对服务进行具体实现
type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error),下面是一个实现的例子:

func MakeFooEndpoint(s service.HelloService) endpoint.Endpoint {return func(ctx context.Context, request interface{}) (interface{}, error) {req := request.(FooRequest)rs, err := s.Foo(ctx, req.S)return FooResponse{Err: err,Rs:  rs,}, nil}
}

然后通过传入service创建endpoint:

func New(s service.HelloService) Endpoints {eps := Endpoints{FooEndpoint:  MakeFooEndpoint(s),TestEndpoint: MakeTestEndpoint(s),}return eps
}

然后传入一个service创建一个endpoint实例:

svc := service.New() // service 部分会介绍
eps := endpoint.New(svc)

最后将endpoint实例传给上面的"github.com/go-kit/kit/transport/http".NewServer(),创建一个http.Handler()实现。

service层

service.go应该是go-kit里面最好理解的一层,也是定义业务最纯粹的地方,所有的业务定义在RPC接口HelloService中。

type HelloService interface {Foo(ctx context.Context, s string) (rs string, err error)Test(ctx context.Context, s string, i int64) (string, error)
}

实现接口

type basicHelloService struct{}func (b *basicHelloService) Foo(ctx context.Context, s string) (rs string, err error) {return rs, err
}
func (b *basicHelloService) Test(ctx context.Context, s string, i int64) (s0 string, e1 error) {return s0, e1
}

创建service

func New() HelloService {return &basicHelloService{}
}

启动一个微服务的详细流程

import http1 "github.com/go-kit/kit/transport/http"// 1. 创建一个service,此service为当前目录下service包
var svc HelloService = service.New()// 2. 创建一个Endpoints,此endpoint为当前目录下的endpoint包
eps := endpoint.New(svc) // 3. 创建一个microserver
//   3.1 创建http.Handler
//这里省略(decodeFooRequest和encodeFooResponse实现)
// type DecodeRequestFunc func(context.Context, *http.Request) (request interface{}, err error)
// type EncodeResponseFunc func(context.Context, http.ResponseWriter, interface{}) error
serv := http1.NewServer(eps.FooEndpoint, decodeFooRequest, encodeFooResponse, options...)
//   3.2 创建Mux server
mux := http.NewServeMux()
mux.Handle("/foo", serv)
//   3.3 启动微服务server
http.ListenAndServe("localhost:8080", mux)

3 middleware(service/endpoint)

middleware模块应该是go-kit最强大的地方,middleware通常是一个chain处理,比如go-kit中对于endpoint层的Middleware的定义endpoint.Middleware => type Middleware func(Endpoint) Endpoint。endpoint的middleware通常是对request做一些预处理,比如对header中的Authorization的处理。

对于service层的Middleware的定义需要根据service本身的业务接口定义,比如HelloService的Middleware可以定义为type Middleware func(HelloService) HelloService。go-kit提供了一些供service用的middleware组件。
通常service Middleware的实现是用对基类HelloService的扩展来实现的,比如

type loggingMiddleware struct {logger log.Loggernext   HelloService
}

这样就可以传入一个Base HelloService而返回一个loggingMiddleware,比如func(HelloService) loggingMiddleware

对于transport层没有明确是说明是middleware,但是可以添加option,比如记录log,trace等。

含有middleware的endpoint和service是go-kit的服务的标准创建方式,也就是说上面的介绍为了理解简化了创建流程,接下来将详细介绍含有middleware的服务创建。

包含middleware的服务创建流程

由于middleware的创建有些绕,这里先给出一个具体的service的创建的主要流程,将忽略具体的业务的实现,下面的介绍将围绕该流程展开,微服务包含两个方法Foo Test


启动一个带middleware微服务的详细流程

import http1 "github.com/go-kit/kit/transport/http"// 1. 创建一个Service Middleware类型定义
type Middleware func(HelloService) HelloService// 2. 扩展一个基于HelloService的middleware,并重写HelloService的所有RPC接口
type loggingMiddleware struct {logger log.Loggernext   HelloService
}
func (l loggingMiddleware) Foo(ctx context.Context, s string) (rs string, err error) {// somethingreturn l.next.Foo(ctx, s)
}
func (l loggingMiddleware) Test(ctx context.Context, s string, i int64) (s0 string, e1 error) {// somethinreturn l.next.Test(ctx, s, i)
}// 3. 实例化一个Service Middleware,并append到一个[]Middleware
var logger log.Logger
logMW := func(next HelloService) HelloService {return &loggingMiddleware{logger, next}}// 4. 创建一个service,这里需要重新定义service.New()为service.New(mws []Middleware),传入的为需要处理的middleware,后面会具体介绍这些middleware是怎么串起来的形成一个service chain的。
mws := []Middleware{logMW}
var svc HelloService = service.New(mws)// 5. 实例化一个endpoint.Middleware => type Middleware func(Endpoint) Endpoint
logeMW := func(next endpoint.Endpoint) endpoint.Endpoint {return func(ctx context.Context, request interface{}) (response interface{}, err error) {// something TODO about log// ctx = ...// request = ...logger.Log("...")return next(ctx, request)}}// 6. 创建一个Endpoint,这里需要重新定义`endpoint.New(service.HelloService)`为`endpoint.New(service.HelloService,map[string][]endpoint.Middleware)`,传入一个`map[string][]endpoint.Middleware{}`。emws := map[string][]endpoint.Middleware{}
emws["Foo"] = []endpoint.Middleware{logeMW} // 这里的"Foo"是HelloService里面定义的RPC方法,也可以更多的类似logeMW的实现;
//如果"Test"也有endpoint.Middleware,则也应该添加
// emws["Test"] = []endpoint.Middleware{logeMW}
eps := endpoint.New(svc,emws)// eps为Endpoints类型,即所有Service服务接口对应的endpoint.Endpoint集合:
// type Endpoints struct {
//      FooEndpoint  endpoint.Endpoint
//      TestEndpoint endpoint.Endpoint
// }// 7. 创建一个microserver
//   7.1 创建http.Handler
//这里省略(decodeFooRequest和encodeFooResponse实现)
// type DecodeRequestFunc func(context.Context, *http.Request) (request interface{}, err error)
// type EncodeResponseFunc func(context.Context, http.ResponseWriter, interface{}) error
servfoo := http1.NewServer(eps.FooEndpoint, decodeFooRequest, encodeFooResponse, options...)
servtest := http1.NewServer(eps.TestEndpoint, decodeFooRequest, encodeFooResponse, options...)
//   7.2 创建Mux server
mux := http.NewServeMux()
mux.Handle("/foo", servfoo)
mux.Handle("/test", servtest)
//   7.3 启动微服务server
http.ListenAndServe("localhost:8080", mux)

endpoint/middleware

endpoint.Endpoint定义:

// Endpoint is the fundamental building block of servers and clients.
// It represents a single RPC method.
type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)

endpoint.Middleware定义:

// Middleware is a chainable behavior modifier for endpoints.
type Middleware func(Endpoint) Endpoint

所以Middleware的实现方式可以理解为是一个输入输出链模型:

http/req
ctx,req
ctx1,req1...ctxN,reqN
客户端请求
serverHTTP
ctx1,req1
response

其实kit对endpoint的实现是比较巧妙的,具体体现在endpoint.Newendpoint.Middleware,看下他们的实现:

// New returns a Endpoints struct that wraps the provided service, and wires in all of the
// expected endpoint middlewares
func New(s service.HelloService, mdw map[string][]endpoint.Middleware) Endpoints {eps := Endpoints{FooEndpoint:  MakeFooEndpoint(s),TestEndpoint: MakeTestEndpoint(s),}for _, m := range mdw["Foo"] {eps.FooEndpoint = m(eps.FooEndpoint)}for _, m := range mdw["Test"] {eps.TestEndpoint = m(eps.TestEndpoint)}return eps
}
func(next endpoint.Endpoint) endpoint.Endpoint {return func(ctx context.Context, request interface{}) response interface{}, err error) {// something need to doreturn next(ctx, request)}
}

来分析下核心代码:

第一段代码中的:for _, m := range mdw["Foo"] {eps.FooEndpoint = m(eps.FooEndpoint)}//--------
第二段代码中的:return next(ctx, request)

也就是说在New创建的时候,会创建一个endpoint.Endpoint的链式调用,最后创建的将会先执行。当收到http的请求时,http.Handler会调用endpoint.Endpoint(ctx,req),从而依次往后调,最后将调用业务接口的Endpoint。

service/middleware

service的middleware和endpoint的middleware是类似的,也是一个链式调用,先来看几个概念:

Middleware的定义:

// Middleware describes a service middleware.
type Middleware func(HelloService) HelloService

具体某个Middleware的定义:

type loggingMiddleware struct {logger log.Loggernext   HelloService
}

我们来看看其中实现的奥秘,共三段代码:

loggingMiddleware包含的HelloService接口的实现:

func (l loggingMiddleware) Foo(ctx context.Context, s string) (rs string, err error) {defer func() {l.logger.Log("method", "Foo", "s", s, "rs", rs, "err", err)}()return l.next.Foo(ctx, s)
}
func (l loggingMiddleware) Test(ctx context.Context, s string, i int64) (s0 string, e1 error) {defer func() {l.logger.Log("method", "Test", "s", s, "i", i, "s0", s0, "e1", e1)}()return l.next.Test(ctx, s, i)
}

Middleware的实现:

var logger log.Logger
func(next HelloService) HelloService {return &loggingMiddleware{logger, next}}

创建一个service的时候

// New returns a HelloService with all of the expected middleware wired in.
func New(middleware []Middleware) HelloService {var svc HelloService = NewBasicHelloService()for _, m := range middleware {svc = m(svc)}return svc
}

来分析下核心代码:

第一段代码中的:return l.next.Foo(ctx, s)//--------
第二段代码中的:return &loggingMiddleware{logger, next}//--------
第三段代码中的:for _, m := range middleware {svc = m(svc)}

也就是说每个Middleware会接收一个老的HelloService返回一个包含老的HelloService的新的HelloService,同时新的HelloService的接口实现会调用老的HelloService的接口return l.next.Foo(ctx, s)
在创建的时候,会依次调用,从而将这些Middleware串起来。

4 Client

kit g c hello
client的连接具体参考生成client库。

package mainimport ("context""fmt"client "hello/client/http""github.com/go-kit/kit/transport/http"
)func main() {svc, err := client.New("http://localhost:8081", map[string][]http.ClientOption{})if err != nil {panic(err)}r, err := svc.Foo(context.Background(), "hello")if err != nil {fmt.Println("Error:", err)return}fmt.Println("Result:", r)
}

5 多协议支持

go-kit 除了支持http还支持grpc,amqp,nats,thrift。比如,grpc使用kit g s hello -t grpc,nats使用kit g s hello -t nats

这些的实现框架与http是一致的。

kit框架详解(基于go-kit)相关推荐

  1. 框架详解_Qt开发技术:QtCharts(一)QtCharts基本介绍以及图表框架详解

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  2. (转) shiro权限框架详解06-shiro与web项目整合(上)

    http://blog.csdn.net/facekbook/article/details/54947730 shiro和web项目整合,实现类似真实项目的应用 本文中使用的项目架构是springM ...

  3. 集合框架详解之Set、Map接口与实现类

    集合框架 1.Set集合 1.1Set集合概述 Set实现类:HashSet类.TreeSet类 特点:无序.无下标.元素不可重复 方法:全部继承自Collection中的方法 1.11 Set接口的 ...

  4. 双目视觉集合框架详解

    双目视觉几何框架详解 一.图像坐标:我想和世界坐标谈谈(A) 玉米竭力用轻松具体的描述来讲述双目三维重建中的一些数学问题.希望这样的方式让大家以一个轻松的心态阅读玉米的<计算机视觉学习笔记> ...

  5. Django REST 框架详解 07 | 三大认证与权限六表

    文章目录 一.三大认证 1. 认证组件:校验用户 2. 权限组件:校验用户权限 3. 频率组件:限制视图接口被访问次数 4. 分析源码 二.权限六表 1. RBAC 认证 2. 权限三表 3. 权限五 ...

  6. laravel框架详解 学以致用

    系列文章目录 提示: laravel介绍.文件配置.路由使用 .控制器的使用 . 数据的操作.@csrf防护.文件上传 文章目录 系列文章目录 laravel框架 详解一些功能 学以致用 一.lara ...

  7. Linux内核Thermal框架详解十二、Thermal Governor(2)

    本文部分内容参考 万字长文 | Thermal框架源码剖析, Linux Thermal机制源码分析之框架概述_不捡风筝的玖伍贰柒的博客-CSDN博客, "热散由心静,凉生为室空" ...

  8. 微服务架构 与 Dubbo 微服务框架、SpringCloud 微服务框架 详解

    微服务架构 与 Dubbo 微服务框架.SpringCloud 微服务框架 详解 什么是微服务架构? 微服务架构就是将单体的应用程序分成多个应用程序,这一个应用程序就组成一个服务,这多个应用程序就组成 ...

  9. 详解基于图卷积的半监督学习

    Kipf和Welling最近发表的一篇论文提出,使用谱传播规则(spectral propagation)快速近似spectral Graph Convolution. 和之前讨论的求和规则和平均规则 ...

  10. Java--集合框架详解

    文章目录 1.集合概念 2.Collection接口 2.1.Collection父接口 2.2.**Collection的使用** 3.List接口与实现类 3.1.List子接口 3.2.List ...

最新文章

  1. 定义ComboBox(下拉列表)组件垂直滚动条的样式。
  2. 交换机端口灯闪烁频率一样_思创易控cetron-新品S2024GE 24口全千兆非网管交换机即将上市!...
  3. php oracle 无查询结果,php - Oracle Insert查询不起作用,也不会抛出任何错误 - 堆栈内存溢出...
  4. Java作业09-异常
  5. php cookie 字串,php入门(字符串,cookie,session)
  6. asc码转换 linux_Linux终端下将图片转换ASCII Art代码图案
  7. (6)css常用样式属性--文字样式
  8. Bootstrap 滚动监听插件Scrollspy 的方法
  9. Vue学习之ref属性
  10. MySQL(二):MySQL性能优化
  11. python表格对齐_python 格式化输出 列表对齐左对齐右对齐
  12. 删除专利模板文件的最后一页(WPS亲测可用)
  13. 杭电ACM-LCY算法进阶培训班-专题训练(Hash及其应用)
  14. matlab——非线性规划
  15. 关于华硕电脑进入bios
  16. TOM邮箱|163邮箱容量评比!注册哪个容量好呢?
  17. Substance Painter 服饰材质制作 - 肩带1
  18. Android 面试必备之 JVM 相关口水话,flutterpageview动画
  19. PP体育APP产品体验报告
  20. signature=6846357f033a668e61dd424f68d4d1c2,Wybrane aspekty zwinności organizacyjnej

热门文章

  1. 车轱辘APP提交到各应用市场的心得~
  2. Installation error: INSTALL_FAILED_UPDATE_INCOMPATIBLE
  3. xss.haozi挑战
  4. Blender-反转法线
  5. TEXT 5 Stuff of dreams
  6. 滴滴章文嵩分享大数据在城市智慧交通领域探索实践
  7. XP系统,开机启动报NTDETECT 失败
  8. Raspberry pi设置Samba
  9. 全国DNS服务器IP地址【电信、网通、铁通】。
  10. 计算机绘图课程选用课本,机械制图与计算机绘图 机械制图与计算机绘图 机械制图与计算机绘图课程标准.doc...