热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

gokit简介

1.microserviceGo-Kitgokit是一个分布式的开发工具集,在大型的组织(业务)中可以用来构建微服务。其解决了分布式系统

1. microservice


Go-Kit

 

go kit 是一个分布式的开发工具集,在大型的组织(业务)中可以用来构建微服务。其解决了分布式系统中的大多数常见问题,因此,使用者可以将精力集中在业务逻辑上。

2. go-kit 组件介绍


2.1 Endpoint(端点)

Go kit首先解决了RPC消息模式。其使用了一个抽象的 endpoint 来为每一个RPC建立模型。

endpoint通过被一个server进行实现(implement),或是被一个client调用。这是很多 Go kit组件的基本构建代码块。

2.2 Circuit breaker(回路断路器)

Circuitbreaker(回路断路器) 模块提供了很多流行的回路断路lib的端点(endpoint)适配器。回路断路器可以避免雪崩,并且提高了针对间歇性错误的弹性。每一个client的端点都应该封装(wrapped)在回路断路器中。

2.3 Rate limiter(限流器)

ratelimit模块提供了到限流器代码包的端点适配器。限流器对服务端(server-client)和客户端(client-side)同等生效。使用限流器可以强制进、出请求量在阈值上限以下。

2.4 Transport(传输层)

transport 模块提供了将特定的序列化算法绑定到端点的辅助方法。当前,Go kit只针对JSON和HTTP提供了辅助方法。如果你的组织使用完整功能的传输层,典型的方案是使用Go在传输层提供的函数库,Go kit并不需要来做太多的事情。这些情况,可以查阅代码例子来理解如何为你的端点写一个适配器。目前,可以查看 addsvc的代码来理解Transport绑定是如何工作的。我们还提供了针对Thirft,gRPC,net/rpc,和http json的特殊例子。对JSON/RPC和Swagger的支持在计划中。

2.5 Logging(日志)

服务产生的日志是会被延迟消费(使用)的,或者是人或者是机器(来使用)。人可能会对调试错误、跟踪特殊的请求感兴趣。机器可能会对统计那些有趣的事件,或是对离线处理的结果进行聚合。这两种情况,日志消息的结构化和可操作性是很重要的。Go kit的 log 模块针对这些实践提供了最好的设计。

2.6 Metrics(Instrumentation)度量/仪表盘

直到服务经过了跟踪计数、延迟、健康状况和其他的周期性的或针对每个请求信息的仪表盘化,才能被认为是“生产环境”完备的。Go kit 的 metric 模块为你的服务提供了通用并健壮的接口集合。可以绑定到常用的后端服务,比如 expvar 、statsd、Prometheus。

2.7 Request tracing(请求跟踪)

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

2.8 Service discovery and load balancing(服务发现和负载均衡)

如果你的服务调用了其他的服务,需要知道如何找到它(另一个服务),并且应该智能的将负载在这些发现的实例上铺开(即,让被发现的实例智能的分担服务压力)。Go kit的loadbalancer模块提供了客户端端点的中间件来解决这类问题,无论你是使用的静态的主机名还是IP地址,或是 DNS的 SRV 记录,Consul,etcd 或是 Zookeeper。并且,如果你使用定制的系统,也可以非常容易的编写你自己的 Publisher,以使用 Go kit 提供的负载均衡策略。(目前,支持静态主机名、etcd、Consul、Zookeeper)

3 目标


  • 在各种SOA架构中操作–预期会与各种非Go kit服务进行交互
  • 使用RPC作为最主要的消息模式
  • 可插拔的序列化和传输–不仅仅只有JSON和HTTP
  • 简单便可融入现有的架构–没有任何特殊工具、技术的相关指令

4 目标之外(不考虑做的事情)


  • 支持除RPC之外的消息模式(至少目前是)–比如 MPI、pub/sub,CQRS,等
  • 除适配现有软件外,重新实现一些功能
  • 在运维方面进行评论:部署、配置、进程管理、服务编排等

5 依赖管理

Go kit 是一个函数库,设计的目标是引入到二进制文件中。对于二进制软件包的作者来讲,Vendoring是目前用来确保软件可靠、可重新构建的最好的机制。因此,我们强烈的建议我们的用户使用vendoring机制来管理他们软件的依赖,包括Go kit。

