Slide 1

Slide 1 text

A Date with gRPC YWC Programmer Meetup 2019

Slide 2

Slide 2 text

Me ● Manatsawin Hanmongkolchai ● Architect at Wongnai - We build the platform for Wongnai of tomorrow ● Owner at TipMe - Donate platform for streamers

Slide 3

Slide 3 text

Today's Agenda ● RPC vs REST ● Brief introduction to gRPC ● gRPC on Kubernetes ● … ??

Slide 4

Slide 4 text

RPC?

Slide 5

Slide 5 text

REST

Slide 6

Slide 6 text

import requests requests.post("http://sealerd/documents/1/seal", json={ "key": 1, })

Slide 7

Slide 7 text

What now?

Slide 8

Slide 8 text

XML? JSON?

Slide 9

Slide 9 text

{ "success": true }

Slide 10

Slide 10 text

{ "response": { "success": true }, "status": 200 }

Slide 11

Slide 11 text

Error handling

Slide 12

Slide 12 text

try: req = requests.post("http://sealerd/documents/1/seal") except requests.HTTPError: print("Server error") return body = req.json() if "error" in body: print(body["error"]) return print("Seal success!!") Why this is not exception?

Slide 13

Slide 13 text

try: req = requests.post("http://sealerd/documents/1/seal") except requests.HTTPError: print("Server error") return body = req.json() if "error" in body: print(body["error"]) return print("Seal success!!") How could I know there is error field? What if load balancer errors?

Slide 14

Slide 14 text

It's not hard to solve It just more boilerplate to write (Or you could make it a library)

Slide 15

Slide 15 text

Then why don't you just use gRPC?

Slide 16

Slide 16 text

gRPC 101

Slide 17

Slide 17 text

Step 1: Write a service declaration

Slide 18

Slide 18 text

syntax = "proto3"; package tipme.sealerd; service Sealerd { rpc Seal (SealRequest) returns (SealResponse); } message SealRequest { string path = 1; } message SealResponse { } Free API Docs, with types!

Slide 19

Slide 19 text

Step 2: Generate

Slide 20

Slide 20 text

python -m grpc_tools.protoc -I=. \ --python_out=. \ --grpc_python_out=. sealerd.proto

Slide 21

Slide 21 text

# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: sealerd/sealerd.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='sealerd/sealerd.proto', package='tipme.sealerd', syntax='proto3', serialized_options=None, serialized_pb=_b('\n\x15sealerd/sealerd.proto\x12\rtipme.sealerd\"\x1b\n\x0bSealRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\"\x0e\n\x0cSealResponse2J\n\x07Sealerd\x12?\n\x04Seal\x12\x1a.tipme.sealerd.SealRequest\x1a\x1b.tipme.sealerd.SealResponseb\x06proto3') ) _SEALREQUEST = _descriptor.Descriptor( name='SealRequest', full_name='tipme.sealerd.SealRequest', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='path', full_name='tipme.sealerd.SealRequest.path', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], serialized_start=40, serialized_end=67,

Slide 22

Slide 22 text

Step 3: Run

Slide 23

Slide 23 text

import grpc from proto_gen.sealerd.sealerd_pb2 import SealRequest from proto_gen.sealerd.sealerd_pb2_grpc import SealerdStub channel = grpc.insecure_channel("sealerd:4000") client = SealerdStub(channel) result = client.Seal(SealRequest(path=path)) print(result)

Slide 24

Slide 24 text

What you get ● Exception on errors ● Typed request & response ● More efficient serialization ● (Optional) Server to server verification & encryption ● Connection reuse ● Load balancing

Slide 25

Slide 25 text

Sounds great?

Slide 26

Slide 26 text

gRPC, in real world, in Kubernetes

Slide 27

Slide 27 text

How Kubernetes do load balancing

Slide 28

Slide 28 text

Kubernetes service balance connections, not calls

Slide 29

Slide 29 text

What we think

Slide 30

Slide 30 text

What we actually get with gRPC

Slide 31

Slide 31 text

What we actually get with gRPC

Slide 32

Slide 32 text

It's even worse: server shutdown

Slide 33

Slide 33 text

Client Server Client Client Server Client Server Connection Reset Service IP

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

Solution

Slide 37

Slide 37 text

1. gRPC client side load balance

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

It's Go only

Slide 40

Slide 40 text

2. Read Kubernetes Blog

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

(Yes, I used their image earlier)

Slide 43

Slide 43 text

2. Use service mesh (Maybe it'll be ready in 2020….)

Slide 44

Slide 44 text

3. Disable connection pool? It'll be slower, but it won't break my infra

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No disable! Only set connection lifetime

Slide 49

Slide 49 text

4. Use REST

Slide 50

Slide 50 text

5. Join guild of gRPC haters

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

import requests requests.post("http://sealerd/twirp/tipme.Sealerd/Seal", json={ "document": 1, "key": 1, })

Slide 54

Slide 54 text

import requests requests.post("http://sealerd/twirp/tipme.Sealerd/Seal", json={ "key": 1, }) but… ● Client library ● Still standardized request/response/error ● Send either Protobuf or JSON = easy to debug ● HTTP 1.1 + Bring your own server = can integrate into existing stack ● No streaming/bidirectional support (yet)

Slide 55

Slide 55 text

Porting

Slide 56

Slide 56 text

Have fun! And pray for service mesh