Temporalというマイクロサービスオーケストレーションについて

temporal
workflow

2022-05-08

Employee performance vector created by vectorjuice - www.freepik.com

#はじめに

最近はワークフローをどう扱うかについて、調査を進めています。
その中で、興味深いオープンソースソフトウェアを紹介したいと思います。
Temporalというマイクロサービスオーケストレーションプラットフォームです。

#Temporalとは

Temporal is a scalable and reliable runtime for Reentrant Processes called Temporal Workflow Executions.

出典: Introduction to Temporal | Temporal Documentation

Temporal is a microservice orchestration platform which enables developers to build scalable applications without sacrificing productivity or reliability. Temporal server executes units of application logic, Workflows, in a resilient manner that automatically handles intermittent failures, and retries failed operations.

出典: temporal - Github

Reentrant Processesとありますが、再入可能ということです。
Wikipediaのリエントラントが参考になります。情報処理の教科書でもよくでてくる単語ですが、おおよそ単一プログラムにおける再入可能を説明していることが多いと思います。
近年では、マイクロサービスやネットワークを越えて複数のタスクを一連のワークフローの中で実行することが当たり前になりましたが、こうした環境における再入可能なプログラムを実現するのがTemporalだと理解しています。

どうやって実現しているかを最もわかりやすく説明してくれている動画があります。動画の途中から再生します。

https://www.youtube.com/watch?v=bjlFculKheI&t=1910s

#ワークフローとマイクロサービスにおける課題

先に紹介したYoutube動画では送金を題材に説明されています。
送金元口座から送金先口座に金額を指定して送金するというものです。
これを一つのワークフローとして考えると、2つのステップが存在します。

  1. 送金元口座から指定された金額分を減らす。
  2. 送金先口座へ指定された金額分を増やす。

このワークフローを信頼性の高く成功させるためには、どうような考慮が必要でしょうか。
Temporalを使わない場合を考えてみます。送金はマイクロサービスを通じて行うこととし、ワークフローのなかでは、トランザクションセーフではないこととします。

信頼性を高めるには、ステップ1,2が失敗する場合を考慮して、ワークフローロジックの中にリトライロジックを入れるでしょう。
また、ワークフローの実行プロセス自体がダウンした時を考慮して、ワークフロー自体をリトライするロジックをワークフローの呼び出し元に入れるでしょう。こう考えるとリトライは呼び出し元をたどって無限に入れないといけなくなってしまいます。

これを解決する方法の一つとして、メッセージングシステムを使うことができます。メッセージングシステムを使うと、処理が成功したらメッセージを消費し、失敗した場合はメッセージを消費しないことにより、再度同じメッセージを受信してリトライを実現することができます。
メッセージを受信する側では、受信したメッセージ処理のべき等性を担保する必要があります。
べき等性を担保するために、一般的にDBのトランザクションを使ったりして、2重処理を防ぎます。
これは、マイクロサービスが増えていくと至るところに同じようなべき等性を担保する仕組みが必要になります。

更に、ワークフロー自体がリトライされた時を考慮して、ステップ1,2が実行済みであるかを判定して、すでに実行済みであれば処理をスキップするか、結果情報だけを保存しておくように状態管理をするかもしれません。あるいは、もし、ステップ1,2自体の操作がべき等性を担保していれば、同じ情報(おそらくRequestIDのようなキー)を指定して前回成功時の結果情報を取り出すことができます。ただし、このRequestIDはどこかに保存しておかなければなりません。

途中でキャンセルしたい場合はどうでしょう。マイクロサービスアーキテクチャではSagaパターンで実装するかもしれません。

最後に、失敗してシステムが自動的にリトライ出来なかった場合、手動の運用対処をすることになるかもしれません。

たった一つのマイクロサービスを呼び出すだけでも、非常に考慮することが沢山あります。

  • 各ステップにリトライロジック
  • リトライトリガー
  • べき等性を担保するための状態管理
  • キャンセルの対処
  • インフラの設計・運用
    • メッセージングシステム
    • トランザクション管理用DB
  • 運用対処による復旧

こうした実装は煩雑で複雑になりがちで、テストをすることも大変困難です。

Youtube動画をみるとわかるのですが、Temporalは、こうしたマイクロサービスにおけるワークフローの課題を扱ってくれます。

