Closed18

Rails on GCP(GAE)の非同期処理の構成を考える

bisquebisque

従来は、キューとしてRedisを利用するSidekiqなどのライブラリが主流だが、Redisはコストが高いしマネージドサービスだとしても管理コストは掛かるので使いたくない。クラウド環境においてはキューサービスがあるので、そちらを利用する構成を考える。

bisquebisque

そもそもCloud TasksはPush型のサービスなので、Job worker(Pullして処理する人)を作る必要がない?
https://zenn.dev/aikizoku/articles/cloudtasks-scheduler

bisquebisque

CloudTasks
https://cloud.google.com/tasks/docs/dual-overview?hl=ja

処理時間

  • 宛先がGAEではないHTTPターゲットの場合、10分以内
  • 宛先がGAEスタンダート環境の場合、自動スケーリングで10分以内、手動スケーリングで24時間以内
  • 宛先がGAEフレキシブル環境の場合、60分以内
    https://cloud.google.com/tasks/docs/creating-appengine-handlers?hl=ja
  • レスポンスが2xx以外、またはレスポンスがない場合はリトライされる
bisquebisque

元々はGAEのタスクキューとして開始されたものが、Cloud Tasksとして独立した形。
だから設定方法としてqueue.yamlとCloud Tasks APIをつかう2種類の方法が残っている。
https://cloud.google.com/tasks/docs/queue-yaml?hl=ja

Cloud Tasks または App Engine を初めて使用する場合は、Cloud Tasks API だけを使用してキューを管理し、queue.yaml と queue.xml の使用は避けてください。Cloud Tasks でキューを管理すると、キューの作成、更新、削除を行うときの選択肢が増えます。

今から使い始めるのならAPIで管理する方法が推奨される。

「default」という名前の App Engine キューに対しては、App Engine SDK でも Cloud Tasks API でも特殊な処理が行われます。

defaultというキューは特殊な扱いになるので、避けたほうが良さそう。

bisquebisque

https://cloud.google.com/tasks/docs/configuring-queues?hl=ja

キューは、適切なワーカーを含むサービスの名前とバージョンを必要とします。これらの情報をターゲットといいます。ターゲットを設定するには、次の 3 つの方法があります。

GAEをターゲットとする場合、アプリのバージョン指定も必要。GAEのアプリを切り替えたときに、キューのターゲットのアプリバージョンをどう切り替えるか?

どちらの場合も、トークン バケット アルゴリズムを使用して、タスクの実行レートが制御されます。

ディスパッチのレート制御は、トークンバケット方式。それに加えて最大同時実行数も制御ができる。

ターゲットのインスタンスが複数ある場合、リクエストは均等に分散されるのだろうか?
処理時間が長い処理と短い処理が混在した場合に、うまく負荷分散できるのだろうか?

bisquebisque

GAEターゲット側の実装
https://cloud.google.com/tasks/docs/creating-appengine-handlers?hl=ja

App Engine タスクでは、キューとタスクハンドラは同じ Cloud プロジェクト内で実行されます。

プロジェクトは同じである必要がある。

安全なタスクハンドラ、安全性の低いタスクハンドラ、サポートされるランタイムにおいては login: admin で制限された URI に、タスクをディスパッチできます。

これを指定しておけば、外から叩かれることはない。

login handler のサポートは終了していた。

https://cloud.google.com/appengine/docs/standard/python/config/appref?hl=ja#handlers_login

bisquebisque

負荷分散について

前提

  • ターゲットはGAEのフレキシブル環境。
  • ターゲットはマルチスレッドで複数のリクエストを並行して処理できるものとする。
    • ここでは仮にスレッド数を10とする。

タスクの想定処理時間に応じて3つのキューを作り、ターゲット1台あたり以下の設定にする。

  • 処理時間が小(~1s)
    • maxDispatchesPerSecond: 20
    • maxConcurrentDispatches: 10
  • 処理時間が中(1s~30s)
    • maxDispatchesPerSecond: 1
    • maxConcurrentDispatches: 5
  • 処理時間が大(30s~最大60,000s)
    • maxDispatchesPerSecond: 1
    • maxConcurrentDispatches: 1
bisquebisque

ターゲットのインスタンスが複数ある場合、リクエストは均等に分散されるのだろうか?
処理時間が長い処理と短い処理が混在した場合に、うまく負荷分散できるのだろうか?

このあたりはGAEのPending Request Queueの動作による。

bisquebisque

GAEをターゲットとする場合、アプリのバージョン指定も必要。GAEのアプリを切り替えたときに、キューのターゲットのアプリバージョンをどう切り替えるか?

Queueの設定では、バージョンを省略することもできる。
https://cloud.google.com/tasks/docs/reference/rest/v2/AppEngineRouting?hl=ja

このとき、デフォルトのバージョンにルーティングされるとあるが、デフォルトのバージョンとはなにか?

bisquebisque

https://cloud.google.com/tasks/docs/creating-appengine-handlers?hl=ja

注: ハンドラをべき等にするかどうか検討する必要があります。Cloud Tasks は「少なくとも 1 回」処理を行うように設計されています。つまり、タスクが正常に追加された場合、キューはそれを少なくとも 1 回配信します。まれに複数のタスクが実行されることもあるので、反復的な実行で有害な副作用が生じないように注意してください。

配信は「少なくとも1回」なので、ハンドラ側は冪等性を担保する必要がある。

bisquebisque

ハンドラのエンドポイントの保護について

GAEにIAPを設定した状態で認証を通せるか?

いまのところ、GAE第1世代のloginハンドラの設定しかドキュメントにはない

https://cloud.google.com/tasks/docs/creating-appengine-handlers?hl=ja

サービスアカウント + IAPによる認証ができるようになるはず(もうできる?)

https://medium.com/google-cloud-jp/gcp-からの-http-リクエストをセキュアに認証する-dda4933afcd6

このスクラップは2021/10/18にクローズされました