Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go kit: the road ahead #843

Open
peterbourgon opened this issue Mar 4, 2019 · 20 comments
Open

Go kit: the road ahead #843

peterbourgon opened this issue Mar 4, 2019 · 20 comments
Assignees

Comments

@peterbourgon
Copy link
Member

peterbourgon commented Mar 4, 2019

Go kit: the road ahead

  • This is a tracking issue for broad changes to the Go kit project
  • Expect edits and updates
  • No ETA at this time

Context

  • The microservices ecosystem has matured since Go kit's introduction
  • Many responsibilities have, sensibly, moved to the platform/infrastructure
  • Go kit has, accordingly, reduced its scope of responsibilities in practice
  • Go kit is less about specific components or integrations, more about good application architecture
  • The next iteration of the project should reflect this reality
  • Keep and refocus on the good and useful parts, deprecate the less-useful parts

Keep

  • package transport - necessary and valuable
  • package endpoint - required for service/transport interop, pending generics
  • package log - has clearly proved its value in the test of time
  • package tracing - has also proved its value
  • package examples - move to new or individual repos

Undecided

  • package metrics - pending broader re-think and refactor
  • kitgen - ownership is unclear
  • package auth - I can't easily judge usefulness; seeking comment

Sunset

  • package ratelimit - less useful in modern platforms, easy to bolt-on with generic middleware
  • package circuitbreaker - less useful in modern platforms, easy to bolt-on with generic middleware
  • package sd - less useful in modern platforms, many test flakes, a maintenance headache

Additional changes

  • Rewrite website with new focus on architectural design and best practice
  • New, expanded tutorial(s) based on lessons learned in my consulting work

Coda: repos

  • One option is to break each package (or package-group) into its own repo under the go-kit org
  • Another is to retain the existing kit repo, and use version tagging
  • The latter is slightly more appealing to me, for continuity and visibility reasons

Coda: generics

  • Generics, if/when they come, will change relationship between transport and service
  • I expect the endpoint layer will no longer be necessary
  • It's too early to say more

Errata

  • Do transport- and service-level errors need to be kept so distinct? #807
@peterbourgon peterbourgon self-assigned this Mar 4, 2019
@peterbourgon peterbourgon pinned this issue Mar 5, 2019
@sagikazarmark
Copy link
Contributor

sagikazarmark commented Oct 16, 2019

package metrics - pending broader re-think and refactor

With OpenCensus and OpenTelemetry the abstraction is kinda moved to the platform layer. I would say the same is true for tracing.

package auth - I can't easily judge usefulness; seeking comment

I think the implemented auth methods are useful, but need a bit of work. They are also great reference implementations for how auth in a go-kit environment should work. Since auth (sadly) is rarely as simple as basic auth or JWT, chances are people will use customized versions (for example I extended the jwt package with additional token validation).

Do transport- and service-level errors need to be kept so distinct?

This is a huge pain point for me. Not the separation of transport and service level errors, but the fact that the way they are handled is quite inconsistent.

Service level errors are supposed to be encoded by the transport's response encoder, transport level errors are usually encoded by a dedicated error encoder (at least in case of the HTTP server). There is another dimension of errors as well: errors that are "internal" and errors returned to the caller. Both sources (service, transport) can produce both types of errors, but they are "handled" (logged or returned to the caller) separately.

Furthermore, server level error handlers (a third way of error handling, where I usually want to log fatal, internal errors only) receive both encoding/decoding errors (which are still transport errors, but not originated from endpoints, so I guess they are a third type of errors?) and transport level errors returned from endpoints.

The way I see it, errors are either returned to the caller (usually not logged, because they are business/client errors) or logged (and the caller receives a generic "internal" error). Both service and transport level can produce both types of errors.

I opened a separate issue with an example: #923

@basvanbeek
Copy link
Member

Disagree with punting native tracing plugability for standard OTel middleware. OTel is a giant shitshow so far.

@sagikazarmark
Copy link
Contributor

TBH I've seen more marketing than actually working features so far, so moving towards OTel might indeed be a bad idea at this point. Just wanted to point out that tracing and metrics packages might both get deprecated over time in favor of solutions like OpenCensus or OpenTelemetry.

@basvanbeek
Copy link
Member

They won't because the abstractions made are often political compromises and not based on actual value. As an example the Zipkin native ecosystem is very extensive, well tested and continues to be under active development. Having Go kit native tracing abstractions allows for better granularity and consistency across different transports within Go kit as well as better interop in brown field. Even if using OTel there is a place for Go kit native hooks and logic.

@sagikazarmark
Copy link
Contributor

Okay, I think I've just understood that the tracing abstraction layer is actually just integrations for different tracing frameworks, while the metrics package actually provides a separate abstraction layer. I was confused why those two would be treated differently, but I guess having integrations with different systems makes sense.

@yiv
Copy link

yiv commented Apr 3, 2020

How to understand "I expect the endpoint layer will no longer be necessary"

@ppipada
Copy link

ppipada commented May 12, 2020

package examples - move to new or individual repos

go modules supports multiple modules per repository. Can we consider examples being a sub module that depends on the go-kit main module? A pain point when doing this is adding versions to individual modules separately. But for examples package it could be fine.