为了避免兼容性和可用性的问题,Go kit没有vendor它自己的依赖,并且并不推荐使用第三方的引用代理。

有一些工具可以让vendor机制更简单,包括 gb、glide、gvt、 govendor 和 vendetta。另外,Go kit使用了一系列的持续集成的机制来确保在尽快地修复那些复杂问题。

5 相关项目

标注有 ★ 的项目对 Go kit 的设计有着特别的影响 (反之亦然)

  1. 服务框架

    • gizmo, a microservice toolkit from The New York Times ★
    • go-micro, a microservices client/server library ★
    • gocircuit, dynamic cloud orchestration
    • gotalk, async peer communication protocol & library
    • h2, a microservices framework ★
    • Kite, a micro-service framework
  2. 独立组件

    afex/hystrix-go, client-side latency and fault tolerance library

    armon/go-metrics, library for exporting performance and runtime metrics to external metrics systems

    codahale/lunk, structured logging in the style of Google’s Dapper or Twitter’s Zipkin

    eapache/go-resiliency, resiliency patterns

    sasbury/logging, a tagged style of logging

    grpc/grpc-go, HTTP/2 based RPC

    inconshreveable/log15, simple, powerful logging for Go ★

    mailgun/vulcand, programmatic load balancer backed by etcd

    mattheath/phosphor, distributed system tracing

    pivotal-golang/lager, an opinionated logging library

    rubyist/circuitbreaker, circuit breaker library

    Sirupsen/logrus, structured, pluggable logging for Go ★

    sourcegraph/appdash, application tracing system based on Google’s Dapper

    spacemonkeygo/monitor, data collection, monitoring, instrumentation, and Zipkin client library

    streadway/handy, net/http handler filters

    vitess/rpcplus, package rpc + context.Context

    gdamore/mangos, nanomsg implementation in pure Go

  3. Web 框架

    Beego

    Gin

    Goji

    Gorilla

    Martini

    Negroni

    Revel (considered harmful)

  4. ###其他参考

    Architecting for the Cloud — Netflix

    Dapper, a Large-Scale Distributed Systems Tracing Infrastructure — Google

    Your Server as a Function (PDF) — Twitter

 

 

 

 

 

go-kit 入门 (二) 第一个 Go kit 程序

发表于2016 年 5 月 28 日由chunshengster@gmail.com

下面让我来们创建一个非常精简的 Go kit 服务


业务逻辑逻辑

服务(Service)是从业务逻辑开始的,在 Go kit 中,我们将服务以 interface 作为模型

 

1

2

3

4

5

// StringService provides operations on strings.

type StringService interface {

    Uppercase(string) (string, error)

    Count(string) int

}

这个 interface 需要有一个“实现”

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

type stringService struct{}

 

func (stringService) Uppercase(s string) (string, error) {

    if s == "" {

        return "", ErrEmpty

    }

    return strings.ToUpper(s), nil

}

 

func (stringService) Count(s string) int {

    return len(s)

}

 

// ErrEmpty is returned when input string is empty

var ErrEmpty = errors.New("Empty string")


请求和响应

在 Go kit 中,主要的消息模式是 RPC。因此,接口( interface )的每一个方法都会被模型化为远程过程调用(RPC)。对于每一个方法,我们都定义了请求和响应的结构体,捕获输入、输出各自的所有参数。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

type uppercaseRequest struct {

    S string `json:"s"`

}

 

type uppercaseResponse struct {

    V   string `json:"v"`

    Err string `json:"err,omitempty"` // errors don't define JSON marshaling

}

 

type countRequest struct {

    S string `json:"s"`

}

 

type countResponse struct {

    V int `json:"v"`

}


端点 (endpoint)

Go kit 通过 endpoint 提供了非常丰富的功能。

一个端点代表一个RPC,也就是我们服务接口中的一个函数。我们将编写简单的适配器,将我们的服务的每一个方法转换成端点。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

import (

    "golang.org/x/net/context"

    "github.com/go-kit/kit/endpoint"

)

 

 