この他にも、タイムアウトや、分散アーキテクチャシステムでのスケーラビリティや、他にもいろんな課題があるのですが、長くなるので割愛します。

#類似のサービスとは何が違うのか

Temporalと同等のサービスは思いつきませんが、私がワークフローの課題をどうやって解決するかをこれまで考えてきたなかで検討したものを挙げて比較してみたいと思います。

  • Apache Airflow

Apache Airflowは、データエンジニアリングパイプライン用のオープンソースのワークフロー管理プラットフォーム

とあるように同じワークフローでもユースケースが異なる。よりAirflowはデータパイプライン用途の印象が強いが、Temporalのほうはビジネスワークフローも書けるし、もちろんデータパイプラインも書くことができるだろう。
有向非巡回グラフでは、ループするようなワークフローを定義することはできないので本質的に異なると思われる。

  • AWS Step Functions

このディスカッションは、AWS Step FunctionsとTemporalの違いを説明しています。DSLとコードでワークフローを実現する違いについて言及されています。Sagaパターンについても言及されています。コードで実現するほうが圧倒的にシンプルに書けるのがすごいです。

  • メッセージシステムを使った分散アーキテクチャ

これはすでにワークフローとマイクロサービスにおける課題で述べたが、メッセージシステムを使ったリトライトリガーの実現をTemporalに委ねることができます。
また、ワークフローの状態管理もTemporalに委ねることができます。

実際にOAuth2のコード認可のフローを実装してみました。OAuth2ではstateという一時的なトークンを発行・検証することでCSRF攻撃を防ぐことが推奨されていますが、Temporalのワークフローにstateの状態を持たせることができるので、このためだけにDBを用意する必要なく実現できます。

これまでは、このためだけにKVSなどDBを用いることありましたが、Temporalを使うとナンセンスに思えてきます。実際にはTemporalはDBに依存しますが。

参考:https://auth0.com/docs/secure/attack-protection/state-parameters

#注意点

数個のワークフローを実装してみて、注意しないといけないなと感じた点です。

  • 学習曲線

    これまでのアーキテクチャと異なる部分が多いのでワークフローの実装には注意が必要です。

    • 決定的アルゴリズム

      temporalのドキュメントのなかでしばしばDeterministicという単語が出てきます。決定論的と訳されるのですが、上記の決定的アルゴリズムという意味でしょう。

      ワークフローはいつ、どのインスタンスで、何回実行されても同じ結果を返さないといけないので、現在時刻を取得したり、ランダムな値を生成することは、SDKが提供している関数を使うなどして、実行時に決定的に実行する必要があります。

      また、Goでは、goroutineselectなどもワークフロー内では禁止されているのでSDKが提供するラッパー関数を使わなければいけません。

      また、ワークフローをアップデートする場合でも決定論に従わなければなりません。互換性のないワークフローをデプロイするとうまく動かなくなるらしいので、注意しないといけません。互換性のないワークフローに置き換える場合は、バージョニングという機能が用意されています。

      ということで、使いこなすまでに、いろいろと学ぶことが多いです。

    • デバッグが難しそう

      ワークフローのコードは何度も実行されるので、ブレークポイントをつけると最初はよくわからないかもしれません。

      デバッグをやりやすくするための機能でリプレイという機能があるので使ってみたいと思います。

  • マネージドサービス

    Temporal Cloudというサービスがあります。しかし、Join the Cloud Waitlistとありすぐには利用できないようです。OSS版のDockerやHelmChartが公開されていますので、セルフホスティングは可能です。Local環境ならauto-setupのDockerイメージを利用すればすぐに開発を始められます。しかし、商用環境向けにスケーラブルで信頼性の高い構成を構築して検証して運用し続けるのは骨が折れそうですね。

#まとめ

個人的には、Temporalは、ReactやVue.jsと同じくらいインパクトがあり、特にミッションクリティカルな要求があるシステムでは採用していく企業は増えていくと思います。シリコンバレーのテック企業では採用されている事例がいくつか掲載されています。日本の企業で採用しているのは、まだ聞いたことがないですが。
Temporalは、サンプルコードやドキュメントが充実しており、お気に入りになりました。