README: updates and rationales
Peter Bourgon
8 years ago
0 | 0 | # gokit [![Circle CI](https://circleci.com/gh/go-kit/kit.svg?style=svg)](https://circleci.com/gh/go-kit/kit) [![Drone.io](https://drone.io/github.com/go-kit/kit/status.png)](https://drone.io/github.com/go-kit/kit/latest) [![Travis CI](https://travis-ci.org/go-kit/kit.svg?branch=master)](https://travis-ci.org/go-kit/kit) [![GoDoc](https://godoc.org/github.com/go-kit/kit?status.svg)](https://godoc.org/github.com/go-kit/kit) |
1 | 1 | |
2 | **Gokit** is a **distributed programming toolkit** for microservices in the modern enterprise. | |
2 | **Go kit** is a **distributed programming toolkit** designed for microservices. | |
3 | 3 | |
4 | 4 | - Mailing list: [go-kit](https://groups.google.com/forum/#!forum/go-kit) |
5 | 5 | - Slack: [gophers.slack.com](https://gophers.slack.com) **#go-kit** ([invite](http://bit.ly/go-slack-signup)) |
6 | 6 | |
7 | 7 | ## Motivation |
8 | 8 | |
9 | See [the motivating blog post](http://peter.bourgon.org/go-kit) and [the video of the talk](https://www.youtube.com/watch?v=iFR_7AKkJFU). | |
9 | Go has emerged as the language of the server, but it remains underrepresented | |
10 | in large, consumer-focused tech companies like Facebook, Twitter, Netflix, and | |
11 | SoundCloud. These organizations have largely adopted JVM-based stacks for | |
12 | their business logic, owing in large part to libraries and ecosystems that | |
13 | directly support their microservice architectures. | |
14 | ||
15 | To reach its next level of success, Go needs more than simple primitives and | |
16 | idioms. It needs a comprehensive toolkit, for coherent distributed programming | |
17 | in the large. Go kit is a set of packages and best practices, leveraging years | |
18 | of production experience, and providing a comprehensive, robust, and trustable | |
19 | platform for organizations who want to invest in Go. | |
20 | ||
21 | For more details, see | |
22 | [the motivating blog post](http://peter.bourgon.org/go-kit) and | |
23 | [the video of the talk](https://www.youtube.com/watch?v=iFR_7AKkJFU). | |
10 | 24 | |
11 | 25 | ## Goals |
12 | 26 | |
13 | - Operate in a heterogeneous SOA — expect to interact with mostly non-gokit services | |
27 | - Operate in a heterogeneous SOA — expect to interact with mostly non-Go-kit services | |
14 | 28 | - RPC as the primary messaging pattern |
15 | 29 | - Pluggable serialization and transport — not just JSON over HTTP |
16 | - Zipkin-compatible request tracing | |
30 | - Operate within existing infrastructures — no mandates for specific tools or technologies | |
17 | 31 | |
18 | 32 | ## Non-goals |
19 | 33 | |
20 | - Supporting messaging patterns other than RPC (in the initial release) — pub/sub, CQRS, etc. | |
34 | - Supporting messaging patterns other than RPC (in the initial release) — MPI, pub/sub, CQRS, etc. | |
35 | - Re-implementing functionality that can be provided by wrapping existing packages | |
21 | 36 | - Having opinions on deployment, orchestration, process supervision, etc. |
22 | 37 | - Having opinions on configuration passing — flags, env vars, files, etc. |
23 | 38 | |
28 | 43 | - [`package server`](https://github.com/go-kit/kit/tree/master/server) — **implemented** |
29 | 44 | - [`package transport`](https://github.com/go-kit/kit/tree/master/transport) — **implemented** |
30 | 45 | - [`package log`](https://github.com/go-kit/kit/tree/master/log) — **implemented** |
31 | - [`package tracing`](https://github.com/go-kit/kit/tree/master/tracing) — prototyping | |
32 | - `package client` — pending | |
46 | - [`package tracing`](https://github.com/go-kit/kit/tree/master/tracing) — Zipkin supported, Appdash coming | |
33 | 47 | - Service discovery — pending |
34 | ||
35 | ## Contributing | |
36 | ||
37 | Please see [CONTRIBUTING.md]. Thank you, [contributors]! | |
38 | ||
39 | [CONTRIBUTING.md]: /CONTRIBUTING.md | |
40 | [contributors]: https://github.com/go-kit/kit/graphs/contributors | |
41 | 48 | |
42 | 49 | ### Dependency management |
43 | 50 | |
48 | 55 | |
49 | 56 | We will use a variety of continuous integration providers to find and fix |
50 | 57 | compatibility problems as soon as they occur. |
58 | ||
59 | ## Contributing | |
60 | ||
61 | Please see [CONTRIBUTING.md]. Thank you, [contributors]! | |
62 | ||
63 | [CONTRIBUTING.md]: /CONTRIBUTING.md | |
64 | [contributors]: https://github.com/go-kit/kit/graphs/contributors | |
51 | 65 | |
52 | 66 | ### API stability policy |
53 | 67 |
0 | 0 | # addsvc |
1 | 1 | |
2 | addsvc is an example service, used to illustrate the mechanics of gokit. | |
3 | It exposes simple functionality on a variety of transports and endpoints. | |
2 | addsvc is an example service, used to illustrate the mechanics of Go kit. It | |
3 | exposes a single method to add two integers on a variety of transports and | |
4 | endpoints. | |
5 | ||
6 | ## Highlights | |
7 | ||
8 | ### Configuration via flags | |
9 | ||
10 | Go kit has no strong opinions about how to pass configuration to your service. | |
11 | If your organization has established conventions to pass configuration into | |
12 | your service, Go kit won't stand in your way. That said, package flag is a | |
13 | good default: it's simple, well-understood, and provides a self-documenting | |
14 | configuration surface area. Keeping with | |
15 | [best practices](http://peter.bourgon.org/go-in-production/#configuration), flags | |
16 | are defined in func main. | |
17 | ||
18 | ### Declarative composition | |
19 | ||
20 | Go kit strongly favors explicit, declarative composition of interacting | |
21 | components via a comprehensive func main. Time spent in keystrokes is made up | |
22 | many, many times over when returning to the code and understanding exactly | |
23 | what's happening, without having to unravel indirections or abstractions. | |
24 | ||
25 | ### Multiple transports | |
26 | ||
27 | Go kit treats transports — HTTP, Thrift, gRPC, etc. — as pluggable. The same | |
28 | service can be exposed on any, or multiple, available transports. The addsvc | |
29 | example demonstrates how to make the same business logic available over | |
30 | multiple transports simultaneously. | |
31 | ||
32 | ### Daemonizing | |
33 | ||
34 | Go kit has no strong opinions about how to daemonize, supervise, or run your | |
35 | service. If your organization has established conventions for running | |
36 | services. Go kit won't stand in your way. Go kit services run equally well as | |
37 | manually-copied binaries; applications provisioned with configuration | |
38 | management tools like [Chef][], [Puppet][], or [Ansible][]; in containers like | |
39 | [Docker][] or [rkt][]; or as part of a comprehensive scheduling platform like | |
40 | [Kubernetes][], [Mesos][], [OpenStack][], [Deis][], etc. | |
41 | ||
42 | [Chef]: https://www.chef.io | |
43 | [Puppet]: https://puppetlabs.com | |
44 | [Ansible]: http://www.ansible.com | |
45 | [Docker]: http://docker.com | |
46 | [rkt]: https://github.com/coreos/rkt | |
47 | [Kubernetes]: http://kubernetes.io | |
48 | [Mesos]: https://mesosphere.com | |
49 | [OpenStack]: https://www.openstack.org | |
50 | [Deis]: http://deis.io | |
4 | 51 | |
5 | 52 | ## Server |
6 | 53 | |
7 | 54 | To build and run addsvc, |
8 | 55 | |
9 | 56 | ``` |
10 | $ go install | |
11 | $ addsvc | |
57 | go install | |
58 | addsvc | |
12 | 59 | ``` |
13 | 60 | |
14 | 61 | ## Client |
16 | 16 | |
17 | 17 | // proxyAdd returns an implementation of Add that invokes a remote Add |
18 | 18 | // service. |
19 | func proxyAdd(e endpoint.Endpoint, logger log.Logger) Add { | |
19 | func proxyAdd(remote endpoint.Endpoint, logger log.Logger) Add { | |
20 | 20 | return func(ctx context.Context, a, b int64) int64 { |
21 | resp, err := e(ctx, &addRequest{a, b}) | |
21 | resp, err := remote(ctx, &addRequest{a, b}) | |
22 | 22 | if err != nil { |
23 | 23 | logger.Log("err", err) |
24 | 24 | return 0 |
47 | 47 | thriftBufferSize = fs.Int("thrift.buffer.size", 0, "0 for unbuffered") |
48 | 48 | thriftFramed = fs.Bool("thrift.framed", false, "true to enable framing") |
49 | 49 | |
50 | proxyHTTPAddr = fs.String("proxy.http.url", "", "if set, proxy requests over HTTP to this addsvc") | |
50 | proxyHTTPURL = fs.String("proxy.http.url", "", "if set, proxy requests over HTTP to this addsvc") | |
51 | 51 | |
52 | 52 | zipkinServiceName = fs.String("zipkin.service.name", "addsvc", "Zipkin service name") |
53 | 53 | zipkinCollectorAddr = fs.String("zipkin.collector.addr", "", "Zipkin Scribe collector address (empty will log spans)") |
108 | 108 | |
109 | 109 | // Our business and operational domain |
110 | 110 | var a Add = pureAdd |
111 | if *proxyHTTPAddr != "" { | |
111 | if *proxyHTTPURL != "" { | |
112 | 112 | codec := jsoncodec.New() |
113 | 113 | makeResponse := func() interface{} { return &addResponse{} } |
114 | 114 | |
115 | 115 | var e endpoint.Endpoint |
116 | e = httptransport.NewClient(*proxyHTTPAddr, codec, makeResponse, httptransport.ClientBefore(zipkin.ToRequest(zipkinSpanFunc))) | |
116 | e = httptransport.NewClient(*proxyHTTPURL, codec, makeResponse, httptransport.ClientBefore(zipkin.ToRequest(zipkinSpanFunc))) | |
117 | 117 | e = zipkin.AnnotateClient(zipkinSpanFunc, zipkinCollector)(e) |
118 | 118 | |
119 | 119 | a = proxyAdd(e, logger) |
0 | 0 | package main |
1 | 1 | |
2 | // The request and response types should be annotated sufficiently for all | |
2 | // The concrete request and response types are defined for each method our | |
3 | // service implements. Request types should be annotated sufficiently for all | |
3 | 4 | // transports we intend to use. |
4 | 5 | |
5 | 6 | type addRequest struct { |
0 | 0 | # package tracing |
1 | 1 | |
2 | `package tracing` provides [Dapper-style][dapper] request tracing to services. | |
2 | `package tracing` provides [Dapper][]-style request tracing to services. | |
3 | 3 | An implementation exists for [Zipkin][]; [Appdash][] support is planned. |
4 | 4 | |
5 | [dapper]: http://research.google.com/pubs/pub36356.html | |
5 | [Dapper]: http://research.google.com/pubs/pub36356.html | |
6 | 6 | [Zipkin]: https://blog.twitter.com/2012/distributed-systems-tracing-with-zipkin |
7 | 7 | [Appdash]: https://sourcegraph.com/blog/117580140734 |
8 | 8 | |
9 | 9 | ## Rationale |
10 | 10 | |
11 | TODO | |
11 | Request tracing is a fundamental building block for large distributed | |
12 | applications. It's instrumental in understanding request flows, identifying | |
13 | hot spots, and diagnosing errors. All microservice infrastructures will | |
14 | benefit from request tracing; sufficiently large infrastructures will require | |
15 | it. | |
12 | 16 | |
13 | 17 | ## Usage |
14 | 18 | |
15 | Wrap a [server.Endpoint][] so that it emits traces to a Zipkin collector. | |
19 | Wrap a server- or client-side [endpoint][] so that it emits traces to a Zipkin | |
20 | collector. | |
16 | 21 | |
17 | [server.Endpoint]: http://godoc.org/github.com/go-kit/kit/server#Endpoint | |
22 | [endpoint]: http://godoc.org/github.com/go-kit/kit/endpoint#Endpoint | |
18 | 23 | |
19 | 24 | ```go |
20 | 25 | func main() { |
24 | 29 | scribeHost = "scribe.internal.net" |
25 | 30 | timeout = 50 * time.Millisecond |
26 | 31 | batchSize = 100 |
27 | batchInterval = 3 * time.Second | |
32 | batchInterval = 5 * time.Second | |
28 | 33 | ) |
29 | ||
30 | 34 | spanFunc := zipkin.NewSpanFunc(myHost, myMethod) |
31 | 35 | collector, _ := zipkin.NewScribeCollector(scribeHost, timeout, batchSize, batchInterval) |
32 | 36 | |
33 | var e server.Endpoint | |
34 | e = makeEndpoint() // for your service | |
35 | e = zipkin.AnnotateEndpoint(spanFunc, collector) | |
37 | // Server-side | |
38 | var server endpoint.Endpoint | |
39 | server = makeEndpoint() // for your service | |
40 | server = zipkin.AnnotateServer(spanFunc, collector)(server) | |
41 | go serveViaHTTP(server) | |
36 | 42 | |
37 | serve(e) | |
43 | // Client-side | |
44 | before := httptransport.ClientBefore(zipkin.ToRequest(spanFunc)) | |
45 | var client endpoint.Endpoint | |
46 | client = httptransport.NewClient(addr, codec, factory, before) | |
47 | client = zipkin.AnnotateClient(spanFunc, collector)(client) | |
38 | 48 | } |
39 | 49 | ``` |