微服务架构 | Go-Kit 初探

微服务

微服务是一种软件开发技术——面向服务架构(SOA)架构风格的变体,它将应用程序构建为松散耦合服务的集合。微服务是指开发一个单个小型的但有业务功能的服务,每个服务都有自己的处理和轻量通讯机制,可以部署在单个或多个服务器上。当服务发生错误时,如果每个服务都要同时修改,那么它们就不是微服务,因为它们紧耦合在一起。

  • 在微服务架构中,服务是细粒度的,协议是轻量级的。将应用程序分解成较小服务实现模块化。这使得应用程序更容易理解、开发、测试,架构更有弹性。
  • 小型自治团队能够独立开发、部署和扩展各自的服务,从而实现开发的并行化。
  • 基于微服务的体系结构支持连续交付和部署。

Microservices are a software development technique—a variant of the service-oriented architecture (SOA) architectural style that structures an application as a collection of loosely coupled services. --wikipedia

Go-Kit(A toolkit for microservices)

go-kit自称为toolkit,并不是framework,也就是go-kit是将一系列的服务集合在一起,提供接口,从而让开发者自由组合搭建自己的微服务项目。go-kit使用者可以将精力集中在业务逻辑上。
go-kit主要结构:
微服务架构 | Go-Kit 初探_第1张图片

