こんにちは。
電通総研IT 重松です。
Azure クラウドサービスを使って、アプリケーション開発およびアーキテクチャ構築の業務を行っております。
この記事では、主な業務内容と直近で対応した.NET:Azure Functionsの開発についてご紹介します。
1.初めに
1-1. 自己紹介
まずは自己紹介をいたします。
私は、新卒でシステムエンジニアとしてキャリアをスタートし現在は6年目になります。
主に ITアーキテクト として .NET 系の技術 を活用しながら、クラウド上でシステム開発の業務に携わっています。
主な業務としては、次のような作業を行っています。
.NETバージョンアップ対応
システムの動作環境を最新の.NETフレームワークに更新する作業です。
この対応では、まず現在使用している.NETのバージョンを確認し、最新バージョンのリリースノートを調べます。
次に、既存のコードや使用しているライブラリが新バージョンと互換性があるかをチェックし、テスト環境でのアプリケーションで正しく動作するか確認します。
テストが成功したら、本番環境に新しいバージョンを展開し、パフォーマンスを引き続き監視します。
バージョンアップにより、セキュリティの強化や新機能の利用が可能となり、より安全で効率的なアプリケーション運用のために取り組んでいます。SQLチューニング
データベースのクエリ(SQL文)の性能を改善する作業です。
この対応では、まず無駄な処理を減らし、効率的にデータを取得するためにクエリの書き方を見直します。
次に、適切なインデックスを設定することでデータ検索の速度を向上させ、さらにデータベースがクエリをどのように実行するかを示す実行計画を分析してボトルネックを特定します。
SQLチューニングは、データベースの応答時間を短縮し、全体的なシステムパフォーマンスを向上させるために重要な作業であり継続的に対応しています。性能試験
システムが要求される性能基準を満たしているかを確認するためのテストです。
この試験では、応答時間やスループット、負荷耐性に焦点を当てます。
具体的には、システムがユーザーのリクエストにどれくらいの速さで応答するか、一定期間内に処理できるトランザクションの数、同時に多くのユーザーがアクセスした際の安定性を評価します。
性能試験は、システムが実運用で適切に動作することを保証し、潜在的なボトルネックの解消に向けて取り組んでいます。IaC(Infrastructure as Code)のメンテナンス
インフラストラクチャをコードとして管理する手法で、その代表的なツールである Terraform を対象に行っています。
Terraformを使ったリソースの構築、コードのGit管理、Terraformやプロバイダーの定期的なバージョンアップ等の作業を実施しています。
これらを行うことで、インフラを安定して運用し、将来的な変更にも柔軟に対応できるように構築に取り組んでいます。
これらの業務を通じて、システムの安定性とパフォーマンスを追求しつつ、新しい技術にも積極的にチャレンジしています。
技術の進化が速いIT業界で、柔軟に対応できるエンジニアを目指して日々取り組んでいます。
2. 業務紹介(Azure Functionsの分離ワーカーモデルへの移行)
ここからは、日々行っている業務の1例として、直近に対応した 「Azure Functionsの分離ワーカーモデルへの移行」 をご紹介いたします。
現在担当しているシステムでは、.NET6から.NET8へのバージョンアップ対応を行っております。
上記に伴って、Azure Functionsの実行モデル移行が必要になりました。
2-1. なぜ移行が必要か
そもそも実行モデルの移行が必要になった経緯を説明します。
Azure Functionsのインプロセスモデルが、2026年11月10日をもってサポートが終了することが発表されました。
インプロセスモデルは継続して利用可能なものの、セキュリティアップデートや新機能の提供は受けられないことからMicrosoft社は、分離ワーカーモデルへの移行を推奨しています。
また、次期バージョン.NET9ではインプロセスモデルは利用できず、分離ワーカーモデルへの移行が必須であるということから.NET 8に移行するこのタイミングで分離ワーカーモデルへの移行対応が必要になりました。
2-2. Azure Functionsのモデルの違い
次にそれぞれの実行モデルの特徴を以下に記載します。
インプロセスモデル
インプロセスモデルでは、Azure Functionsのランタイムとアプリケーションコードが同じプロセス内で実行されます。
このモデルの主な利点は、ランタイムと密接に統合されているため、パフォーマンスが高く、セットアップが比較的シンプルなことです。短い応答時間が求められるシンプルなアプリケーションに適しています。
ただし、ランタイムに依存するため、主にFunction Host側(画像青枠)のAzureアップデート等によりLanguage Worker側(アプリケーション)も影響を受けてしまうというデメリットがあります。
また、Function Host側にLanguage Worker側のアセンブリ.dll を読み込ませ、Function Host側 と一体となってコードを実行する仕組み上、.NET の最新バージョンを使いたい場合、Function Host側 が対応しない限りLanguage Worker側(アプリケーション)が利用できないといったデメリットもありました。
分離ワーカーモデル
一方で、分離ワーカーモデルでは、Azure Functionsのランタイムとアプリケーションコードが別々のプロセスとして実行されます。
これにより、Functions Host側に依存することなく、Language Worker側(アプリケーション)はアセンブリの依存関係やバージョン管理が柔軟に行えるようになったことがメリットとして挙げられます。
しかし、Functions HostとLanguage Worker間における通信が新たに追加されたこと(画像青線)、Language Workerが独立したことによる仕様変更を理解しつつ、アプリケーション開発を行うことが重要となります。
2-3. 移行にあたっての進め方
実際に移行するに当たりどのような作業をしているのかご説明します。
Microsoft社から、移行に当たってのマイグレーションガイドラインや実装/アプリケーション構築例などが、公式ドキュメントとして提供されています。
上記を指針として、以下のように各フェーズ毎に対応を行います。
前述に挙げた、マイグレーションガイドや実装例には記載されていない機能改修が多数確認されたため、実装~テストの工程は繰り返し行う必要があり、移行作業に時間を要しました。
また、クラウド上でのシステム開発の特性として、ローカル環境で正常に動作していたものが、クラウドサービス上では想定外の動作をする、といったことが頻繁に起こりえます。
こういったものを見落とさないためにも、上流の工程はもちろんのこと、テスト方針の決定やテスト実施を慎重かつ正確に行うことが重要になります。
3. 課題対応(診断設定経由でのログ出力および保存方式においてログが欠落する)
ここからは、開発を行っていく過程で苦労した課題についてご紹介します。
3-1.事象
担当システムでは、複数のログ出力方式を導入しています。
その中の1つに、Azure提供機能の 診断設定 というものを使用してログ出力するという仕組みを採用しています。
ログ出力までの経路は以下のようになっています。
・Azure Functions → ILogger → 診断設定→ ストレージアカウント
また、パフォーマンスの観点から、ILoggerの実行はバッファリングして 非同期 で行う仕組みとしていました。
分離ワーカーモデル移行後のアプリケーションで、上記の仕組みを動作させたところ、ログ欠落の事象が発生しました。
課題切り分けのため以下のようなアプローチを試みました。
- 非同期処理から同期処理への変更
ILoggerの実行を非同期方式から同期処理に変更したところ、ログの欠落は発生しないことを確認しました。
以下がサンプルコードになります。
- 同期処理によるログ出力(ログ欠落なし)
public void Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, FunctionContext functionContext) { // 開始ログ Logger.Log(aaa, model.Header, "Message"); await Task.Delay(1000); // 1秒待機 // 終了ログ Logger.Log(bbb, model.Header, "Message"); }
- 非同期によるログ出力(ログ欠落あり)
public void Run([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, FunctionContext functionContext) { // 開始ログ Logger.Log(aaa, model.Header, "Message"); // 業務処理実装(引数にMicrosoft.Extensions.Logging.Iloggerインスタンスを渡す) // 非同期で Run 呼び出し. Run 内で 1 秒待機中に、本関数内で終了ログが出力されて関数が終了する Run<BaseRequestModel>(myTimer, _logger, functionContext, false); // 終了ログ Logger.Log(bbb, model.Header, "Message"); } async Run<T>(xxx myTimer, ILogger logger, yyy functionContext, bool zzz) { logger.LogInformation("ログA"); await Task.Delay(1000); // 1秒待機 logger.LogInformation("ログB"); }
- Application Insightsへのログ出力の場合の挙動
前述に挙げた通り、複数のログ出力方式を採用している中の1つにApplication Insightsへのログ出力があります。
こちらの挙動を確認したところ、ログの欠落は発生しないことが確認されました。
以上から、非同期実行と診断設定の出力機構に問題があると推測を立てました。
3-2.原因と回避方法
原因
調査したところ、分離ワーカーモデルでの診断設定によるログ記録までの処理の流れが関係していることが判明しました。
分離ワーカーモデルでは、ホストが実行されるFunctions Hostプロセスと、関数コードが実行されるLanguage Workerプロセスに分離されますが、
診断設定のログは、Language Worker からの関数実行終了後の応答を契機として Functions Host にて記録しているとのことです。(画像赤線の部分)
分離ワーカーモデルでは Functions Host と Language Worker のプロセスが分かれていることにより、
「非同期実行したILoggerによるログ出力処理の終了を待たずメインの関数処理を終了してしまうと、関数実行後に記録されるログが拾いきれなくなる」というものでした。
この仕組みはインプロセスモデルも同様であるものの、分離ワーカーモデルでプロセス間通信(画像赤線)が発生することによりログの欠落が顕在化した、と理解しています。
一方、Application Insights のログは、画像青線の通り、Language Worker から直接記録されるため、プロセス間の通信がない分、診断設定ログに比べてログ欠落が発生しなかったのでは、と推測しています。
回避策
原因により、サブスレッドの終了を待たずに、メイン関数の処理が終了してしまっていたことでログの欠落が発生していたため、メイン関数の処理にてサブスレッドの終了を監視する処理の追加を試みました。
以下がサンプルコードになります。
public void Run([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, FunctionContext functionContext) { // 開始ログ Logger.Log(aaa, model.Header, "Message"); // 業務処理実装(引数にMicrosoft.Extensions.Logging.Iloggerインスタンスを渡す) // 非同期タスクを受け取る var task = Run<BaseRequestModel>(myTimer, _logger, functionContext, false); //非同期処理のタスクをwaitさせる task.Wait(); // 終了ログ Logger.Log(bbb, model.Header, "Message"); } async Run<T>(xxx myTimer, ILogger logger, yyy functionContext, bool zzz) { logger.LogInformation("ログA"); await Task.Delay(1000); // 1秒待機 logger.LogInformation("ログB"); }
これにより、ログの欠落が回避できることを確認しました。
補足
一方で、サブスレッドの実行終了を待機することでメインスレッド、サブスレッドの実行時間が延びることになります。
それにより、単位時間あたりの関数実行数に対してアクティブとなるスレッド数が増えることになるため
スレッド数の上限や使用できるリソースの上限に達しないように注意が必要であると考えています。
4.まとめ
マイグレーションガイド/実装例に、明確に記載されていない内容から発生した課題となります。
しかし、分離ワーカーモデルの仕組みやスレッドの仕様を理解することで対応することが出来ました。
分離ワーカーモデルは日々改修アップデートがされている機能です。
それにより、課題なども多く発生してしまっている状況ですが、これまで培った技術および知識を活用することで課題解決につながると感じました。
5.終わりに
今回はITアーキテクトの業務紹介と担当案件を1例として紹介いたしました。
難易度の高い業務ではあるものの、最新技術を活用し、複雑な課題を解決するスキルが求められるため、常に技術的な成長とチャレンジがある点が魅力だと感じています。
少しでも参考に、そしてITアーキテクトというものに興味を持っていただければ幸いです。
採用ページ
執筆:@shigematsu.shu、レビュー:@yukio.kazama
(Shodoで執筆されました)