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

Python用のマイクロサービスフレームワークを探す旅 / A journey to find a microservices framework for Python

yukinagae
September 29, 2019

Python用のマイクロサービスフレームワークを探す旅 / A journey to find a microservices framework for Python

golangのGoa (https://goa.design/) のようなマイクロフレームワークに似たようなのをPythonでもほしいので、Nameko (https://www.nameko.io/) の拡張を作ってみました(`・ω・´)
repository: https://github.com/yukinagae/nameko-design

yukinagae

September 29, 2019
Tweet

More Decks by yukinagae

Other Decks in Technology

Transcript

  1. Python用のマイクロサービスフレームワーク
    を探す旅
    @yukinagae

    View Slide

  2. 目的
    golangの Goa のようなマイクロフレームワークに似たようなのを
    Pythonでもほしい
    2

    View Slide

  3. 背景
    webアプリではないのでマイクロなフレームワークを使っていき
    言語はGo/Pythonで絞りたい
    学習コストを減らす
    検証やハマることを減らしたい
    キャッチアップしやすい
    機械学習システムは似たような構成になりやすい
    バッチで学習しDBにデータをストア: Python
    DBからAPIでデータをサービングする: Go or Python
    3

    View Slide

  4. Goaとは?
    Goa is a Go framework for writing microservices that
    promotesbest practice by providing a single source of
    truth from which server code, client code, and
    documentation is derived.
    マイクロサービス用のフレームワーク
    コードからサーバサイドのスケルトンやドキュメント(swagger)
    を生成できる
    4

    View Slide

  5. こんな感じのAPIデザインをgoで記述する
    var _ = Service("calc", func() {
    Method("add", func() {
    Payload(func() {
    Field(1, "a", Int, "Left operand")
    Field(2, "b", Int, "Right operand")
    Required("a", "b")
    })
    Result(Int)
    HTTP(func() {
    GET("/add/{a}/{b}")
    })
    GRPC(func() {
    })
    })
    })
    5

    View Slide

  6. ポチッとな(`・ω・´)
    goa gen calc/design
    6

    View Slide

  7. 省略しているがいろいろ生成してくれる
    gen
    ├── calc
    │ └── *.go
    ├── grpc
    │ ├── calc
    │ │ ├── client
    │ │ │ └── *.go
    │ │ ├── pb
    │ │ │ ├── calc.pb.go
    │ │ │ └── calc.proto # <- protobuffer
    │ │ └── server
    │ │ └── *.go
    │ └── cli
    │ └── calc
    │ └── cli.go
    └── http
    ├── calc
    ├── cli
    ├── openapi.json # <- swagger
    ファイル
    └── openapi.yaml # <- swagger
    ファイル
    7

    View Slide

  8. ロジックを実装
    あとは生成されたうちの2~3ファイルにロジックを実装するだけ。
    生成された空メソッド
    実装する
    func (s *calcsrvc) Add(ctx context.Context, p *calc.AddPayload)
    return 0, nil
    }
    func (s *calcsrvc) Add(ctx context.Context, p *calc.AddPayload)
    return p.A + p.B, nil
    }
    8

    View Slide

  9. Goaのいいところ
    スキーマファースト
    スキーマ作成 → 開発というワークフローができる
    http + gRPCの両方使える
    9

    View Slide

  10. Pythonでも似たようなのほしいのでは
    (`・ω・´)
    10

    View Slide

  11. 11

    View Slide

  12. Nameko(なめこ)
    A microservice framework for Python.
    マイクロサービス用のpythonフレームワーク
    ビジネスロジックの実装に集中できる
    拡張いろいろできる(どのプロトコルやDBにもサービス拡張でき
    る)
    名前がよい
    12

    View Slide

  13. Nameko(なめこ)の由来
    Nameko takes its name from the Japanese mushroom, which
    grows in clusters.
    クラスタ(?)に成長する日本のキノコである "なめこ" が由来
    13

    View Slide

  14. HTTPの場合
    アノテーションで @http
    を指定
    import json
    from nameko.web.handlers import http
    class HttpService:
    name = "http_service"
    @http('GET', '/get/')
    def get_method(self, request, value):
    return json.dumps({'value': value})
    14

    View Slide

  15. gRPCの場合
    アノテーションで @grpc
    を指定
    grpc = Grpc.implementing(exampleStub)
    class GrpcService:
    name = "grpc_service"
    @grpc
    def stream_unary(self, request, context):
    messages = []
    for req in request:
    message = req.value * (req.multiplier or 1)
    messages.append(message)
    return ExampleReply(message=",".join(messages))

    namekoのコアにはgRPCが入っていないが nameko‑grpc という拡張を
    使用可能
    15

    View Slide

  16. 使い方
    HTTPサービスを起動
    nameko run http_service
    curlで叩いてみる(`・ω・´)
    $ curl localhost:8000/get/123
    {'value': 123}
    ためしにサンプルプロジェクト作成した。
    ただDBからselectするだけ(/・ω・)/
    yukinagae/nameko‑api‑template
    16

    View Slide

  17. 軽く触ってみての感想
    ざっと調べた中では一番イメージに近いPythonライブラリ
    コーディング量も少なくて済みそう
    exampleレポジトリあるので結構参考になりそう
    DB周りのやり方はまだよくわかってない
    sqlalchemyは対応してるのを軽くサンプルで動作確認した
    swaggerのコード生成はないので作る必要あり
    17

    View Slide

  18. namekoの足りないところ
    スキーマファーストではない
    ふつうにエントリーポイントを作成する感じ
    http or gRPCはそれぞれ別に作らないといけない
    swaggerのコード生成
    18

    View Slide

  19. 結論
    Flaskでよくない?
    19

    View Slide

  20. Flaskから置き換えるほどか??
    実績 + ノウハウ + ドキュメントが多い
    namekoを新しく使うメリットがどこまであるか?
    正直今後の新サービスは9割方go(Goa)でいけるのでは?
    20

    View Slide

  21. ただやはり諦めきれない......
    namekoにもいいところある(`・ω・´)
    Flaskよりミニマム
    API部分はselectしたいだけならばこれくらいで十分
    gRPCのエントリーポイントをアノテーションで記述できる
    可読性高いのでは
    21

    View Slide

  22. これを改善すればよいのでは?
    スキーマからコード生成
    swagger生成
    22

    View Slide

  23. スキーマからコード生成だけやってみる
    方法案
    × yamlから生成
    × swaggerから生成
    ○ PythonでDSLっぽくやる ← 今回はこの方法(`・ω・´)

    テンプレートエンジンは Jinja2 を使用
    23

    View Slide

  24. 作ってみた(`・ω・´)
    yukinagae/nameko‑design
    24

    View Slide

  25. 端的に地獄......( ˘ω˘)スヤァ
    service = Service('http_service') \
    .Title('This is a http service') \
    .Method('liveness') \
    .Description('liveness probe') \
    .Result(str) \
    .HTTP(GET, '/liveness')
    service.generate() #
    コード生成
    25

    View Slide

  26. Pythonicに書けるようにしたつもり
    このPythonファイルをスキーマとする
    with Service('http_service'):
    Title('This is a http service')
    with Method('liveness'):
    Description('liveness probe')
    Result(str)
    HTTP(GET, '/liveness')
    with Method('readiness'):
    Description('readiness probe')
    Result(str)
    HTTP(GET, '/readiness')
    26

    View Slide

  27. これを叩くだけ
    cd nameko-design
    poetry run python cli/main.py
    27

    View Slide

  28. これを生成(`・ω・´)
    from nameko.web.handlers import http
    class HttpService:
    name = 'http service'
    @http('GET', '/liveness')
    def liveness(self, request) -> str:
    pass
    @http('GET', '/readiness')
    def readiness(self, request) -> str:
    pass
    28

    View Slide

  29. まだTODOたくさんあるけれど
    Configure http url and port
    Add URL parameter and type
    Add payload (name, type, description, position etc)
    Add validation
    Add gRPC server
    Generate proto files
    Generate swagger json
    29

    View Slide

  30. こんな感じでできたらよさそう(´∀`
    )
    with Service('example_service'):
    Title('This is an example service')
    with Method('liveness'):
    Description('liveness probe')
    Result(str)
    HTTP(GET, '/liveness')
    with Method('add'):
    Description('a + b')
    with Payload():
    Field(1, "a", int, "left operand")
    Field(2, "b", int, "right operand")
    Required("a", "b")
    Result(int)
    HTTP(GET, '/add/{a}/{b}')
    GRPC()
    30

    View Slide

  31. おわり
    31

    View Slide