Upgrade to Pro — share decks privately, control downloads, hide ads and more …

音声プラットフォームのアーキテクチャ変遷から学ぶ、クラウドネイティブなバッチ処理 (20250...

音声プラットフォームのアーキテクチャ変遷から学ぶ、クラウドネイティブなバッチ処理 (20250422_CNDS2025_Batch_Architecture)

2025年4月22日に開催された「CloudNative Days Summer 2025 プレイベント」での発表資料です。
https://cloudnativedays.connpass.com/event/351211/

プロポーザル内容
---
既存システムのクラウド移行の際、単にクラウドで実行するだけではそのメリットを享受することができません。移行前と同等の性能を出すために移行前以上のコストがかかってしまうことさえあります。

本セッションでは、Voicyの音声処理アーキテクチャの変遷を通じて、クラウド環境におけるバッチ処理の設計についてお話しします。ワークロードに応じて適切なリソースが割り当てられる設計とすることで、性能とコストの両方を改善することができます。

具体的には、従来のCronベースの逐次処理から、並列化による処理の高速化、キューを活用したイベントドリブンな形式への変更、コンテナによるオートスケーリングの適用といった流れと、それぞれの変更の狙いを解説します。また、その過程におけるマネージドサービスと内製サービスの使い分けについてもご紹介します。

今回テーマとする音声処理には、アップロードされた音源のフォーマット変換やノイズ低減、音量調節などが含まれます。これらはビジネス的な制約により、遅くとも数分以内の完了が求められます。

想定する聞き手
- クラウド環境でバッチ処理を設計するアーキテクトや開発者

---

P. 30 に書いてある「以前の発表」のリンクはこちら
https://speakerdeck.com/thousanda/20230705-concurrent-normalization

Koki Senda

April 22, 2025
Tweet

More Decks by Koki Senda

Other Decks in Programming

Transcript

  1. © Voicy, Inc. はじめに
 クラウド環境におけるバッチ処理の設計 
 • ただクラウドで実行すればいいわけではない
 ◦ 例:

    オンプレでやっていたことをそのままクラウドの仮想サーバー上で実行 
 ▪ → ランニングコストはむしろ上がる傾向 
 
 • クラウドネイティブなアーキテクチャが必要 
 ◦ → Voicyの音声処理のアーキテクチャ変遷を通じて解説 
 

  2. © Voicy, Inc. この発表で言いたいこと 
 「パフォーマンス」と「コスト」の両方を改善
 • 事前準備
 ◦ 疎結合


    ▪ Evnet-driven
 ▪ Queueing
 ◦ 冪等
 ▪ 並列処理
 ▪ リトライ
 • Autoscaling
 ◦ いつスケールアウトするべきか/いつスケールインしていいか 
 すべてはAutoscalingのために 

  3. © Voicy, Inc. 自己紹介
 • 名前
 ◦ 千田 航己 (せんだ

    こうき) 
 • 担当
 ◦ チームリード
 ◦ バックエンド開発, クラウドインフラ 
 • 仕事でよく使う技術
 ◦ Go
 ◦ Kubernetes
 ◦ AWS
 • 趣味
 ◦ ギターと将棋とオムライス作り 
 ソフトウェアエンジニア 

  4. © Voicy, Inc. Voicyにおける音声処理 
 収録された音源が配信されるまで 
 パーソナリティ
 収録
 リスナー


    音声処理1
 音声処理2
 音量調節
 ノイズ低減
 など
 統一フォーマット
 への変換

  5. © Voicy, Inc. リスナー目線 
 • コア機能「安定した聴取体験」
 パーソナリティ目線 
 •

    編集の手間をかける必要がない
 • 録ったらすぐに公開したい
 ◦ → 数分程度では処理されてほしい 
 Voicyにおける音声処理 
 重要性とビジネス要件 
 音声処理1
 音声処理2
 音量調節
 ノイズ低減
 など
 統一フォーマット
 への変換

  6. © Voicy, Inc. アーキテクチャ変遷 
 • 初期のアーキテクチャ
 • Step 1.

    Event-drivenアーキテクチャ
 • Step 2. 並列処理
 • Step 3. Autoscaling
 • (Step 4. Cluster Autoscaling)
 目次

  7. © Voicy, Inc. 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理 


    ◦ 直列実行
 Cronによる定期実行 
 バッチサーバー
 (仮想サーバー)
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1 
 内製
 音声処理サービス
 on K8s
 リクエスト
 定期監視
 1件ずつ
 処理依頼

  8. © Voicy, Inc. 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理 


    ◦ 直列実行
 Cronによる定期実行 
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1 
 リクエスト 
 アップロード 
 バッチサーバー
 (仮想サーバー)
 内製
 音声処理サービス
 on K8s

  9. © Voicy, Inc. 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理 


    ◦ 直列実行
 Cronによる定期実行 
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1 
 定期監視
 バッチサーバー
 (仮想サーバー)
 内製
 音声処理サービス
 on K8s

  10. © Voicy, Inc. 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理 


    ◦ 直列実行 
 Cronによる定期実行 
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1 
 参照
 1件ずつ
 処理依頼
 バッチサーバー
 (仮想サーバー)
 内製
 音声処理サービス
 on K8s

  11. © Voicy, Inc. 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理 


    ◦ 直列実行
 Cronによる定期実行 
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1
 取得
 バッチサーバー
 (仮想サーバー)
 内製
 音声処理サービス
 on K8s

  12. © Voicy, Inc. 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理 


    ◦ 直列実行
 Cronによる定期実行 
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1
 処理
 バッチサーバー
 (仮想サーバー)
 内製
 音声処理サービス
 on K8s

  13. © Voicy, Inc. 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理 


    ◦ 直列実行
 Cronによる定期実行 
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1
 格納
 バッチサーバー
 (仮想サーバー)
 内製
 音声処理サービス
 on K8s

  14. © Voicy, Inc. 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理 


    ◦ 直列実行
 Cronによる定期実行 
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1
 完了連絡
 バッチサーバー
 (仮想サーバー)
 内製
 音声処理サービス
 on K8s

  15. © Voicy, Inc. 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理 


    ◦ 直列実行
 Cronによる定期実行 
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 0 
 完了連絡
 記録
 バッチサーバー
 (仮想サーバー)
 内製
 音声処理サービス
 on K8s

  16. © Voicy, Inc. 初期アーキテクチャの問題点 
 • サーバーのリソース量が一定
 ◦ 短時間にたくさんアップロードされると待ち時間が長くなる 


    ◦ 仕事がないときでもお金がかかる 
 • 直列処理
 ◦ 巨大データがひとつあるだけで後続の処理が滞る 
 • 状態管理の方法に難あり
 ◦ ステータスが二値しかなくジョブの状態管理が難しい 
 ◦ DBが他の用途にも使われており、責務が混在 
 スケーラビリティがない 
 バッチサーバー
 (仮想サーバー)
 内製
 音声処理サーバー
 on K8s
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)

  17. © Voicy, Inc. Step 1. Event-drivenアーキテクチャ 
 • ジョブの処理状況の把握が困難
 ◦

    ステータスが処理対象かそうでないかの二値しかない 
 • DBが他の用途にも使われており、責務が混在
 ◦ 関係ない負荷の影響を受ける / 関係ない処理に影響を与える 
 
 Pick up: 初期アーキテクチャの問題点 
 バッチサーバー
 (仮想サーバー)
 RDB (音源のメタデータ)
 依頼者
 under_processing = 1 
 リクエスト
 定期監視

  18. © Voicy, Inc. Step 1. Event-drivenアーキテクチャ 
 • ProducerとConsumerが疎結合になる
 •

    ジョブの処理状況を管理しやすい
 ◦ 「待ち/処理中/完了」を表現 
 ◦ リトライが容易 など
 • Queue自体も他のシステムと独立にスケール可能
 Queueを採用する (VoicyではAmazon SQS) 
 Job Handler (Consumer)
 on K8s
 Queue
 依頼者 (Producer)
 リクエスト
 定期監視
 (Polling)
 (これは初期アーキテクチャでも実現されていた)
 (汎用DBでも同じことはできるが大変)

  19. © Voicy, Inc. Step 1. Event-drivenアーキテクチャ 
 • 「同じ処理を何度実行しても同じ結果になる」ようにしておく
 ◦

    → 失敗したら再実行すればよくなる 
 一連の処理を冪等にする 
 内製
 音声処理サーバー
 on K8s
 処理依頼
 Job Handler (Consumer)
 on K8s
 Queue
 Polling
 失敗しました
 もう一回頼む

  20. © Voicy, Inc. Step 1 終了後のアーキテクチャ 
 入り口がQueueになった & リトライしやすくなった

    
 オブジェクトストレージ (音源本体)
 依頼者
 Job Handler (Consumer)
 on K8s
 Queue
 リクエスト
 定期監視
 (Polling)
 処理依頼
 内製
 音声処理サービス
 on K8s

  21. © Voicy, Inc. 比較: 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理

    
 ◦ 直列実行
 Cronによる定期実行 
 バッチサーバー
 (仮想サーバー)
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1 
 内製
 音声処理サービス
 on K8s
 リクエスト
 定期監視
 1件ずつ
 処理依頼

  22. © Voicy, Inc. Step 2. 並列処理 
 • 直列処理
 ◦

    巨大データがひとつあるだけで後続の処理が滞る 
 
 Pick up: 初期アーキテクチャの問題点 
 バッチサーバー
 (仮想サーバー)
 RDB (音源のメタデータ)
 under_processing = 1 
 参照
 1件ずつ
 処理依頼
 内製
 音声処理サーバー
 on K8s

  23. © Voicy, Inc. Step 2. 並列処理 
 • 入り口がQueueになったことでジョブの状態管理が楽になっている
 •

    一連の処理を冪等化したので、同じ処理が複数回走っても壊れない
 
 Step 1 の結果 
 1件ずつ
 処理依頼
 Queue
 Polling
 内製
 音声処理サーバー
 on K8s
 Job Handler (Consumer)
 on K8s

  24. © Voicy, Inc. Step 2. 並列処理 
 • 入り口がQueueになったことでジョブの状態管理が楽になっている
 •

    一連の処理を冪等化したので、同じ処理が複数回走っても壊れない
 → 8倍高速に! 
 音声処理サーバーへのリクエストを並行化 
 並行して複数処理依頼 
 Queue
 Polling
 以前の発表: https://speakerdeck.com/thousanda/20230705-concurrent-normalization 
 内製
 音声処理サーバー
 on K8s
 Job Handler (Consumer)
 on K8s

  25. © Voicy, Inc. Step 2 終了後のアーキテクチャ 
 ジョブの並列処理が可能になりました 
 オブジェクトストレージ

    (音源本体)
 依頼者
 Queue
 リクエスト
 Polling
 処理依頼
 Job Handler (Consumer)
 on K8s
 内製
 音声処理サービス
 on K8s

  26. © Voicy, Inc. 比較: 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理

    
 ◦ 直列実行
 Cronによる定期実行 
 バッチサーバー
 (仮想サーバー)
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1 
 内製
 音声処理サービス
 on K8s
 リクエスト
 定期監視
 1件ずつ
 処理依頼

  27. © Voicy, Inc. Step 2 の問題点 
 • Job Handlerが単一障害点

    (Single Point of Failure; SPOF)
 ◦ 音声処理サーバーのスペックが固定 → 意図せず並列度が上がるとパンクする 
 ◦ 並列度をコントロールしやすくするためにひとつのインスタンスにしてしまった 
 
 
 当時の自分の設計ミス 
 処理依頼
 Queue
 Polling
 SPOF
 内製
 音声処理サーバー
 on K8s
 Job Handler (Consumer)
 on K8s

  28. © Voicy, Inc. Step 3. Autoscaling 
 • こちらはまだ本番リリースされていません
 •

    (発表までもう1か月あると思ってた...)
 ◦ CNDS2025: 5月23日 
 ◦ プレイベント: 4月22日 ← 今日 
 注釈

  29. © Voicy, Inc. Step 3. Autoscaling 
 • サーバーのリソース量が一定
 ◦

    短時間にたくさんアップロードされると待ち時間が長くなる 
 ◦ 仕事がないときでもお金がかかる 
 Pick up: 初期アーキテクチャの問題点 
 バッチサーバー
 (仮想サーバー)
 処理依頼
 内製
 音声処理サーバー
 on K8s

  30. © Voicy, Inc. Step 3. Autoscaling 
 • サーバーのリソース量が一定
 ◦

    短時間にたくさんアップロードされると待ち時間が長くなる 
 • 並列化された
 ◦ が、並列度を超える量の重いリクエストが届くとやはり滞る 
 Step 2 で並列処理できるようになった 
 バッチサーバー
 (仮想サーバー)
 処理依頼
 処理依頼
 内製
 音声処理サーバー
 on K8s
 Job Handler (Consumer)
 on K8s
 内製
 音声処理サーバー
 on K8s

  31. © Voicy, Inc. Step 3. Autoscaling 
 • まずはJob Handlerと音声処理サーバーの機能を統合


    ジョブの量に応じて勝手にリソース量を調節してほしい 
 音声処理Consumer on K8s
 Queue
 Polling

  32. © Voicy, Inc. Step 3. Autoscaling 
 • まずはJob Handlerと音声処理サーバーの機能を統合


    • 次にConsumerを複数立ち上げる
 ジョブの量に応じて勝手にリソース量を調節してほしい 
 音声処理Consumers on K8s
 Queue
 Polling
 ・・・
 処理を冪等にしておけばこれが可能 

  33. © Voicy, Inc. Step 3. Autoscaling 
 • KEDA: Kubernetes

    Event-driven Autoscaling 
 ◦ イベントに応じて水平スケールできるAutoscaler 
 ◦ 例: Amazon SQSの場合 
 ▪ 最小: 0 pods
 ▪ 最大: 5 pods
 ▪ 10メッセージ溜まるごとに1 pod増やす 
 ジョブの量に応じて勝手にリソース量を調節してほしい 
 Queue
 Polling
 ・・・
 音声処理Consumers on K8s

  34. © Voicy, Inc. Step 3. 終了後のアーキテクチャ 
 ジョブの量に応じてConsumersがAutoscalingされます 
 音声処理Consumers

    on K8s
 ・・・
 オブジェクトストレージ (音源本体)
 依頼者
 Queue
 リクエスト
 Polling

  35. © Voicy, Inc. 比較: 初期のアーキテクチャ 
 • 特徴
 ◦ RDBで処理状況を管理

    
 ◦ 直列実行
 Cronによる定期実行 
 バッチサーバー
 (仮想サーバー)
 RDB (音源のメタデータ)
 オブジェクトストレージ (音源本体)
 依頼者
 under_processing = 1 
 内製
 音声処理サービス
 on K8s
 リクエスト
 定期監視
 1件ずつ
 処理依頼

  36. © Voicy, Inc. Step 4. Cluster Autoscaling 
 • VoicyではKubernetesを使っている


    ◦ Worker Nodeは仮想サーバー (EC2) 
 ◦ → Podだけでなく、Nodeのスケーリングも考慮する必要がある 
 ▪ Podのスケールアウトに合わせて Nodeも増えないとリソースが不足する かも
 ▪ Podのスケールインに合わせて Nodeも減らないと料金は減らない 
 
 必要な人のみ対象 

  37. © Voicy, Inc. むすび
 クラウド環境におけるバッチ処理の設計 
 • ただクラウドで実行すればいいわけではない
 • いかにAutoscalingするか

    
 ◦ → 「パフォーマンス」と「コスト」の両方を改善 
 • Autoscalingできる状態にするための用意
 ◦ 疎結合
 ▪ Evnet-driven
 ▪ Queueing
 ◦ 冪等
 ▪ 並列処理
 ▪ リトライ

  38. © Voicy, Inc. マネージドサービス 
 • ファイル形式の変換
 • 音量調節 (一部)


    内製サービス 
 • 音量調節
 • ノイズ低減
 マネージドサービス vs 内製サービス 
 Voicyの音声処理ではそれぞれどちらを使っているか 

  39. © Voicy, Inc. マネージドサービス 
 • ファイル形式の変換
 • 音量調節 (一部)


    特徴
 • 高い信頼性
 • 低い開発工数
 • 高い料金
 → お金を使って、簡単高品質
 内製サービス 
 • 音量調節
 • ノイズ低減
 特徴
 • 高いカスタマイズ性
 • 高い開発工数
 • 低い料金
 → 労力を使って、お安く高機能
 マネージドサービス vs 内製サービス 
 それぞれの特徴 

  40. © Voicy, Inc. ファイル形式の変換
 • 基本的な機能のため初期から必要だった = 開発工数削減のためにマネージドサービス を使ったのかも
 •

    リリース当初は負荷の量が予測できなかっ た
 • 内製サービスに移行する可能性は? 
 ◦ 単調な処理のため、コスト観点から移 行する可能性がある 
 音量調節 & ノイズ低減
 • 細かいパラメータ調節が必要な処理であり、 内製が理にかなっている 
 • マネージドサービスに移行する可能性は? 
 ◦ 重い計算が必要なため、内製サービ スで信頼性の確保が難しくなったら検 討する価値がある
 ◦ AIによる音声処理サービス等がマネー ジドで提供され始めた場合に使いたく なるかもしれない
 マネージドサービス vs 内製サービス 
 意思決定の理由と今後の方針