func makeUppercaseEndpoint(svc StringService) endpoint.Endpoint {

    return func(ctx context.Context, request interface{}) (interface{}, error) {

        req := request.(uppercaseRequest)

        v, err := svc.Uppercase(req.S)

        if err != nil {

            return uppercaseResponse{v, err.Error()}, nil

        }

        return uppercaseResponse{v, ""}, nil

    }

}

 

func makeCountEndpoint(svc StringService) endpoint.Endpoint {

    return func(ctx context.Context, request interface{}) (interface{}, error) {

        req := request.(countRequest)

        v := svc.Count(req.S)

        return countResponse{v}, nil

    }

}


传输(Transports)

现在我们需要将服务暴露给外界,这样它们才能被调用。对于服务如何与外界交互,你的组织可能已经有了定论。可能你会使用 Thrift、基于 HTTP 的自定义 JSON。Go kit支持多种开箱即用的 传输 方式。(Adding support for new ones is easy—just 对新方式的支持是非常简单的。参见 这里

针对我们现在的这个微型的服务例子,我们使用基于 HTTP 的 JSON。Go kit 中提供了一个辅助结构体,在 transport/http 中。

 

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

import (

    "encoding/json"

    "log"

    "net/http"

 

    "golang.org/x/net/context"

 

    httptransport "github.com/go-kit/kit/transport/http"

)

 

func main() {

    ctx := context.Background()

    svc := stringService{}

 

    uppercaseHandler := httptransport.NewServer(

        ctx,

        makeUppercaseEndpoint(svc),

        decodeUppercaseRequest,

        encodeResponse,

    )

 

    countHandler := httptransport.NewServer(

        ctx,

        makeCountEndpoint(svc),

        decodeCountRequest,

        encodeResponse,

    )

 

    http.Handle("/uppercase", uppercaseHandler)

    http.Handle("/count", countHandler)

    log.Fatal(http.ListenAndServe(":8080", nil))

}

 

func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) {

    var request uppercaseRequest

    if err := json.NewDecoder(r.Body).Decode(&request); err != nil {

        return nil, err

    }

    return request, nil

}

 

func decodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) {

    var request countRequest

    if err := json.NewDecoder(r.Body).Decode(&request); err != nil {

        return nil, err

    }

    return request, nil

}

 

func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {

    return json.NewEncoder(w).Encode(response)

}

 

 

 

 

 

go-kit 入门(三)日志和仪表化

发表于2016 年 6 月 1 日由chunshengster@gmail.com

日志和仪表化

任何服务在日志和仪表化没有就绪的情况下,都不能说是生产环境就绪的。

传输日志

任何需要日志记录的组件都需要将 logger 作为依赖,就像数据库连接一样。因此,我们在 main 函数中构造 logger 对象,然后将其传入需要使用它的组件中。我们始终不去使用一个全局的 logger 对象。

我们可以直接将 logger 传入到 stringService 的实现代码中,但是,还有一个更好的方式。我们可以使用 中间件 (middleware) ,也常常被称为 装饰者。

middleware 是一个函数,它接收一个 endpoint 作为参数,并且返回一个 endpoint。

 

1

type Middleware func(Endpoint) Endpoint

在函数中,它可以做任何事情。下面就让我们来创建一个基本的日志中间件。

 

1

2

3

4

5

6

7

8

9

func loggingMiddleware(logger log.Logger) Middleware {

    return func(next endpoint.Endpoint) endpoint.Endpoint {

        return func(ctx context.Context, request interface{}) (interface{}, error) {

            logger.Log("msg", "calling endpoint")

            defer logger.Log("msg", "called endpoint")

            return next(ctx, request)

        }

    }

}

然后,我们将它加入到每一个处理函数中。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

logger := log.NewLogfmtLogger(os.Stderr)

 

svc := stringService{}

 

var uppercase endpoint.Endpoint

uppercase = makeUppercaseEndpoint(svc)

uppercase = loggingMiddleware(log.NewContext(logger).With("method", "uppercase"))(uppercase)

 

var count endpoint.Endpoint

count = makeCountEndpoint(svc)

count = loggingMiddleware(log.NewContext(logger).With("method", "count"))(count)

 

uppercaseHandler := httptransport.Server(

    // ...

    uppercase,

    // ...

)

 

countHandler := httptransport.Server(

    // ...

    count,

    // ...

)