@sagikazarmark
Copy link
Contributor

sagikazarmark commented Jun 17, 2020

Here is a Go kit example with the latest generics proposal: https://go2goplay.golang.org/p/vpUyP0j6cwH

Update: new version reflecting the latest proposal: https://go2goplay.golang.org/p/3wpdReO7leW

@mcesar
Copy link

mcesar commented Jun 17, 2020

Here is a Go kit example with the latest generics proposal: https://go2goplay.golang.org/p/vpUyP0j6cwH

I fiddled a little bit with the example in order to use a service interface and to highlight the code that can be generated by a tool:
https://go2goplay.golang.org/p/HcHSbBHAVd4

@monmohan
Copy link

Sunset
package ratelimit - less useful in modern platforms, easy to bolt-on with generic middleware

I think one of the reasons is that in practice, with microservices, per-node fine-grained rate limiting is rarely used (as with https://godoc.org/golang.org/x/time/rate ) . Additionally depending on one's infrastructure, it could be challenging to implement token bucket (or leaky bucket) with their fixed rate token addition requirement. When doing global rate limiting (needed for pretty much any real world use case), latency and storage overhead per request, are important constraints at scale.

In our org, we use this implementation, https://github.com/monmohan/rate-limiting and it has worked really well for us. We handle ~400K rpm traffic consistently with this rate limiter with extremely low overhead. Its based on a report by Cloudflare, where they use this implementation to handle a tonne of traffic (way higher than ours)

IMHO, One option is that the go-kit package should contain a real world production ready rate-limiter. Another option is to have a separate project where some of these real-world "third-party" packages are kept. Users of go-kit can pick and chose them as bolt-on middleware

M

@sev3ryn
Copy link

sev3ryn commented Oct 6, 2020

my 5 cents here - I believe package log should be separated to its own repo. Its imported by external projects much more than other packages from go-kit. But right now importing just log package adds lots of unwanted entries to go.sum which is quite bothering for everyone who care about "dependency hygiene".

E.g. see related issue from Prometheus (who is user of kit/log package) prometheus/common#255

@peterbourgon
Copy link
Member Author

We will probably extract log to its own package, but two notes about your comment:

  • Importing go-kit/kit/log does bring in the whole Go kit module as a dependency, but your compiled artifact should only include the specific packages you use, so it's not really an issue at that level
  • go.sum is an append-only log of checksums used to verify module integrity in general, it really has no relationship to the actual dependencies of a module or dependency hygiene, as a user you should just ignore it

@sagikazarmark
Copy link
Contributor

but your compiled artifact should only include the specific packages you use, so it's not really an issue at that level

True, but there are two major issues with Go modules dependencies download:

  • Packages without go.mod are always downloaded, no matter what (even if they won't be in the resulting binary)
  • go mod download downloads everything. It is commonly used for populating caches (eg. in docker builds)

These two can dramatically increase build times and affect a lot of users.

@peterbourgon
Copy link
Member Author

What should be the rule for defining a "module boundary" going forward? package log was pretty straightforward, but should each e.g. transport package be it's own module? I can think of good reasons to do it that way: technically, dependency isolation; logistically, release and maturity isolation; probably others.

@sagikazarmark
Copy link
Contributor

Dependency isolation sounds like the most compelling argument from Go's perspective.

Maintenance is certainly another issue with everything in a single core: do you deprecate certain components while it's in the main repo? Can you selectively apply maintenance policy without confusing users?

It might be a wild idea, but if manage to eliminate the endpoint layer (which I'm still not sure we can), the core module might disappear entirely: from the Keep section above:

  • endpoint disappears
  • transport would become separate modules
  • tracing as well(?)
  • examples is already moved out

From this perspective, it might actually make sense to move out the code that make sense to keep and leave the current kit repo as is for backwards compatibility (unless you want to do sub-go-modules there, but I guess not).

@ghostsquad
Copy link

Now that Golang 1.18rc1 is out, is there a roadmap for using generics here? Last time I used go-kit it was incredibly verbose, and I felt it required either generics or code generation to be productive.

@RussellLuo
Copy link

Go 1.18 is released!

@jagitch
Copy link

jagitch commented Apr 7, 2022

generics is comming

@arinto
Copy link

arinto commented Aug 25, 2022

@peterbourgon : last release is last year, do we plan to keep regular release for this?
Context is: Our app is using go-kit and it's flagged for security issue (due to dependent library, such as nats-io/nats-server). So would like to know whether there will be regular patch to fix security issue.

Another option is to enable dependabot, to ensure dependent library is regularly updated

@peterbourgon
Copy link
Member Author

@peterbourgon : last release is last year, do we plan to keep regular release for this? Context is: Our app is using go-kit and it's flagged for security issue (due to dependent library, such as nats-io/nats-server). So would like to know whether there will be regular patch to fix security issue.

Another option is to enable dependabot, to ensure dependent library is regularly updated

There's no reason to automatically upgrade dependencies in a project like Go kit, as versions are controlled by downstream consumers. Those security issues are generally bogus.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests