热门标签 | 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 是一个完整的,真实的应用,由多个微服务组成,基于领域驱动设计原则。


推荐阅读
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
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社区 版权所有