事实证明,这项技术是非常有价值的,远远不止于记录日志,Go kit 的很多模块都被实现为端点中间件。

应用日志

那么,在我们的应用中,应该如何记录日志呢?比如那些需要被传入的参数等。事实上,我们能够为我们的服务定义一个中间件,从而获得同样好的组合效果。由于我们的 StringService被定义为一个接口,我们只需要作出一个新的类型,来包装先有的 StringService,让它来执行扩充的记录日志的任务。

 

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

type loggingMiddleware struct{

    logger log.Logger

    StringService

}

 

func (mw loggingMiddleware) Uppercase(s string) (output string, err error) {

    defer func(begin time.Time) {

        mw.logger.Log(

            "method", "uppercase",

            "input", s,

            "output", output,

            "err", err,

            "took", time.Since(begin),

        )

    }(time.Now())

 

    output, err = mw.StringService.Uppercase(s)

    return

}

 

func (mw loggingMiddleware) Count(s string) (n int) {

    defer func(begin time.Time) {

        mw.logger.Log(

            "method", "count",

            "input", s,

            "n", n,

            "took", time.Since(begin),

        )

    }(time.Now())

 

    n = mw.StringService.Count(s)

    return

}

然后,将新的类型引入到下面的代码中:

 

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

import (

    "os"

 

    "github.com/go-kit/kit/log"

    httptransport "github.com/go-kit/kit/transport/http"

)

 

func main() {

    logger := log.NewLogfmtLogger(os.Stderr)

 

    svc := stringService{}

    svc = loggingMiddleware{logger, svc}

 

    uppercaseHandler := httptransport.NewServer(

        // ...

        makeUppercaseEndpoint(svc),

        // ...

    )

 

    countHandler := httptransport.NewServer(

        // ...

        makeCountEndpoint(svc),

        // ...

    )

}

在传输环节使用端点中间件,比如回路断路器和速率限制。在业务环节使用服务中间件,比如日志和仪表化。

仪表化

在 Go kit 中,仪表化意味着使用 包指标 来记录关于服务运行行为的状态。统计执行的任务的数量,在请求完成后记录消耗的时间,以及跟踪所有正在执行的操作的数量,都被认为是 仪表化。

我们可以使用同样的中间件模式,在记录日志的环节我们曾经用过。

 

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

type instrumentingMiddleware struct {

    requestCount   metrics.Counter

    requestLatency metrics.TimeHistogram

    countResult    metrics.Histogram

    StringService

}

 

func (mw instrumentingMiddleware) Uppercase(s string) (output string, err error) {

    defer func(begin time.Time) {

        methodField := metrics.Field{Key: "method", Value: "uppercase"}

        errorField := metrics.Field{Key: "error", Value: fmt.Sprintf("%v", err)}

        mw.requestCount.With(methodField).With(errorField).Add(1)

        mw.requestLatency.With(methodField).With(errorField).Observe(time.Since(begin))

    }(time.Now())

 

    output, err = mw.StringService.Uppercase(s)

    return

}

 

func (mw instrumentingMiddleware) Count(s string) (n int) {

    defer func(begin time.Time) {

        methodField := metrics.Field{Key: "method", Value: "count"}

        errorField := metrics.Field{Key: "error", Value: fmt.Sprintf("%v", error(nil))}

        mw.requestCount.With(methodField).With(errorField).Add(1)

        mw.requestLatency.With(methodField).With(errorField).Observe(time.Since(begin))

        mw.countResult.Observe(int64(n))

    }(time.Now())

 

    n = mw.StringService.Count(s)

    return

}

然后将其引入到服务中:

 

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

import (

    stdprometheus "github.com/prometheus/client_golang/prometheus"

    kitprometheus "github.com/go-kit/kit/metrics/prometheus"

    "github.com/go-kit/kit/metrics"

)

 

