Wantedly Engineering Handbook
  • Wantedly Engineering Handbook
  • まえがき
  • 第一部:開発チームへの案内
    • 技術とアーキテクチャ
    • プロダクト概要(未執筆)
    • 開発チームの構造
    • コミュニケーションの全体
    • ドキュメンテーション(未執筆)
    • カレンダー
    • 障害対応の心構え
    • 効率的な社内知識の調べ方
    • 外部発信(執筆中)
  • 第二部:技術領域への案内
    • Apps
      • アプリを提供するプラットフォーム
      • デザインシステム入門
      • Web アプリのアーキテクチャ
      • プロダクトデザイナーと上手に協働するための心得
      • Web アプリのデザインシステムライブラリ
      • Web アプリ共通ライブラリ "React Shared Component" の紹介
      • モバイルアプリのアーキテクチャ
      • モバイルアプリのデザインシステムライブラリ(未執筆)
    • The System
      • protobuf スキーマと gRPC 通信
      • 実践: gRPC in Ruby
      • 実践: gRPC in Go
      • GraphQL Gateway - アプリ向けに API を公開する
      • Wantedly Visit で BFF GraphQL サーバーを辞めた理由
      • 実践: GraphQL スキーマ設計(未執筆)
      • API での認可処理 (Authorization)
      • マイクロサービス共通ライブラリ "servicex" の紹介
      • 非同期メッセージング処理入門(未執筆)
      • バッチ処理入門(未執筆)
    • Infrastructure
      • Infrastructure Squad
      • プロダクト開発のための Kubernetes 入門
      • インフラ構成概要
      • リリース・デプロイ戦略を支える技術
      • SaaS を活用する:New Relic, Honeybadger, Datadog
    • Data
      • データ基盤入門
      • レコメンデーション
      • Looker 入門
      • 推薦システムの開発に使っているツール
    • 開発プロセス
      • Git の慣習
      • ポストモーテムの取り組み
      • 負債返済日の取り組み
      • プロダクトの課題発見及び解決
      • ソフトウェアデザインの基礎
      • コードレビュー
      • コーディング規約
      • リリース・デプロイ戦略
      • 上長承認が必要な作業
      • アーキテクチャディシジョンレコード(ADR)
      • 作業ログを残す意味
      • 多言語化対応(i18n)
      • メール開発
    • 開発ツール
      • 社内利用している開発ツールの最新状況
      • kube
      • Code Coverage
      • Kubefork
  • おわりに
    • ロードマップ(未執筆)
    • Handbook の書き方
    • コントリビューター
  • 付録
    • 社内用語集
    • 主要な GitHub レポジトリのリスト(未執筆)
    • 今後の挑戦・未解決イシュー(未執筆)
    • プロダクト開発組織のバリュー(未執筆)
    • 採用についての考え方(未執筆)
GitBook提供
このページ内
  • TL;DR
  • マイクロサービス共通ライブラリ"servicex"
  • 何をしてくれているか
  • なぜ必要か
  • コアとなる機能:入出力フックとコンテキスト伝搬
  • 言語・フレームワークサポート
  • メンテナンス体制
  • まとめ

役に立ちましたか?

  1. 第二部:技術領域への案内
  2. The System

マイクロサービス共通ライブラリ "servicex" の紹介

前へAPI での認可処理 (Authorization)次へ非同期メッセージング処理入門(未執筆)

最終更新 1 か月前

役に立ちましたか?

TL;DR

  • 共通ライブラリを導入することで

    • 「すべてのマイクロサービスが備えるべき機能を間違いなく提供できる」だけでなく

    • 「アーキテクチャ全体を継続的に・小さく改善していく足がかり」にもなった

  • 各言語に実装した共通ライブラリのコア機能は「すべてのサービスが」「すべての入出力にフックし」「入力のコンテキストを出力まで伝搬する」であった

マイクロサービス共通ライブラリ"servicex"

Wantedly ではマイクロサービスアーキテクチャを採用しています。 などでも言及のあるとおり、Ruby・Go・Python・Node.js(・Rust)と複数の言語が採用されています。 そして、"servicex" という共通ライブラリがこれらの言語それぞれに用意されています。 servicex の各言語実装はすべて同じ目的を達成するためのもので、その Why / What は以下のように定義されています。

Why

新しくサービスを作る際に考えることを減らし,本来実現したいドメインに集中できるようにしたい.

What

Wantedly のすべてのマイクロサービスが備えるべき機能を扱いやすい・統一的な形で提供する.

(wantedly/servicex の README より抜粋)