Go-Kit组件

  1. Endpoint 端点
    go-kit使用一个抽象的Endpoint来表示每个服务提供的方法。在这个定义的类型里面会去调用service层的方法,组装成response返回。

    import "github.com/go-kit/kit/endpoint"
    // type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
    
    // MakeGetSpecEndpoint returns an endpoint that invokes GetSpec on the service.
    func MakeGetSpecEndpoint(s CptService) endpoint.Endpoint {
    	return func(ctx context.Context, request interface{}) (interface{}, error) {
    		req := request.(Request)
    		status, errinfo, data := s.GetSpec(ctx, req.TaskId)
    		return Response{
    			Status:  status,
    			Errinfo: errinfo,
    			Data:    data,
    		}, nil
    	}
    }
    

    其中,GetSpecRequest是我们的服务CptService在处理此请求时所需要参数对应的结构体。

    // 在业务逻辑中,处理此请求只需要Id一个参数,所以GetSpecRequest对应如下
    type GetSpecRequest struct {
    	TaskId string `json:"taskId"`
    }
    
  2. Transport 数据传输(序列化和反序列化)
    transport 模块提供将特定的序列化算法绑定到端点的辅助方法。

    // decodeGetSpecRequest is a transport/http.DecodeRequestFunc that decodes a
    // JSON-encoded request from the HTTP request body.
    func decodeGetSpecRequest(_ context.Context, r *http.Request) (interface{}, error) {
    	vars := mux.Vars(r)
    	taskId, ok := vars["taskId"]
    	if !ok {
    		return nil, errors.New("not a valid taskId")
    	}
    	req := endpoint.GetSpecRequest{
    		TaskId: taskId,
    	}
    	return req, nil
    }
    
    // encodeGetSpecResponse is a transport/http.EncodeResponseFunc that encodes
    // the response as JSON to the response writer
    func encodeGetSpecResponse(ctx context.Context, w http.ResponseWriter, response interface{}) (err error) {
    	w.Header().Set("Content-Type", "application/json; charset=utf-8")
    	err = json.NewEncoder(w).Encode(response)
    	return
    }
    
  3. Logging 日志
    日志可以方便我们追踪服务调用的过程,同时方便我们调式错误。go-kit为我们提供了易用的log模块。

    // 此代码实现的是应用层日志,也可以和下方Rate Limiter实现方法一样,实现tranport logging
    // log middleware
    import 	"github.com/go-kit/kit/log"
    type LoggingMiddleware struct {
    	Logger log.Logger
    	Next   CptService
    }
    
    func (l *LoggingMiddleware) GetSpec(ctx context.Context, taskId string) (status bool, errinfo string, data interface{}) {
    	defer func(begin time.Time) {
    		l.Logger.Log(
    			"method", "GetSpec",
    			"input", fmt.Sprintf("%#v", Request{TaskId: taskId}),			# log模块并不支持复杂的数据类型,会产生`unsuported value type`的问题,我们可以使用fmt.Sprintf()来将其转化为字符串再输出。
    			"output", fmt.Sprintf("%#v", Response{status, errinfo, data}),
    			"took", time.Since(begin),
    		)
    	}(time.Now())
    	status, errinfo, data = l.Next.GetSpec(ctx, taskId)
    	return
    }
    
  4. Rate Limiter 限流器
    限流器模块提供了到限流器代码包的端点适配器。限流器对服务端和客户端同等生效,使用限流器可以强制进、出请求量在阈值以下。使用限流器能限制访问后端的流量,起到一个保护作用,被限制的流量,可以根据具体的业务逻辑去处理,直接返回错误或者返回默认值。
    go-kit的限流器模块是封装了golang自带的golang.org/x/time/rate包来实现的,提供了两种限流:DelayingLimiter【限流延迟访问】ErroringLimiter【限流错误返回】

    // NewDelayingLimiter是go-kit实现的ratelimiter,我们可以直接使用。
    func NewDelayingLimiter(limit ratelimit.Waiter) endpoint.Middleware {
       return func(next endpoint.Endpoint) endpoint.Endpoint {
          return func(ctx context.Context, request interface{}) (interface{}, error) {
             if err := limit.Wait(ctx); err != nil {
                return nil, err
             }
             return next(ctx, request)
          }
       }
    }
    // 如何使用此中间件
    import (
    	"golang.org/x/time/rate"
    	"github.com/go-kit/kit/ratelimit"
    )
    limiter := rate.NewLimiter(rate.Every(time.Second * 1), 1) 
    GetSpecEndpoint = ratelimit.NewDelayingLimiter(limiter)(GetSpecEndpoint) 
    getSpecHandler := httptransport.NewServer(
    	GetSpecEndpoint,
    	decodes.GetSpecDecode,
    	encodes.GetSpecEncode,
    )
    ......
    
  5. Metrics 指标度量
    直到服务经过了跟踪计数、延迟、健康状况和其他的周期性的或针对每个请求信息的仪表盘化,才能被认为是“生产环境”完备的。Go kit 的 metric 模块为你的服务提供了通用并健壮的接口集合。

    import 	"github.com/go-kit/kit/metrics"
    type InstrumentingMiddleware struct {
    	RequestCount   metrics.Counter
    	RequestLatency metrics.Histogram
    	Next           CptService
    }
    
    func (i *InstrumentingMiddleware) GetSpec(ctx context.Context, taskId string) (status bool, errinfo string, data interface{}) {
    	defer func(begin time.Time) {
    		lvs := []string{"method", "GetSpec", "error", errinfo}
    		i.RequestCount.With(lvs...).Add(1)
    		i.RequestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
    	}(time.Now())
    	status, errinfo, data = i.Next.GetSpec(ctx, taskId)
    	return
    }
    
  6. Circuit breaker 断路器
    Circuit breaker模块提供了很多流行的回路断路lib的端点(endpoint)适配器,回路断路器可以避免雪崩,并且提高了针对间歇性错误的弹性,每一个client的端点都应该封装在回路断路器中。

  7. Request tracing 请求追踪
    随着你的基础设施的增长,能够跟踪一个请求变得越来越重要,因为它可以在多个服务中进行穿梭并回到用户。Go kit的 tracing 模块提供了为端点和传输的增强性的绑定功能,以捕捉关于请求的信息,并把它们发送到跟踪系统中。

  8. Service Discovery 服务发现
    如果你的服务调用了其他的服务,需要知道如何找到它(另一个服务),并且应该智能的将负载在这些发现的实例上铺开(即,让被发现的实例智能的分担服务压力)。Go kit的 loadbalancer 模块提供了客户端端点的中间件来解决这类问题

【参考链接】

  1. go-kit 示例。
  2. https://en.wikipedia.org/wiki/Microservices
  3. https://www.cnblogs.com/wintersun/p/6219259.html
  4. https://blog.csdn.net/warrior_0319/article/details/77548958

你可能感兴趣的:(微服务)