func main() {

    logger := log.NewLogfmtLogger(os.Stderr)

 

    fieldKeys := []string{"method", "error"}

    requestCount := kitprometheus.NewCounter(stdprometheus.CounterOpts{

        // ...

    }, fieldKeys)

    requestLatency := metrics.NewTimeHistogram(time.Microsecond, kitprometheus.NewSummary(stdprometheus.SummaryOpts{

        // ...

    }, fieldKeys))

    countResult := kitprometheus.NewSummary(stdprometheus.SummaryOpts{

        // ...

    }, []string{}))

 

    svc := stringService{}

    svc = loggingMiddleware{logger, svc}

    svc = instrumentingMiddleware{requestCount, requestLatency, countResult, svc}

 

    uppercaseHandler := httptransport.NewServer(

        // ...

        makeUppercaseEndpoint(svc),

        // ...

    )

 

    countHandler := httptransport.NewServer(

        // ...

        makeCountEndpoint(svc),

        // ...

    )

 

    http.Handle("/metrics", stdprometheus.Handler())

}

 

stringsvc2

目前位置,完整的服务是 stringsvc2.

 

1

2

3

$ go get github.com/go-kit/kit/examples/stringsvc2

$ stringsvc2

msg=HTTP addr=:8080

 

 

1

2

3

4

$ curl -XPOST -d'{"s":"hello, world"}' localhost:8080/uppercase

{"v":"HELLO, WORLD","err":null}

$ curl -XPOST -d'{"s":"hello, world"}' localhost:8080/count

{"v":12}

 

 

1

2

method=uppercase input="hello, world" output="HELLO, WORLD" err=null took=2.455µs

method=count input="hello, world" n=12 took=743ns

 

 

 

 

 

Go-kit 入门(四)服务调用

发表于2016 年 6 月 16 日由chunshengster@gmail.com

调用服务

存在“真空”(即极其独立,与其他任何服务无互相调用的关系)中的服务是罕见的。而我们常见的是,我们需要调用其他的服务。这也是 Go kit 的闪光点 ,我们提供了 传输中间件机制来解决可能出现的很多问题。

下面我们将实现一个代理功能的中间件,作为一个服务中间件。在这里我们只代理一个方法,Uppercase。

 

1

2

3

4

5

6

7

8

// proxymw implements StringService, forwarding Uppercase requests to the

// provided endpoint, and serving all other (i.e. Count) requests via the

// embedded StringService.

type proxymw struct {

   context.Context

   StringService                       // Serve most requests via this embedded service...

   UppercaseEndpoint endpoint.Endpoint // ...except Uppercase, which gets served by this endpoint

}


客户端端点

我们已经有了一个跟我们所知道的完全相同的端点,但是我们将使用它来调用一个请求,而不是提供服务。按照这种方式来使用它的时候,我们称它为客户端端点。为了调用客户端端点,我们需要做一些简单的转换。

 

1

2

3

4

5

6

7

8

9

10

11

func (mw proxymw) Uppercase(s string) (string, error) {

    response, err := mw.UppercaseEndpoint(mw.Context, uppercaseRequest{S: s})

    if err != nil {

        return "", err

    }

    resp := response.(uppercaseResponse)

    if resp.Err != "" {

        return resp.V, errors.New(resp.Err)

    }

    return resp.V, nil

}

现在,我们为了构造一个代理中间件,我们将一个代理URL字符串转换为一个端点。加入我们使用 HTTP 协议之上的 JSON,我们可以使用 transport/http 包中的一个辅助(helper)函数。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

import (

   httptransport "github.com/go-kit/kit/transport/http"

)

 

func proxyingMiddleware(proxyURL string, ctx context.Context) ServiceMiddleware {

   return func(next StringService) StringService {

      return proxymw{ctx, next, makeUppercaseEndpoint(ctx, proxyURL)}

   }

}

 

func makeUppercaseEndpoint(ctx context.Context, proxyURL string) endpoint.Endpoint {

   return httptransport.NewClient(

      "GET",

      mustParseURL(proxyURL),

      encodeUppercaseRequest,

      decodeUppercaseResponse,

   ).Endpoint()

}


服务发现和负载均衡

如果我们只使用一个远程的服务就好了。但是实际上,我们往往 会有很多个服务实例。我们希望通过一些服务发现算法来发现它们,然后将我们的负载分散到它们上面,并且如果这些实例中的任何一个变得糟糕,我们能够处理它,并且不影响我们服务的可用性。

Go kit 为不同的服务发现系统提供了适配器,为了获取最新的服务实例集合,暴露端点个体。这些适配器被称为 发布器(publishers)。

 

1