本章ではこのマイクロサービス共通ライブラリ "servicex" について、なぜ必要だったのか、そしてそれがあることでどんな良いことがあったかなどを紹介します。

何をしてくれているか

機能ベースでは、大きく2種類に分けられます。

まず、ログやメトリクスなど Observability 関連。 マイクロサービスアーキテクチャを採用するとリクエストの流れも複雑になりますし、障害発生時の原因特定などの難易度も上昇します。 よって、それぞれのコンポーネントで Metrics, Logs, Traces などを収集しておくことは重要なのです。 Wantedly のマイクロサービスでは、開発者が意識せずとも servicex さえ導入しておけば、これらの機能が有効になります。

また、だいたいのマイクロサービスで必要になる便利機能群というのも実装されています。 いくつか挙げてみましょう。

  • マイクロサービス間通信のデフォルトタイムアウト・認証などの設定

  • マイクロサービス間通信で、環境(ローカル, 開発, QA, 本番, ..)を見て URL をいい感じにしてくれる

  • BigQuery にイベントを記録できる機能

  • RDB に依存しない A/B テスト機構

  • ...

ほかにもいくつか機能がありますが、ここでは省略します。

なぜ必要か

「(プロダクト開発者としては)設定を忘れがちだが、忘れたらかなり困る」ものを忘れないようにするためです。特にログやメトリクスはわかりやすいでしょう。 普段からメトリクスが取れてないと、問題発生時に気づくのが遅れるかもしれません。 また、アクセスログなどは問題に調査・対応するときの最後の砦となることもあります。 こういうものはだいたい問題が起きたタイミングで初めて需要が生まれます。しかし、その時点でログが取れてないことに気づいても後の祭りです。

それに、ログやメトリクスの送り先にもちゃんとルールが必要です。 マイクロサービスによってログテーブルの命名規則やデータフォーマットが違っていたらちょっとしんどいですよね。

また、一般的なソフトウェア実装プラクティスの話でもあります。同じようなコードを複数のリポジトリで何度も書くのは不毛ですし、間違いも起きるかもしれません。 「読み出す環境変数の名前を間違えて正しくメトリクスが取れなかった」みたいなことが起きる可能性もあります。自分は3回くらいやりました。

...と、このように、プロダクト自体の開発以外にも「忘れたら困る」「何回も書きたくない」「間違えたら困る」みたいなコードは意外とたくさん存在します。 このような 「新しくマイクロサービスを作る際に考えないといけないこと」を減らし、本来実現したいドメインに集中できるようにする ために、Wantedly のすべてのマイクロサービスが備えるべき機能を扱いやすい・統一的な形で提供するのが "servicex" という共通ライブラリの責務です。

コアとなる機能:入出力フックとコンテキスト伝搬

ここまでで「マイクロサービス共通ライブラリ "servicex" とは何のために・何を提供するのか」を紹介してきました。 このライブラリを実際に2018年ごろに作り始めてからいままでのあいだに、起きたことを踏まえて、「共通ライブラリがあることで何が起きるか」というのを掘り下げていきます。

さて、前の節で servicex が提供するものに "Observability 関連" を挙げました。 具体的には「Metrics, Logs, Traces を収集するための機能」です。これを達成するためには何が必要になるでしょうか。自分は以下の3項目が重要なのではないかと考えています。

  • Observability を網羅的に高めるためには、すべての入出力にフックできる必要がある

  • 入力と出力を正しく紐付けるためには、入力のコンテキストを出力部まで伝搬している必要がある

  • マイクロサービスをまたいでログ・メトリクス・トレーシングを関連付けるには、すべてのマイクロサービスが上記の性質を満たしている必要がある

入出力 という表現をしましたが、これはマイクロサービスが「どんなリクエストを受けて」「どうやってリクエストを飛ばすか」ということです。 Wantedly ではマイクロサービス間通信に JSON over HTTP だけでなく gRPC を推進しているほか、非同期なやりとりには Cloud Pub/Sub を利用しています。 また、当然 RDB などのデータストアを持つマイクロサービスも多数存在します。ほかにも Redis や Elasticsearch など、いくつかのミドルウェアを利用しています。 これらのマイクロサービス間通信の入出力やミドルウェアへの出力にフックし、観察することでリクエスト全体が追跡可能になったり、障害発生時にどこで異常が起きているのかを発見しやすくなるのです。

