Microservices Get Started その1

このエントリに書くこと

このエントリは以下のようなことについて自分が最近まなんだ範囲で書く。

自分の環境は以下:

- macOS 10.13.4
- cpython 3.6.1
- nameko 2.9.1
- Docker for Mac Version 18.06.0-ce-mac70


introduction

Microservicesというワードはよく聞くし、いくつかブログや本も齧ったりしたけど、 全く自分で構築したこともないということで、いつか仕事で役立つ時がくるかもしれないしローカル環境で作ってみようと思う。

NamekoというPython製のフレームワークを使う。
可愛らしい名前だが、初心者にやさしいチュートリアル的なものが一切なく、結構使い始めるのに困るので、そういった意味でもこのエントリを書いている。 本エントリはマジでhello worldしかしてない。

GitHub - nameko/nameko: Python framework for building microservices


MicroservicesとSOA

Microservicesを始めようとする時、絶対気になるのが、 SOA(Service oriented architecture)との違いかと思われる。自分もいまだに気になる。

SOAは、S/Wエンティティ同士が細かく分割されていて、それぞれがメッセージのやりとり(SOAPとかHTTP)でコミュニケーションする。

MicroservicesはこのSOAのアドバンスドというか延長線上にいる。

ただし両者は、目的が大きく異なる。 誤解をおそれない感じで書いてみる。

SOAについて

巨大な業務システムを構築する際に、さまざまなステークホルダがいて、 それらが独自に実装したサブシステム同士が通信することを考える。
取引処理と決済処理と在庫処理が互いにデータを参照しあう時、取引システムと決済システムと在庫システムが全く別の組織が開発をしていても、 共通のインタフェースがあると、それぞれの実装はブラックボックスでもよくて、実装言語はなんでもいいしプラットフォームもそれぞれが得意なものを選択できる。 開発体制を分断できる。
ブラックボックスの先が超巨大で複雑なインフラでも、超スパゲティコードでもSOASOAである。
こういうこともあり、SOAは比較的S/Wの内部的なアーキテクチャに関心がない。

Microservicesについて

こちらはもっと開発品質の向上にフォーカスしている。 デリバリの効率をあげ、S/Wの開発そのものの改善を目指すもの。 したがって必然的に、S/Wの内部的なアーキテクチャに強い関心がある。
個々のサービスは、自律的かつ非依存的で、管理可能なほど小さな単位で完結しており、デプロイが容易でなければならない。 SOAPみたいなXMLのやりとりではなく,RESTやRPCを用いてコミュニケーションする。
サービス間で同じDBを参照するとかコードをシェアするとかは基本的になしである。 このように、非常に小さなサイズのサービスを包括的に管理する必要があるという意味で、 モノリシックなシステムと比較して運用がすごく難しい。
Microservicesの文脈ではコンテナが前提となっているが、運用の困難さを解決すべくOSSがいくつも出ている。


Nameko

さて、PythonでMicroservicesを書く時、Namekoというフレームワークでかなり簡単に始められる。 ちなみに、なめこが群生している様が、小さなサービスが群れているMicroservicesとなんか似ているのが由来ということらしい。 最初に触るにはよさそうである。 ただ、ドキュメントにチュートリアル的な初心者にやさしいものがないので、少し困る。

RPCについて

MicroservicesではRPCでサービス間のコミュニケーションをすることが必要となる。 これは、ネットワーク越しに存在するコードを、見かけ上はローカルのものを呼ぶかのように実行する。 RESTなどと比較して難しいのが、自分が書いているコードで、気をつけないと意図せずリモートとの通信を連発する可能性があること。 外部のリソースを使うのは高くつくものであるので、リモートコールする箇所は意識しておく必要がある。

Message Queuingについて

Namekoでは、RPCによるリモートコールを実行すると、Message Queueにリクエストを詰める。 呼び出し先のサービスでは、このキューからメッセージをconsumeしてタスクを実行する。 consumerは水平スケールすることでパフォーマンスを確保することが容易。

RabbitMQについて

メッセージのブローカとして、NamekoではRabbitMQが利用できる。 自分はDocker for Macでお手軽にローカルにRabbigMQを立てることにする。


Namekoを使って最初のMicroservices

初めてやるので、普段の環境とは分けておいた方が無難だろう。 てきとうに検証用のディレクトリを掘ってそこに移動する。

$ mkdir first_nameko; cd first_nameko

専用の仮想環境を作っておく。 (自分はcpython 3.6.1 を使った)

$ pyenv-virtualenv 3.6.1 first_nameko
$ pyenv local first_nameko

Namekoをインストールする

$ pip install nameko

まずは最初の HelloWold サービスを作ってみる。 公式ドキュメントから借用して、 helloworld.py を以下の内容で作成する。

from nameko.rpc import rpc

class GreetingService:
    name = "greeting_service"

    @rpc
    def hello(self, name):
        return "Hello, {}!".format(name)

サービス名は、 greeting_service である
@rpc デコレータによって、このメソッドがRPC経由で呼び出されるようにする。
次に、以下の config.yaml を同じ階層に置く。

AMQP_URI: 'pyamqp://guest:guest@localhost'

AMQP とは、NamekoがRPCをやりとりする上で利用するプロトコルらしく、今回はメッセージのブローカとしてRabbitMQを使うので、そのエンドポイントを記述。 RabbitMQにはデフォルトで guest:guest なユーザがいる。

次に、RabbitMQ自体はDockerでさくっと立てる。

$ docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq

そして、初めてのサービスを起動する。

$ nameko run helloworld --config config.yaml
starting services: greeting_service
Connected to amqp://guest:**@127.0.0.1:5672//

Namekoには cliが付属しているので、使ってみる。

$ nameko shell
Nameko Python 3.6.1 (default, Sep 26 2017, 15:11:41)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] shell on darwin
Broker: pyamqp://guest:guest@localhost
>>>

さきほど起動したサービスに定義したメソッドを呼び出してみる。

>>> n.rpc.greeting_service.hello("ujun")
'Hello, ujun!'


このあと

Namekoを使って簡単にMicroserviceを構築できそうな雰囲気があるので、どんどん使っていきたい。 nameko.web にHTTPハンドラを作るモジュールがあるので、RESTなエンドポイントを定義してWebアプリっぽいものも簡単に作れる。


つづく