2

3

type Publisher interface {

    Endpoints() ([]endpoint.Endpoint, error)

}

在发布器内部,它使用一个私有的工厂函数,将被发现的每一个 host:port 字符串 转换成一个可用的端点。

 

1

type Factory func(instance string) (endpoint.Endpoint, error)

目前,我们的工程方法,makeUppercaseEndpoint,只是直接请求 URL。但是,在工厂函数中加入一些安全的中间件方法是很重要的,比如 回路断路器 和 限流器。

 

1

2

3

4

5

6

7

8

9

func factory(ctx context.Context, maxQPS int) loadbalancer.Factory {

    return func(instance string) (endpoint.Endpoint, error) {

        var e endpoint.Endpoint

        e = makeUppercaseProxy(ctx, instance)

        e = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{}))(e)

        e = kitratelimit.NewTokenBucketLimiter(jujuratelimit.NewBucketWithRate(float64(maxQPS), int64(maxQPS)))(e)

        return e, nil

    }

}

现在,我们已经有了一系列的端点,我们需要在其中选择一个。负载均衡器包装了 发布器,并且从端点集合中选择其中的某一个。Go kit 提供了一组基本的负载均衡器,并且,如果你希望更多的高级的算法,也可以很容易的自己来写一个。

 

1

2

3

type LoadBalancer interface {

    Endpoint() (endpoint.Endpoint, error)

}

现在,我们可以根据一下算法来选择端点。我们能够使用它为消费器提供一个单一的、逻辑的可靠的端点。通过重试的策略包装负载均衡器,并且返回一个可用的端点。重试的策略可以将一个失败的请求进行重试,直到达到最大的可重试次数或是达到超时时间。

 

1

func Retry(max int, timeout time.Duration, lb LoadBalancer) endpoint.Endpoint

现在,让我们将最后的代理中间件加入到代码中。为了简洁,我们假设用户会为逗号(,)分隔的多个实例端点指定一个标记。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

func proxyingMiddleware(proxyList string, ctx context.Context, logger log.Logger) ServiceMiddleware {

    return func(next StringService) StringService {

        var (

            qps         = 100 // max to each instance

            publisher   = static.NewPublisher(split(proxyList), factory(ctx, qps), logger)

            lb          = loadbalancer.NewRoundRobin(publisher)

            maxAttempts = 3

            maxTime     = 100 * time.Millisecond

            endpoint    = loadbalancer.Retry(maxAttempts, maxTime, lb)

        )

        return proxymw{ctx, endpoint, next}

    }

}


stringsvc3

截止目前,这个完整的服务是 stringsvc3$ go get github.com/go-kit/kit/examples/stringsvc3 $ stringsvc3 -listen=:8001 & listen=:8001 caller=proxying.go:25 proxy_to=none listen=:8001 caller=main.go:72 msg=HTTP addr=:8001 $ stringsvc3 -listen=:8002 & listen=:8002 caller=proxying.go:25 proxy_to=none listen=:8002 caller=main.go:72 msg=HTTP addr=:8002 $ stringsvc3 -listen=:8003 & listen=:8003 caller=proxying.go:25 proxy_to=none listen=:8003 caller=main.go:72 msg=HTTP addr=:8003 $ stringsvc3 -listen=:8080 -proxy=localhost:8001,localhost:8002,localhost:8003 listen=:8080 caller=proxying.go:29 proxy_to="[localhost:8001 localhost:8002 localhost:8003]" listen=:8080 caller=main.go:72 msg=HTTP addr=:8080

 

1

2

3

4

$ for s in foo bar baz ; do curl -d"{\"s\":\"$s\"}" localhost:8080/uppercase ; done

{"v":"FOO","err":null}

{"v":"BAR","err":null}

{"v":"BAZ","err":null}

 

1

2

3

4

5

6

listen=:8001 caller=logging.go:28 method=uppercase input=foo output=FOO err=null took=5.168µs

listen=:8080 caller=logging.go:28 method=uppercase input=foo output=FOO err=null took=4.39012ms

listen=:8002 caller=logging.go:28 method=uppercase input=bar output=BAR err=null took=5.445µs

listen=:8080 caller=logging.go:28 method=uppercase input=bar output=BAR err=null took=2.04831ms

