Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A Date with gRPC

A Date with gRPC

Pain of gRPC on Kubernetes
YWC Programmer Meetup #6

More Decks by Manatsawin Hanmongkolchai

Other Decks in Programming

Transcript

  1. A Date with gRPC
    YWC Programmer Meetup 2019

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. {
    "success": true
    }

    View full-size slide

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

    View full-size slide

  7. Error handling

    View full-size slide

  8. 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?

    View full-size slide

  9. 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?

    View full-size slide

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

    View full-size slide

  11. Then why don't you just use gRPC?

    View full-size slide

  12. Step 1: Write a service declaration

    View full-size slide

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

    View full-size slide

  14. Step 2: Generate

    View full-size slide

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

    View full-size slide

  16. # -*- 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,

    View full-size slide

  17. 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)

    View full-size slide

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

    View full-size slide

  19. Sounds great?

    View full-size slide

  20. gRPC, in real world, in Kubernetes

    View full-size slide

  21. How Kubernetes do load balancing

    View full-size slide

  22. Kubernetes service balance
    connections, not calls

    View full-size slide

  23. What we think

    View full-size slide

  24. What we actually get with gRPC

    View full-size slide

  25. What we actually get with gRPC

    View full-size slide

  26. It's even worse: server shutdown

    View full-size slide

  27. Client Server
    Client
    Client Server
    Client Server
    Connection
    Reset
    Service IP

    View full-size slide

  28. 1. gRPC client side load balance

    View full-size slide

  29. It's Go only

    View full-size slide

  30. 2. Read Kubernetes Blog

    View full-size slide

  31. (Yes, I used their image earlier)

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  34. No disable! Only set connection lifetime

    View full-size slide

  35. 5. Join guild of gRPC haters

    View full-size slide

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

    View full-size slide

  37. 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)

    View full-size slide

  38. Have fun!
    And pray for service mesh

    View full-size slide