Amena開発日記
ピン留め
サービス構想
- 3D Photo生成サービス
- Web UIから静止画をアップロードするだけで簡単に3D Photoを生成
※3D Photo↓
開発用Organization
アーキテクチャ
主に使いたい技術
- MQ
- オリジナル静止画のEnque
- 3Dフォトグラフィ生成エンジンによるDeque
- IaC
- Terraformを用いたインフラ構築(AWS)
- Kubernetes
- Amazon EKSによるコンテナオーケストレーション
- オートスケーリング機構
amena開発用のOrganizationを作成
余談だが、GitLabの「Project」にあたる機能がGitHubでは「Organization」で使えるのは良い発見だった(Zennインスパイア)
基本方針として、このプロダクトで習得したいのは主にインフラ周りの技術なので、アプリケーション層はそこまで凝りたくない。逆に言えばアプリケーション層をシンプルに保てるインフラ構成を目指したい。
全体の大まかなロードマップはこちらのカンバンで管理
ログイン機能は面倒臭くて付けたくないので、ざっと以下フローでアップロード〜成果物確認までを行う方針で検討。もしかするとDBも要らなくなるか?
- クライアント:静止画をフォームからアップロード
- システム:リクエストをEnqueし受付IDを発行
- クライアント:システムから受付IDを受け取ってCookieへセット
- システム:成果物をS3 Bucket://{{受付ID}}に格納(数分掛かる見込み)
- クライアント:Cookieの受付IDを元に一定周期で成果物が出来てないか問合せ
- クライアント:成果物ができていたら署名付きURl経由でS3からダウンロード
こうするとユーザアカウント情報管理が不要なのでシステムをだいぶシンプルに保てる。Cookieを削除すると成果物を取りにいけなくなるが、まあそれは仕様として(間違って削除しても再度リクエスト投げれば良い。)
あと、何気にシェアードナッシングを達成できるので冗長化にも強そう。
いや、上記の構成だと一人のユーザが同時にいくつも解析リクエストを投げられてしまうか。
IP単位でスタック数を制御しようにも複数台のPCでこられたらどうしようもない。
Googleアカウントでログインし、そのIDごとに一度にスタックできる解析リクエスト数を制御しようか(例えば一つのアカウントにつきスタックできる解析依頼は3つまでとか)
その場合別途DBでアカウント毎の解析進行数を管理?それともMQを見てそれぞれの依頼に紐づいているアカウントIDを確認できる?その辺りは調査。
以下のフローにしよう。DB使うのは本意ではなかったがまあセキュリティの面で仕方ないか。
- クライアント:Googleアカウントでログイン
- クライアント:GoogleのAuthTokenと共に静止画をフォームからアップロード
- システム:リクエストをEnqueしGoogleアカウントIDと受付IDをDBへ保存
- システム:成果物をS3 Bucket://{{受付ID}}に格納(数分掛かる見込み)
- クライアント:一定周期でログイン中のGoogleアカウントに紐づいている成果物が出来てないか問合せ
- クライアント:成果物ができていたら署名付きURl経由でS3からダウンロード
## Google APIクライアントライブラリを使用する
本番環境にて Google IDトークンを検証するには、Google API Client Libraries (例えば、Java、Node.js、PHP、Python)のいずれかを使用することが推奨される方法です。
まあアカウント使う仕様になると前から考えてた課金機能も実現しやすくなるので良い。
MQについて、取り敢えずシンプルそうなAmazon SQSの方針で検討してみる。
なお今回は費用面は一切気にせず好きに作ってみる。最悪月10くらい掛かっても良い。
Amena初期構想アーキテクチャ図
draw.io延々弄ってられるな...
【設計】インフラ構成 Done
【構築】インフラ構成 Doing
実際にTerraform使って構築してみる
こちらを参考に進める
terraform apply
時に以下エラー発生
Error: error creating EKS Cluster (eks-dev-cluster): InvalidParameterException: unsupported Kubernetes version
{
RespMetadata: {
StatusCode: 400,
RequestID: "{{ID}}"
},
ClusterName: "eks-dev-cluster",
Message_: "unsupported Kubernetes version"
}
variables.tf
のcluster_version = "1.12"
をcluster_version = "1.18"
に直したら通った。
怒られた
Error: Error creating launch configuration: ValidationError: The key pair 'KEY' does not exist
aws_key_pairを使ってterraformでkey_pairを作るようにして通った。
terraformまともに弄るの初めてだけどだいぶスラスラ設定読めるようになってきた、これは良い。
resource "tls_private_key" "eks-private-key" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "aws_key_pair" "eks-key" {
key_name = var.key_name
public_key = tls_private_key.eks-private-key.public_key_openssh
}
〜〜〜
resource "aws_launch_configuration" "lc" {
associate_public_ip_address = true
iam_instance_profile = aws_iam_instance_profile.eks-node.id
image_id = data.aws_ami.eks-node.image_id
instance_type = var.instance_type
name_prefix = "eks-node"
key_name = aws_key_pair.eks-key.key_name
〜〜〜
初Apply!!これはめでたい!!
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
そして生成したkeyをローカルに保存させるように
参考:https://qiita.com/mAster_rAdio/items/eead779391dc825d9bb9
$ terraform output eks-configmap > ./outputs/eks-configmap.yaml
$ terraform output kubectl-config > ./outputs/kube-config.yaml
kubectl apply
Done!!! 正常にクラスタ作成されてることをコンソールで確認済み!!やった!!
しかしNodeが立ち上がってない...?
コンソールに以下表示。contextあたりが怪しそうか。
Your current user or role does not have access to Kubernetes objects on this EKS cluster
This may be due to the current user or role not having Kubernetes RBAC permissions to describe cluster resources or not having an entry in the cluster’s auth config map.
いや、IAMか
上記の問題でEKSコンソールからは見れないが、EC2コンソールからはちゃんとnode立ち上がっているのを確認できた!!!
kc get nodesでもEKSコンソールからも立ち上がってるnodeが見えないが、EC2コンソールで確認するとEKS由来のEC2インスタンスは立ち上がってる。contextやIAMが関連してると思うが良く分からん。
kc get nodesで取れた!!!!!!!!!!!!
↓の方法でeks関連のモジュール使って作成したらkc get nodesで取れた。↑のQiitaの手順は古いものだったんだろうか...。↓のモジュール使う方法はだいぶ短く書けるし良い。
しかし依然WEBのEKSコンソールからは権限不足でnodeが見えない。ちゃんとIAMも付与出来てるっぽいんだが...。
作成したnodeにpodが載った!!!これはめでたい!!!やった!!!
$ kc logs -f myapp-pod
Hello Kubernetes!
tf apply
までのフロー確立できたからあとは早い
残:CW, S3, SQS, Route53, RDS
開発初期段階で不要なcwとroute53以外のインフラリソースはひとまず仮設定でデプロイできた。
あくまで仮設定なので、これから始めるWEBバックエンド実装で同時にリソースの細かい設定も詰めていく。
【設計】Webバックエンド Doing
完全OSSにしようかと思ってたがさすがにセキュリティ面が怖いのでterraform設定はprivate repositoryへ
忘れてた、SQSキューサイズを見ての3DPエンジンオートスケールはk8s-cloudwatch-adapter
を使う方針
参考:https://aws.amazon.com/jp/blogs/compute/scaling-kubernetes-deployments-with-amazon-cloudwatch-metrics/
TODO tfsec導入
API,DB,S3バケット,MQ設計 Done
webバックエンドWiki
バックエンド実装 start
前から気になっていたNode.jsのFastifyフレームワークで実装してみる
こんな感じのディレクトリ構成に
src
├── 3dphoto
│ ├── 3dphoto.controller.ts
│ ├── 3dphoto.routes.ts
│ └── 3dphoto.service.ts
├── common
│ └── interfaces
│ └── response.interface.ts
├── router.ts
├── server.ts
└── version
└── version.routes.ts
AuthorizationとErrorHandlingのフローをさくっと組み立てた。これから本質のロジック実装に入る。
src
├── 3dphoto
│ ├── 3dphoto.controller.ts
│ ├── 3dphoto.routes.ts
│ └── 3dphoto.service.ts
├── common
│ ├── authorization.ts
│ ├── error
│ │ ├── error.class.ts
│ │ └── error.handler.ts
│ └── interfaces
│ └── response.interface.ts
├── router.ts
├── server.ts
└── version
└── version.routes.ts
コンテナ化して動かしたfastifyだとちゃんとポートフォワード設定してもレスポンス返ってこない...と2時間くらい詰まってたが、どうやらコンテナ化するときはlisten時に0.0.0.0を設定しないといけなかったらしい。
Before
server.listen(3000, (err, address) => {
After
server.listen(3000, "0.0.0.0", (err, address) => {
TYPEORMにEntity認識されないなぁ...と悩んでたけど、entitiesをdist向きにするのを忘れてただけだった
Before
"entities": [
"src/entity/*.ts"
],
After
"entities": [
"dist/entity/*.js"
],
マイグレーションまでこれでうまくいった
"entities": [
"dist/entity/*.js"
],
"migrations": [
"src/migration/*.ts"
],
input_image table作成してapi側から参照するところまでできてる
SQSの全queue size取得。近似しか取得できないぽい。
aws-sdkの導入もdone
backendサーバーからSQSへEnqueue出来た!これは良い
あとは仕様書どうりにAPI実装やるだけ
SQS面白いなぁ
backendサーバからS3へimage画像を保存できた。ここまで来たらこっちのもん。
本当に、本当に今更だけど、↓は完全にあることを見落としてた
いや、上記の構成だと一人のユーザが同時にいくつも解析リクエストを投げられてしまうか。
IP単位でスタック数を制御しようにも複数台のPCでこられたらどうしようもない。
Googleアカウントでログインし、そのIDごとに一度にスタックできる解析リクエスト数を制御しようか(例えば一つのアカウントにつきスタックできる解析依頼は3つまでとか)
その場合別途DBでアカウント毎の解析進行数を管理?それともMQを見てそれぞれの依頼に紐づいているアカウントIDを確認できる?その辺りは調査。
そもそも進行してる解析をDBで管理しなくてもS3のinput bucketを見れば良いだけの話だろう...完全に盲点だった。なんで今のいままでこんな簡単なことに気がつかなかったんだろう。
諸々設計修正する。
修正Done.これでだいぶ設計もシンプルになった
コード修正もDone
これでinput追加APIは実装できた。SQSやS3も完璧に連携できてる。
input取得API Done
input削除API Done
output取得API Done. これでweb-backend実装はほぼ終わり。
次は3DPhoto生成エンジンを作り込む。
現状のディレクトリ構成。ほぼ1日でここまでしっかり構成作り込めたのは良い。
あとは意外にS3とSQSとの連携が簡単だった。
src
├── 3dphoto
│ ├── 3dphoto.controller.ts
│ ├── 3dphoto.routes.ts
│ └── 3dphoto.service.ts
├── common
│ ├── authorization
│ │ └── authorization.ts
│ ├── aws
│ │ ├── aws.s3.ts
│ │ └── aws.sqs.ts
│ ├── config
│ │ ├── config-local.json
│ │ ├── config-production.json
│ │ ├── config.json
│ │ └── config.ts
│ ├── error
│ │ ├── error.class.ts
│ │ └── error.handler.ts
│ └── interfaces
│ └── interface.response.ts
├── router.ts
├── server.ts
└── version
└── version.routes.ts
8 directories, 16 files
あと何気にRDSいらなくなったことで全体的な工数がガクッと減った。良い気づきだった。
RDS除外
【実装】webバックエンド Done(ほぼ)
【設計】3DPエンジン Next
なお3DP=3DPhotography
開発用S3バケットの様子
開発用SQSの様子
【設計】3DPエンジン Doing
【設計】3DPエンジン Done
【実装】3DPエンジン Doing
愚直にビルドしたらモデル含めてimageが5GBもあるな...これからダイエットする
モデルを含めない場合でも4.16GBあるな、おかしい。
pytorchとかcuda関連ツールで容量食ってる?
ビンゴ、pipパッケージのインストール手順省くと1.48GBまでに。
推論エンジンのソースコード削ったら876MB。
大体内訳がわかってきた。
そして876MBはちょうどベースのpython imageの大きさ。
こんなでかいのか。
要はalpineを使えと...
python3.7-slimで1GB減った
alpine導入するとさらに80MB減らせる見込みだけど、opencvのビルドエラーで面倒くさいことになってる。まあ妥協してpython3.7-slim使う方針で行こう。残りは必須なライブラリだから4GB imageはのちの課題としてひとまず妥協。
流石に5GBは大きすぎる、もう少し内訳を探る
56K /usr/local/lib/python3.7/site-packages/proglog
248K /usr/local/lib/python3.7/site-packages/wheel
292K /usr/local/lib/python3.7/site-packages/certifi
408K /usr/local/lib/python3.7/site-packages/requests
444K /usr/local/lib/python3.7/site-packages/tqdm
504K /usr/local/lib/python3.7/site-packages/transforms3d
516K /usr/local/lib/python3.7/site-packages/idna
872K /usr/local/lib/python3.7/site-packages/urllib3
1.1M /usr/local/lib/python3.7/site-packages/moviepy
1.1M /usr/local/lib/python3.7/site-packages/tifffile
1.6M /usr/local/lib/python3.7/site-packages/chardet
2.7M /usr/local/lib/python3.7/site-packages/setuptools
5.0M /usr/local/lib/python3.7/site-packages/imageio
8.8M /usr/local/lib/python3.7/site-packages/pip
9.9M /usr/local/lib/python3.7/site-packages/vispy
11M /usr/local/lib/python3.7/site-packages/networkx
25M /usr/local/lib/python3.7/site-packages/numpy
35M /usr/local/lib/python3.7/site-packages/matplotlib
35M /usr/local/lib/python3.7/site-packages/torchvision
43M /usr/local/lib/python3.7/site-packages/cynetworkx
65M /usr/local/lib/python3.7/site-packages/scipy
1.4G /usr/local/lib/python3.7/site-packages/torch
小手先のテクニック使っても4GB程度が限界だった...いったんissue切ってとりあえずこのまま進む
pythonからSQSとS3連携できた。あとはこの仕組みを既存の推論エンジンに組み込む。
s3 transferなる便利なものが
せやな
I think direct writing on S3 using multipart upload is a good solution. It will upload quickly and the process will be fast. As of now we are saving the output video on a local file and then that file is uploaded to S3 which takes time (1. video rendering 2. uploading 3. Deleting the video) and then respond to the client.
バックエンド側でSQS EnqueからS3画像保存までラグがあって、クライアントがMessage受信してS3からDLする頃にS3にオブジェクトがないという現象が起きていた。そうか、このためにSQSのMessage配信ラグ設定があったのか、学び。
delay sec = 1でうまくいった。にしても、Enque(from: backend) からDeque & S3 DL (from: 解析engine)までにこれまで1sもかかってなかったってことか、予想以上に早いな
バックエンドAPIへ画像POSTしたらSQS経由で同時に解析エンジンが動き出すところまで動いてる
REST APIでポチッとするだけでほぼ同時に別コンソールの解析エンジンが動き出す体験、良い。
API POST → 解析エンジンが動作 → S3へ成果物をOutput
まで、若干荒削りだけど動いた
docker runで立ち上げたpythonのprint内容がdocker logsで見えないなと思ったら、どうやらpython -uオプションで起動してあげないとstdoutをバッファしちゃうっぽかった。
Dequeしたあと処理で何かしらエラーが起こったらS3のoutputバケットにerror.jsonを吐くようにした
【実装】3DPエンジン Done
文献漁ってると解析エンジンのimageで10GB以上ある場合もあると知った。
よし4GBで妥協しよう()
【実装】Webフロントエンド Doing
フロントは実際作っていきながらインスパイアでUIデザインするのが好きだから、設計フェーズを飛ばす(ロジック面もまあ簡単なAPI叩くだけだから)
と、ここで解析エンジンをdockerで動かすとvispyがqt5を要求してクラッシュする問題がでた。
vispy & EGLでどうにかできないか探り中。
うーん、EGLはGPUレンダリングか。dockerでvispy動かすにはどうすれば。
engine_1 | RuntimeError: Could not import backend "EGL":
engine_1 | Could not initialize
OSMesa?
osmesaで動かしたが以下エラーが発生
error: attributeerror("'looseversion' object has no attribute 'version'")
手元のmac開発機だとcuda入らないので、g3sインスタンスにcudaやnvidia driver入れてエンジン単体で動かすと正常に動いた。GPU前提でDockerfile修正してエンジン開発はfixさせよう。
よし!g3sインスタンス&DockerでエンジンのSQS, S3連携まで動かせた。
【実装】3DPエンジン Done
ロゴをアップデートした
【実装】webフロントエンド Doing
React & SPAの構成で作る
とりあえずRoutingと基本ディレクトリ構造を作ってinit
ロゴ修正。だいぶ洗練できた。
ロゴアップデート、さらにイメージカラーを追加。ロゴと文字のバランスが難しいなぁ...。
あとインフラコストを抑えるために、解析Queueが0の場合はkubeのオートスケーリングで解析Node・Podも0にしたい
フロントデザイン脳内で色々fixしてきた。土日で一気に作り上げよう。
TODO: SQS & SNSの構成について学ぶ
だめだフロントデザインにこだわり過ぎてるな...ここは次の休みでもうfixさせよう
なるほど、イベントに対して並行処理が必要な場合「イベント発火→SNS→複数SQSへ配信」というフローがあるのか。
"SNSを挟むべき代表的なユースケースとしてFanoutパターンがあります。一つ目イベントに対して並行して処理を行う場合には、SNSをメッセージのハブの様に使用してPub/Subモデルのアーキテクチャを採用してPublisherで複数メッセージを送信せずにSNSに任せましょう。"
あーSNS挟みたいいいい。しかし今回のシステムではメリットなさそうか。。。
これまでS3へのinput画像配置とSQSへの解析依頼putはバックエンド側でやってたけそ、そもそもSQSへのputはS3のtrigger機能使えば自動で行けそう?要検討。
s3 bucket notifocation to sqs. 意外と簡単にできそう。https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_notification
うーん、重複処理を避けるためにFIFO Queue使うべき?
Redux入門すんぞ
知見upadte:FIFO, LIFO
ほう?
"なんならReduxは使わない方がいいでしょう。"
いやあくまでReact HooksはFunction ComponentでStateを使えるようにするだけってやつか?
もう面倒臭くなった(本来アプリ層にここまで時間をかけたくなかった)から、Class Component & Stateを酷使してAPIとフロントの連携としよう。
get inputsのAPI連携までできた
get outputsの連携も
とりあえず全APIとフロント表示との連携はできてる。
あとは細かいフロントのエラーハンドリングやログイン機構を作り込む。
しかしtrigger機能は一定も負荷を超えるとラグが酷くなるという話も聞くんだよなあ、要検証
はい
はい
【実装】webフロントエンド Done
知見だ
ALB Ingress Controllerなる便利なものがあるのか。。。
ALBのリソース管理をTerraformでやるかk8sでやるか考えないとなのか。もともとTerraformでやる想定だったが、ここはインフラとアプリケーション層の接合部だからなぁ...。
いや、Terraformでingressリソースを定義して、ServiceとのMappingはk8s層でやるという考え方なのか。
見えてきた
ALB経由でフロントエンド疎通や!!!!
おら!!!!!k8s設定完了してfront, back, ai engineの全疎通取れたぞ!!!!!!!これでサービスとして初めて本番乗った!!!!あとは細かいところ詰めるぞ!!!
優秀
backend podやfrontend podのCPU使用率ベースのスケーリングはあっさりできたけど、AI EngineのSQS Queue数を見てのスケーリングが一筋縄ではいかないなぁ...もう少し格闘。
うーん、ALB ingress導入まではできたんだが、External DNSでamena.uehr.coのレコード連携までうまくいかないなぁ...。
できたああああああああ!!!
ssl化もばっちり
【タスク】本番疎通確認 Done
【構築】インフラ構成 Done
初期ロードマップで予定していたタスクは全て完了。あとは細かい仕様やAIエンジンの性能改善に注力する。
現在p2.xlargeインスタンスでCPU推論を動かしていて、8m/imgの性能しか出ていない...。
UXを考えると、遅くとも5m/imgを目指したい。
8m/imgはあくまでリクエストキューが1枚しかない場合の数値。現状キュー数に応じてのオートスケールができていないため、キュー数に比例して解析時間も長くなる。GPU対応の後はアーキテクチャ的な速度改善も入れる。
SQSと連動した水平スケール TODO
あと、こういったパフォーマンス改善は下記の「Amena Performanse Improve」カンバンで管理。
cuda有効かしてpytorchでGPU認識できているにも関わらず早くならないなぁ...。
AIエンジンのpytorch側からGPUを認識できているにも関わらず、いくらGPUインスタンススペックあげても画像一枚の処理時間がほとんど変わらないなぁ...。CPUスペックも付随してアップしてるはずなんで、どうしてもこの値が処理性能限界か...? そんなことある?
p2.xlarge: 8m/img
p2.8xlarge: 8m/img
p2.16xlarge: 8m/img
g4dn.xlarge: 8m/img
g4dn.8xlarge: 6m/img
g4dn.16xlarge: 7m/img
もう少しエンジンの実装レベルも詰めてみて、それでもダメならアーキテクチャ面の速度改善に移る。
あとp3インスタンスも試してみよう
nvidia-smiでGPU使用率見るの忘れてた...
p3.xlargeだと10m掛かった。nvidia-smiでGPUメモリ使用率確認すると、平均:1%, 最大: 40%。
逆に遅くなったのは謎...。
おっとCPU使用率100%に張り付いてるぞ、これか
メモリは20%程度で止まってる。CPUバウンドだった?
CPU強強インスタンスを試してみよう
CPU最適化インスタンスのc5.metalで試すと7m/img
- GPUの有無は処理速度に関係ない?
- CPU性能格段に上がったのに処理速度はほぼ変わらず
- CPU使用率はずっと100%以上
もうよく分からなくなってきた
最終段階で以下を詰める(優先度順)
・エンジン水平スケール
・CI/CD
・軽微なUX
・各種資料
KEDA
ええやん
キューの中のメッセージ数を定期的に確認して、メッセージ数に応じた数の処理(Pod)を実行します。メッセージが0件ならPodは起動されませんし、大量にメッセージがあれば、それに応じた数のPodを起動します。
まさにこれを求めてた
以前の検証でGPUの有無はAIエンジンの処理性能に影響しないと分かったのでAIエンジンの実行環境はCPUインスタンスを採用予定。本来SQS TriggerでCPU処理動かすならLambdaで良いのでは?というのがあると思うが、以下理由によりあくまでPodで動かす方針で。
- Lambdaだと起動毎にモデルを落としてくる必要あり
- Podだと既にモデルが含まれてるImageで起動するだけで良い
- 今後AIエンジンをGPUチューニングで高速化させる可能性がある
- LambdaはGPU対応してない
KEDAでQueue数に応じたPodのスケーリングはできたが問題発生。例えばPod Aの処理が済んでQueueが一つ減った時、本来は役割を終えたPod Aを落として欲しいが、処理中のPod Bが落とされてしまう場合がある...。
Pod A: 処理済み
Pod B: 処理中
Down対象のPodをどう選んでいるのかをk8sのソースレベルで追ったところ、どうやらこうなっていたらしい。これを見ると、処理中のPodは ready だとControllerに認識させておけば、 優先度下がる?試してみよう。
// Sort the pods in the order such that not-ready < ready, unscheduled
// < scheduled, and pending < running. This ensures that we delete pods
// in the earlier stages whenever possible.
getPodsToDelete
https://github.com/kubernetes/kubernetes/blob/f794c824b1e6e68b302d94f42f60af4759e18c6d/pkg/controller/replicaset/replica_set.go#L684:6
この辺りRediness Probeか
画像処理中は input/ フォルダにinput画像が格納されるので、その画像があるか否かでRediness Probeを設定しよう。
うーん。。。
The minimum value of 1 is currently enforced by the EKS API and the Terraform AWS Provider is just validating that same limitation.
https://github.com/hashicorp/terraform-provider-aws/issues/13984
AIエンジン、処理に少なくともMemory 6Gi割り当てないとOEM Killedになる事がわかった。常時1Nodeは稼働させるとして、常駐コストを最小限に抑えられるインスタンスタイプを探す。
見事に以下の地雷を踏み抜いたが、なんとか思い通りにSQSのMSG数に応じてスケールアウトされるようになった。
- 処理済みのPodでなく処理中のPodがスケールインされてしまう
- Readiness Probeで処理済みのPodはNot Readyとすることで処理済みのPodから優先でTerminateするように
- MSGが複数Podに重複配信されてしまう
- Pod側でメッセージを受信してすぐに可視性タイムアウトを設定
- KEDAが「利用可能メッセージ」「処理中メッセージ」の前者のMSG数しか見ておらず、MSGの処理に入った瞬間に(利用可能-1, 処理中+1)スケールインされてしまう
- KEDAのソースコードを修正し前者と後者のMSG数の合算をSQSメトリクスとして扱うように
KEDAの仕様に関しては正直絶望したが、ソースコード弄ってなんとかできたのは胸熱だった。↑みたいに書くとあっさりしてるが、それぞれの解に行き着くまでが長かった...。この辺りのスケールアウト仕様、一回フローに起こたいな。
AIエンジン、処理に少なくともMemory 6Gi割り当てないとOEM Killedになる事がわかった。常時1Nodeは稼働させるとして、常駐コストを最小限に抑えられるインスタンスタイプを探す。
今はMemory 8Giある m5.large で動かしてるが、たまにOemKilledやEvicted起こるな...。しゃあない、常駐コスト増えるが16Giのインスタンス採用するか。Podには7Gi割り当てて、1Node 2Podの構成にしよう。
いや、常駐コストケチりたいんで、8Giインスタンスでもう少し探ってみよう
いろいろ試したが、どれも2割程度のPodでOEM Killedが発生。諦めて16Giインスタンスを採用するが、今度は常駐Node数を0に抑えられないかやってみる。以下を見る感じ難しそうではあるが...。
だめそうか...現状以下の構成で常駐になってるけど、このまま動かすと月5万以上掛かってくる想定。
とりあえず今はこのままで、コスト削減は後で対応しよう。
instance: m5.large
default node: 2
ai engine node: 1
SQSと連動した水平スケール Done
だめそうか...現状以下の構成で常駐になってるけど、このまま動かすと月5万以上掛かってくる想定。
とりあえず今はこのままで、コスト削減は後で対応しよう。
instance: m5.large
default node: 2
ai engine node: 1
↑、試算間違えた、この構成だと月3万行かないくらいか
m5.large でAIエンジン動かすと2割のPodでOem Killed発生という話、何回やっても見事に2割に収束する。面白い。
m5.largeより $0.03/hour 高くはなるがメモリ16Gi乗ってる r5.large 試してみるか。
r5.largeを使った2Pod/Nodeの構成でうまく稼働してくれた。このインスタンスで行くか。
もろもろ調整して以下に落ち着いた、この構成で常駐コストは1.7万/月くらいに抑えられるはず。
default node: t3.medium x 1
ai engine node: r5.large x 1
バックエンドCI設定 Doing
バックエンドCI設定 Done