listen=:8003 caller=logging.go:28 method=uppercase input=baz output=BAZ err=null took=3.285µs

listen=:8080 caller=logging.go:28 method=uppercase input=baz output=BAZ err=null took=1.388155ms


高级话题


线程上下文

上下文对象用来在单个请求中携带那些需要跨越概念性边界的信息。在我们的例子中,我们还没有在业务逻辑中使用线程上下文。但是,这种方式几乎会永远都是一个好方案。它允许我们在业务逻辑和中间件中传递请求范围内的信息,并且对于复杂的任务(比如,分布式系统的细粒度追踪信息)也是很必要的。

具体点来讲,这也意味着你的业务逻辑接口会这样:

 

1

2

3

4

5

type MyService interface {

    Foo(context.Context, string, int) (string, error)

    Bar(context.Context, string) error

    Baz(context.Context) (int, error)

}

 

请求跟踪

一旦你的基础设施增长超过一定的规模,在多个服务中跟踪请求是非常必要的,这样,你就能够分析并解决故障热点。参见 package tracing 获取更多信息。

创建一个客户端软件包

使用 Go kit 为你的服务创建一个客户端软件包是很可能的事情,让你的服务能够很容易对其他的 Go 程序进行调用。实际上,你的客户端package会提供你的服务接口,这个接口会使用指定的传输方式来调用远程服务。参见 package addsvc/client 作为参考例子.

其他例子


addsvc

addsvc 是原来的一个例子。它公开 所有支持的传输方式 的系列操作。它完整地做了日志记录、仪表盘化,并且使用 Zipkin 来跟踪请求。同样,它也示范了如何创建和使用客户端package。它是一个非常棒的例子,为 Go kit 服务提供了完整的功能示例。

profilesvc

profilesvc 示范了如何使用 Go kit 来打造 REST 风格的微服务。

apigateway

apigateway 示范了如何实现一个 API 网关模式,通过 Consul 作为服务发现系统。

shipping

shipping 是一个完整的,真实的应用,由多个微服务组成,基于领域驱动设计原则。


推荐阅读
  • Python 实战:异步爬虫(协程技术)与分布式爬虫(多进程应用)深入解析
    本文将深入探讨 Python 异步爬虫和分布式爬虫的技术细节,重点介绍协程技术和多进程应用在爬虫开发中的实际应用。通过对比多进程和协程的工作原理,帮助读者理解两者在性能和资源利用上的差异,从而在实际项目中做出更合适的选择。文章还将结合具体案例,展示如何高效地实现异步和分布式爬虫,以提升数据抓取的效率和稳定性。 ... [详细]
  • 数字图书馆近期展出了一批精选的Linux经典著作,这些书籍虽然部分较为陈旧,但依然具有重要的参考价值。如需转载相关内容,请务必注明来源:小文论坛(http://www.xiaowenbbs.com)。 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • 如果程序使用Go语言编写并涉及单向或双向TLS认证,可能会遭受CPU拒绝服务攻击(DoS)。本文深入分析了CVE-2018-16875漏洞,探讨其成因、影响及防范措施,为开发者提供全面的安全指导。 ... [详细]
  • 本文介绍了几种常用的图像相似度对比方法,包括直方图方法、图像模板匹配、PSNR峰值信噪比、SSIM结构相似性和感知哈希算法。每种方法都有其优缺点,适用于不同的应用场景。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • 基于Dubbo与Zipkin的微服务调用链路监控解决方案
    本文提出了一种基于Dubbo与Zipkin的微服务调用链路监控解决方案。通过抽象配置层,支持HTTP和Kafka两种数据上报方式,实现了灵活且高效的调用链路追踪。该方案不仅提升了系统的可维护性和扩展性,还为故障排查提供了强大的支持。 ... [详细]
  • php更新数据库字段的函数是,php更新数据库字段的函数是 ... [详细]
  • 解决问题:1、批量读取点云las数据2、点云数据读与写出3、csf滤波分类参考:https:github.comsuyunzzzCSF论文题目ÿ ... [详细]
  • 如何在PHP中准确获取服务器IP地址?
    如何在PHP中准确获取服务器IP地址? ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
author-avatar
上海传安光通科技有限公司_839
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有