Files
website/content/en/blog/_posts/2018-11-07-grpc-load-balancing-with-linkerd.md
Jim Angel 851ef58fa8 Official 1.14 Release Docs (#13174)
* Official documentation on Poseidon/Firmament, a new multi-scheduler support for K8S. (#11752)

* Added documentation about Poseidon-Firmament scheduler

* Fixed some style issues.

* Udpated the document as per the review comments.

* Fixed some typos and updated the document

* Updated the document as per the review comments.

* Document timeout attribute for kms-plugin. (#12158)

See 72540.

* Official documentation on Poseidon/Firmament, a new multi-scheduler  (#12343)

* Removed the old version of the Poseidon documentation. Incorrect location.

* Official documentation on Poseidon/Firmament, a new multi-scheduler support for K8S (#12069)

* Official documentation on Poseidon/Firmament, a new multi-scheduler support for K8S. (#11752)

* Added documentation about Poseidon-Firmament scheduler

* Fixed some style issues.

* Udpated the document as per the review comments.

* Fixed some typos and updated the document

* Updated the document as per the review comments.

* Updated the document as per review comments. Added config details.

* Updated the document as per the latest review comments. Fixed nits

* Made changes as per latest suggestions.

* Some more changes added.

* Updated as per suggestions.

* Changed the release process section.

* SIG Docs edits

Small edits to match style guidelines.

* add plus to feature state

* capitalization

* revert feature state shortcode

since this is a Kubernetes extension, not a direct feature, it shouldn't use the regular feature state tagging.

(cherry picked from commit 7730c1540b)

* Remove initializers from doc. It will be removed in 1.14 (#12331)

* kubeadm: Document CRI auto detection functionality (#12462)

Signed-off-by: Rostislav M. Georgiev <rostislavg@vmware.com>

* Minor doc change for GAing Pod DNS Config (#12514)

* Graduate ExpandInUsePersistentVolumes feature to beta (#10574)

* Rename 2018-11-07-grpc-load-balancing-with-linkerd.md.md file (#12594)

* Add dynamic percentage of node scoring to user docs (#12235)

* Add dynamic percentage of node scoring to user docs

* addressed review comments

* delete special symbol (#12445)

* Update documentation for VolumeSubpathEnvExpansion (#11843)

* Update documentation for VolumeSubpathEnvExpansion

* Address comments - improve descriptions

* Graduate Pod Priority and Preemption to GA (#12428)

* Added Instana links to the documentation (#12977)

* Added link to the Instana Kubernetes integration

* Added Instana link for services section

Added Instana and a link to the Kubernetes integration to the analytics services section and broadened the scope to APM, monitoring and analytics.

* Oxford comma /flex

* More Oxford commas, because they matter

* Update kubectl plugins to stable (#12847)

* documentation for CSI topology beta (#12889)

* Document changes to default RBAC discovery ClusterRole(Binding)s (#12888)

* Document changes to default RBAC discovery ClusterRole(Binding)s

Documentation for https://github.com/kubernetes/enhancements/issues/789 and https://github.com/kubernetes/kubernetes/pull/73807

* documentation review feedback

* CSI raw block to beta (#12931)

* Change incorrect string raw to block (#12926)

Fixes #12925

* Update documentation on node OS/arch labels (#12976)

These labels have been promoted to GA:
https://github.com/kubernetes/enhancements/issues/793

* local pv GA doc updates (#12915)

* Publish CRD OpenAPI Documentation (#12910)

* add documentation for CustomResourcePublishOpenAPI

* address comments

fix links, ordered lists, style and typo

* kubeadm: add document for upgrading from 1.13 to 1.14 (single CP and HA) (#13189)

* kubeadm: add document for upgrading from 1.13 to 1.14

- remove doc for upgrading 1.10 -> 1.11

* kubeadm: apply amends to upgrade-1.14 doc

* kubeadm: apply amends to upgrade-1.14 doc (part2)

* kubeadm: apply amends to upgrade-1.14 doc (part3)

* kubeadm: add note about "upgrade node experimental-control-plane"

+ add comment about `upgrade plan`

* kubeadm: add missing "You should see output similar to this"

* fix bullet indentation (#13214)

* mark PodReadinessGate GA (#12800)

* Update RuntimeClass documentation for beta (#13043)

* Update RuntimeClass documentation for beta

* Update feature gate & add upgrade section

* formatting fixes

* Highlight upgrade action required

* Address feedback

* CSI ephemeral volume alpha documentation (#10934)

* update kubectl documentation (#12867)

* update kubectl documentation

* add document for Secret/ConfigMap generators

* replace `kubectl create -f` by `kubectl apply -f`

* Add page for kustomization support in kubectl

* fix spelling errors and address comments

* Documentation for Windows GMSA feature (#12936)

* Documentation for Windows GMSA feature

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Enhancements to GMSA docs

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Fix links

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Fix GMSA link

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Add GMSA feature flag in feature flag list

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Relocate GMSA to container configuration

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Add example for container spec

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Remove changes in Windows index

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Update configure-gmsa.md

* Update configure-gmsa.md

* Update configure-gmsa.md

* Update configure-gmsa.md

* Rearrange the steps into two sections and other edits

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Fix links

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Add reference to script to generate GMSA YAMLs

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Some more clarifications for GMSA

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* HugePages graduated to GA (#13004)

* HugePages graduated to GA

* fixing nit for build

* Docs for node PID limiting (https://github.com/kubernetes/kubernetes/pull/73651) (#12932)

* kubeadm: update the reference documentation for 1.14 (#12911)

* kubeadm: update list of generated files for 1.14

NOTE: PLACEHOLDERS! these files are generated by SIG Docs each
release, but we need them to pass the k/website PR CI.

- add join_phase* (new sub phases of join)
- add init_phase_upload-certs.md (new upload certs phase for init)
- remove alpha-preflight (now both init and join have this)

* kubeadm: update reference docs includes for 1.14

- remove includes from alpha.md
- add upload-certs to init-phase.md
- add join-phase.md and it's phases

* kubeadm: update the editorial content of join and init

- cleanup master->control-plane node
- add some notes about phases and join
- remove table about pre-pulling images
- remove outdated info about self-hosting

* kubeadm: update target release for v1alpha3 removal

1.14 -> 1.15

* kubeadm: copy edits for 1.14 reference docs (part1)

* kubeadm: use "shell" for code blocks

* kubeadm: update the 1.14 HA guide (#13191)

* kubeadm: update the 1.14 HA guide

* kubeadm: try to fix note/caution indent in HA page

* kubeadm: fix missing sudo and minor amends in HA doc

* kubeadm: apply latest amends to the HA doc for 1.14

* fixed a few missed merge conflicts

* Admission Webhook new features doc (#12938)

- kubernetes/kubernetes#74998
- kubernetes/kubernetes#74477
- kubernetes/kubernetes#74562

* Clarifications and fixes in GMSA doc (#13226)

* Clarifications and fixes in GMSA doc

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Update configure-gmsa.md

* Reformat to align headings and pre-reqs better

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Reformat to align headings and pre-reqs better

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Reformat to fix bullets

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Reword application of sample gmsa

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Update configure-gmsa.md

* Address feedback to use active voice

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Address feedback to use active voice

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* RunAsGroup documentation for Progressing this to Beta (#12297)

* start serverside-apply documentation (#13077)

* start serverside-apply documentation

* add more concept info on server side apply

* Update api concepts

* Update api-concepts.md

* fix style issues

* Document CSI update (#12928)

* Document CSI update

* Finish CSI documentation

Also fix mistake with  ExpandInUsePersistentVolumes documented as beta

* Overall docs for CSI Migration feature (#12935)

* Placeholder docs for CSI Migration feature

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Address CR comments and update feature gates

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Add mappings for CSI plugins

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Add sections for AWS and GCE PD migration

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Add docs for Cinder and CSI Migration info

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Clarify scope to volumes with file system

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Change the format of EBS and Cinder CSI Migration sections to follow the GCE template

Signed-off-by: Deep Debroy <ddebroy@docker.com>

* Windows documentation updates for 1.14 (#12929)

* Updated the note to indicate doc work for 1.14

* first attempt at md export from gdoc

* simplifyig

* big attempt

* moving DRAFT windows content to PR for review

* moving content to PR in markdown for review

* updated note tags

* Delete windows-contributing.md

deleting this file as it is already ported to the github contributor guide

* fixed formatting in intro and cluster setup guide

* updating formatting for running containers guide

* rejiggered end of troubleshooting

* fixed minor typos

* Clarified the windows binary download step

* Update _index.md

making updates based on feedback

* Update _index.md

updating ovn-kubernetes docs

* Update _index.md

* Update _index.md

* updating relative docs links

updating all the links to be relative links to /docs

* Update _index.md

* Update _index.md

updates for windows services and ovn-kubernetes

* formatted for correct step numbering

* fix typos

* Update _index.md

updates for flannel PR in troubleshooting

* Update _index.md

* Update _index.md

updating a few sections like roadmap, services, troubleshooting/filing tickets

* Update _index.md

* Update _index.md

* Update _index.md

* Fixed a few whitespace issues

* Update _index.md

* Update _index.md

* Update _index.md

* add section on upgrading CoreDNS (#12909)

* documentation for kubelet resource metrics endpoint (#12934)

* windows docs updates for 1.14 (#13279)

* Delete sample-l2bridge-wincni-config.json

this file is not used anywhere

* Update _index.md

* Update _index.md

* Update _index.md

* Update _index.md

* Update _index.md

* Rename content/en/docs/getting-started-guides/windows/_index.md to content/en/docs/setup/windows/_index.md

moving to new location

* Delete flannel-master-kubectl-get-ds.png

* Delete flannel-master-kubeclt-get-pods.png

* Delete windows-docker-error.png

* Add files via upload

* Rename _index.md to add-windows-nodes.md

* Create _index.md

* Update _index.md

* Update add-windows-nodes.md

* Update add-windows-nodes.md

* Create user-guide-windows-nodes.md

* Create user-guide-windows-containers.md

* Update and rename add-windows-nodes.md to intro-windows-nodes.md

* Update user-guide-windows-containers.md

* Rename intro-windows-nodes.md to intro-windows-in-kubernetes.md

* Update user-guide-windows-nodes.md

* Update user-guide-windows-containers.md

* Update user-guide-windows-containers.md

* Update user-guide-windows-nodes.md

* Update user-guide-windows-containers.md

* Update _index.md

* Update intro-windows-in-kubernetes.md

* Update intro-windows-in-kubernetes.md

fixing the pause image

* Update intro-windows-in-kubernetes.md

changing tables from html to MD

* Update user-guide-windows-nodes.md

converting tables from HTML to MD

* Update intro-windows-in-kubernetes.md

* Update user-guide-windows-nodes.md

* Update user-guide-windows-nodes.md

* Update user-guide-windows-nodes.md

updating the numbering , even though it messes up the notes a little bit. Jim will file a ticket to follow up

* Update user-guide-windows-nodes.md

* update to windows docs for 1.14 (#13322)

* Update intro-windows-in-kubernetes.md

* Update intro-windows-in-kubernetes.md

* Update intro-windows-in-kubernetes.md

* Update intro-windows-in-kubernetes.md

* Update intro-windows-in-kubernetes.md

* Update user-guide-windows-containers.md

* Update user-guide-windows-nodes.md

* Update intro-windows-in-kubernetes.md (#13344)

* server side apply followup (#13321)

* change some parts of serverside apply docs in response to comments

* fix typos and wording

* Update config.toml (#13365)
2019-03-25 15:06:16 -07:00

173 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
layout: blog
title: 'gRPC Load Balancing on Kubernetes without Tears'
date: 2018-11-07
---
**Author**: William Morgan (Buoyant)
Many new gRPC users are surprised to find that Kubernetes's default load
balancing often doesn't work out of the box with gRPC. For example, here's what
happens when you take a [simple gRPC Node.js microservices
app](https://github.com/sourishkrout/nodevoto) and deploy it on Kubernetes:
![](/images/blog/grpc-load-balancing-with-linkerd/Screenshot2018-11-0116-c4d86100-afc1-4a08-a01c-16da391756dd.34.36.png)
While the `voting` service displayed here has several pods, it's clear from
Kubernetes's CPU graphs that only one of the pods is actually doing any
work&mdash;because only one of the pods is receiving any traffic. Why?
In this blog post, we describe why this happens, and how you can easily fix it
by adding gRPC load balancing to any Kubernetes app with
[Linkerd](https://linkerd.io), a [CNCF](https://cncf.io) service mesh and service sidecar.
# Why does gRPC need special load balancing?
First, let's understand why we need to do something special for gRPC.
gRPC is an increasingly common choice for application developers. Compared to
alternative protocols such as JSON-over-HTTP, gRPC can provide some significant
benefits, including dramatically lower (de)serialization costs, automatic type
checking, formalized APIs, and less TCP management overhead.
However, gRPC also breaks the standard connection-level load balancing,
including what's provided by Kubernetes. This is because gRPC is built on
HTTP/2, and HTTP/2 is designed to have a single long-lived TCP connection,
across which all requests are *multiplexed*&mdash;meaning multiple requests can be
active on the same connection at any point in time. Normally, this is great, as
it reduces the overhead of connection management. However, it also means that
(as you might imagine) connection-level balancing isn't very useful. Once the
connection is established, there's no more balancing to be done. All requests
will get pinned to a single destination pod, as shown below:
![](/images/blog/grpc-load-balancing-with-linkerd/Mono-8d2e53ef-b133-4aa0-9551-7e36a880c553.png)
# Why doesn't this affect HTTP/1.1?
The reason why this problem doesn't occur in HTTP/1.1, which also has the
concept of long-lived connections, is because HTTP/1.1 has several features
that naturally result in cycling of TCP connections. Because of this,
connection-level balancing is "good enough", and for most HTTP/1.1 apps we
don't need to do anything more.
To understand why, let's take a deeper look at HTTP/1.1. In contrast to HTTP/2,
HTTP/1.1 cannot multiplex requests. Only one HTTP request can be active at a
time per TCP connection. The client makes a request, e.g. `GET /foo`, and then
waits until the server responds. While that request-response cycle is
happening, no other requests can be issued on that connection.
Usually, we want lots of requests happening in parallel. Therefore, to have
concurrent HTTP/1.1 requests, we need to make multiple HTTP/1.1 connections,
and issue our requests across all of them. Additionally, long-lived HTTP/1.1
connections typically expire after some time, and are torn down by the client
(or server). These two factors combined mean that HTTP/1.1 requests typically
cycle across multiple TCP connections, and so connection-level balancing works.
# So how do we load balance gRPC?
Now back to gRPC. Since we can't balance at the connection level, in order to
do gRPC load balancing, we need to shift from connection balancing to *request*
balancing. In other words, we need to open an HTTP/2 connection to each
destination, and balance *requests* across these connections, as shown below:
![](/images/blog/grpc-load-balancing-with-linkerd/Stereo-09aff9d7-1c98-4a0a-9184-9998ed83a531.png)
In network terms, this means we need to make decisions at L5/L7 rather than
L3/L4, i.e. we need to understand the protocol sent over the TCP connections.
How do we accomplish this? There are a couple options. First, our application
code could manually maintain its own load balancing pool of destinations, and
we could configure our gRPC client to [use this load balancing
pool](https://godoc.org/google.golang.org/grpc/balancer). This approach gives
us the most control, but it can be very complex in environments like Kubernetes
where the pool changes over time as Kubernetes reschedules pods. Our
application would have to watch the Kubernetes API and keep itself up to date
with the pods.
Alternatively, in Kubernetes, we could deploy our app as [headless
services](/docs/concepts/services-networking/service/#headless-services).
In this case, Kubernetes [will create multiple A
records](/docs/concepts/services-networking/service/#headless-services)
in the DNS entry for the service. If our gRPC client is sufficiently advanced,
it can automatically maintain the load balancing pool from those DNS entries.
But this approach restricts us to certain gRPC clients, and it's rarely
possible to only use headless services.
Finally, we can take a third approach: use a lightweight proxy.
# gRPC load balancing on Kubernetes with Linkerd
[Linkerd](https://linkerd.io) is a [CNCF](https://cncf.io)-hosted *service
mesh* for Kubernetes. Most relevant to our purposes, Linkerd also functions as
a *service sidecar*, where it can be applied to a single service&mdash;even without
cluster-wide permissions. What this means is that when we add Linkerd to our
service, it adds a tiny, ultra-fast proxy to each pod, and these proxies watch
the Kubernetes API and do gRPC load balancing automatically. Our deployment
then looks like this:
![](/images/blog/grpc-load-balancing-with-linkerd/Linkerd-8df1031c-cdd1-4164-8e91-00f2d941e93f.io.png)
Using Linkerd has a couple advantages. First, it works with services written in
any language, with any gRPC client, and any deployment model (headless or not).
Because Linkerd's proxies are completely transparent, they auto-detect HTTP/2
and HTTP/1.x and do L7 load balancing, and they pass through all other traffic
as pure TCP. This means that everything will *just work.*
Second, Linkerd's load balancing is very sophisticated. Not only does Linkerd
maintain a watch on the Kubernetes API and automatically update the load
balancing pool as pods get rescheduled, Linkerd uses an *exponentially-weighted
moving average* of response latencies to automatically send requests to the
fastest pods. If one pod is slowing down, even momentarily, Linkerd will shift
traffic away from it. This can reduce end-to-end tail latencies.
Finally, Linkerd's Rust-based proxies are incredibly fast and small. They
introduce <1ms of p99 latency and require <10mb of RSS per pod, meaning that
the impact on system performance will be negligible.
# gRPC Load Balancing in 60 seconds
Linkerd is very easy to try. Just follow the steps in the [Linkerd Getting
Started Instructions](https://linkerd.io/2/getting-started/)&mdash;install the
CLI on your laptop, install the control plane on your cluster, and "mesh" your
service (inject the proxies into each pod). You'll have Linkerd running on your
service in no time, and should see proper gRPC balancing immediately.
Let's take a look at our sample `voting` service again, this time after
installing Linkerd:
![](/images/blog/grpc-load-balancing-with-linkerd/Screenshot2018-11-0116-24b8ee81-144c-4eac-b73d-871bbf0ea22e.57.42.png)
As we can see, the CPU graphs for all pods are active, indicating that all pods
are now taking traffic&mdash;without having to change a line of code. Voila,
gRPC load balancing as if by magic!
Linkerd also gives us built-in traffic-level dashboards, so we don't even need
to guess what's happening from CPU charts any more. Here's a Linkerd graph
that's showing the success rate, request volume, and latency percentiles of
each pod:
![](/images/blog/grpc-load-balancing-with-linkerd/Screenshot2018-11-0212-15ed0448-5424-4e47-9828-20032de868b5.08.38.png)
We can see that each pod is getting around 5 RPS. We can also see that, while
we've solved our load balancing problem, we still have some work to do on our
success rate for this service. (The demo app is built with an intentional
failure&mdash;as an exercise to the reader, see if you can figure it out by
using the Linkerd dashboard!)
# Wrapping it up
If you're interested in a dead simple way to add gRPC load balancing to your
Kubernetes services, regardless of what language it's written in, what gRPC
client you're using, or how it's deployed, you can use Linkerd to add gRPC load
balancing in a few commands.
There's a lot more to Linkerd, including security, reliability, and debugging
and diagnostics features, but those are topics for future blog posts.
Want to learn more? Wed love to have you join our rapidly-growing community!
Linkerd is a [CNCF](https://cncf.io) project, [hosted on
GitHub](https://github.com/linkerd/linkerd2), and has a thriving community
on [Slack](https://slack.linkerd.io), [Twitter](https://twitter.com/linkerd),
and the [mailing lists](https://lists.cncf.io/g/cncf-linkerd-users). Come and
join the fun!