この 「すべてのマイクロサービスが」「すべての入出力にフックし」「入力のコンテキストを出力まで伝搬できている」 という特性があることで、 Wantedly ではシステムの Observability の向上以外にもいくつかの恩恵を受けることができました。

  • 事例: Network Observability 向上のための PoC

    • (社員向け情報: wantedly/infrastructure#4622)

    • マイクロサービス間通信のネットワークエラーの発生割合を可視化するために、servicex にデータ収集機構を実装した

    • サービスメッシュの導入を念頭に置きつつ、とりあえず PoC として小さく始めるために共通ライブラリを利用した例

  • 事例: HTTP Header / gRPC Metadata 伝搬

    • (社員向け情報: wantedly/dx#89)

    • Feature Flag や開発時の特殊な Request Routing のために、条件を満たす HTTP header / gRPC metadata を後続のマイクロサービスに伝搬させる必要があった

理想的には Sidecar conatiner や Service mesh などアプリ外のレイヤで解決できる/すべき問題も含まれているかもしれませんが、 「ぱっと導入して価値検証できる・高速なフィードバックサイクルを回せる」という点において共通ライブラリに優位性がありました。 また、アプリケーション中でこれらのコンテキストが取り出せることで、adhoc なイベントログ収集などでも活用できます。

言語・フレームワークサポート

「すべてのマイクロサービスが」「すべての入出力にフックし」「入力のコンテキストを出力まで伝搬できている」を満たすために、 Wantedly のバックエンドで利用している Ruby・Go・Python・Node.js に servicex の実装が用意されています。 一方で、すべての機能をすべての言語でサポートしていると大変なので、現状メジャーなユースケースのみのサポートとしています。

-
HTTP server/client
gRPC server/client
Pub/Sub

Ruby / Ruby on Rails

✓/✓

✓/✓

✓/✓

✓/✓

✓/✓

✓/✓

Python

✓/×

✓/×

×/×

Node.js

✓/✓

×/✓

×/×

  • フル機能(あらゆる通信方式で入力にも出力にもなれる)のは Go と Ruby のみ

  • Python は誰にも依存しない「関数」的なマイクロサービスが多いので、 Server として必要な機能のみ存在

  • Node.js も基本的には Python と同じだが、SSR server や GraphQL BFF があるため Client になる必要もある

Wantedly では Ruby と Go が最もよく利用されるため、この2つに関してはフル機能の servicex がサポートされています。 対して Python や Node.js は限定されたユースケースでのみの利用となっているため、それをカバーする範囲のみのサポートとなっています。

上記の表で × になってたりカバーされてない領域に手を出す場合は、servicex も一緒に作りメンテしていく覚悟が必要になります。 ハブになるマイクロサービスでコンテキスト伝搬が切れてしまうと、それより後ろのすべてのマイクロサービスすべてに影響がでるため、特定のチームだけの問題ではありません。

メンテナンス体制

まとめ

  • servicex とは

    • Why: 新しくマイクロサービスを作る際に考えることを減らし,本来実現したいドメインに集中できるように

    • What: Wantedly のすべてのマイクロサービスが備えるべき機能を扱いやすい・統一的な形で提供する

    • 具体的に : Observability まわりのセットアップや、あらゆるマイクロサービスで共通で使う機能が提供される

  • servicex のコア機能

    • すべてのマイクロサービスが」「すべての入出力にフックし」「入力のコンテキストを出力まで伝搬できている」状態を達成する

    • これによってインフラレイヤに機能を入れる前の PoC を小さく始めたり、コンテキスト伝搬を活用した便利機能が実現できる

それぞれの言語実装で簡単に使えるようにする工夫などもあって実装の話も興味深いのですが、本章では割愛しました。ぜひ実装されているコードを手元で読んでみてください。

話を聞きに行きたい

  • GitHub: @wantedly/servicex-owners

もっと知りたい

この Why と What を踏まえて、servicex リポジトリの description には "Microservices governance through code." と書いてあります。 この文言は書籍 (日本語版: )の2.6章のタイトル "Governance Through Code"(コードを介したガバナンス)から取られています。

関連:

Go / ,

servicex 全体のデザインに関してオーナーシップを持つ人間が3人と、各言語実装ごとにそれぞれ2〜4人の CODEOWNERS が設定されています。 言語実装のオーナーは各プロダクトドメインから1人ずつ選出されており、 コードレビューはにより持ち回りで担当しています。

Slack:

Wantedly における Go 導入にまつわる技術背景
Building Microservices
マイクロサービスアーキテクチャ
Istioを使って「Fast、Dependency-Agnostic、Isolated」な開発体験を実現した話
GitHub が Round Robin で割り当ててくれるやつ
#microservices
マイクロサービス共通ライブラリで “Governance through code” を実現する | Wantedly Engineer Blog
grapi
subee
hexagonal-architecture-like-input-and-output