恐らく最初に話をしてから 2 年近く経過している気がしますが、ついに待望の Durable Functions での E2E 分散トレーシングがプレビューとしてリリースされました。牛尾さんの努力の結晶とも言います。
α リリースと言われていますが、現時点での完成度はかなり高いと感じています。
Durable Functions の Distributed Tracing 実装のαバージョンをリリースしました。αなのでフィードバックを得ることが目的です、βに向かって作業をしたいと思いますので、フィードバックがあればお知らせください。ビデオ、デモ、サンプル、ドキュメントが含まれています。https://t.co/GdAVmsLPhy
— TsuyoshiUshio (@sandayuu) 2020年6月2日
以前に .NET Core での分散トレーシングについて調べた時には、Durable Functions については特に動きがないと書いていたのが懐かしいです。
大注目されている Durable Functions の場合は、Queue の値が隠蔽されているので比較的簡単に対応は行えそうですが、今のところは特に動きは無さそうです。
.NET Core における Activity と Application Insights による分散トレーシング - しばやん雑記
これで Durable Functions に必要だと考えていた 2 つの機能のうち、1 つに目処がついたことになります。残りの 1 つは Graceful Shutdown ですが、こっちも最近は多少動きが Azure Functions 全体としてあります。
大体の進捗は知っていましたが、実際に動くのを試したことはなかったので Acmebot で試しました。
分散トレーシングが特に必要な理由
Durable Functions はステートフルなオーケストレーターを簡単に記述できる一方で、その表現力の高さから非常に複雑なオーケストレーションも簡単に書けてしまいます。となると Application Insights でもオーケストレーター単位で確認する必要が出てきます。
しかしアクティビティは単独の Function として実行されるので、Application Insights 上では単なる呼び出しにしか見えません。アクティビティの自動リトライや Event Sourcing によるリプレイが組み合わさると、ログの量が非常に膨れ上がるため Application Insights から該当のログを追うのにも苦労することになります。
とどめに長時間実行や Consumption Plan でのスケーリングが追加されると、1 オーケストレーターの挙動を追うのはかなりの重労働になります。要するにめっちゃしんどかったです。
分散トレーシング対応バージョンをインストール
分散トレーシング対応バージョンを試す話に戻します。パッケージは別名で MyGet で配布されています。
バージョンが 2.2.0-alpha
なので、Durable Functions v2.2.0 相当のようです。試した限りでは Analyzer 周りが古いようで、最新版だと出ない警告が出るようになりました。
牛尾さんの紹介記事では Visual Studio から NuGet パッケージソースを追加する手順でしたが、CI と環境のことを考えると nuget.config
を作成してリポジトリに入れておくのが安全です。
<?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <!--To inherit the global NuGet package sources remove the <clear/> line below --> <clear /> <add key="nuget" value="https://api.nuget.org/v3/index.json" /> <add key="azure-appservice-staging" value="https://www.myget.org/F/azure-appservice-staging/api/v3/index.json" /> </packageSources> </configuration>
パッケージ名から分散トレーシング部分がプラガブルになったのかと思いましたが、実際には Durable Functions 自体のコードが含まれているので、既存の PackageReference
は削除しないとエラーになります。
Acmebot では早速大量のエラーが出たので、最初は意味が分かりませんでした。
きっついなー pic.twitter.com/rGSt8XeNRC
— しばやん (@shibayan) 2020年6月2日
原因としては Durable Functions のアセンブリ名が変わっていた + 厳密名が付けられていたので同じ型が複数存在するというエラーになっていたようです。
アクティビティを型安全に呼び出すプロキシで Durable Functions を参照していたので発生しました。
バージョン違いぐらいなら何とかできますが、今回はどうしようもなかったので使っているライブラリ側に手を入れて対応しました。正式リリースの時には気にせずに済みます。
後は host.json
で設定を行うだけでした。詳細は牛尾さんのブログを参照してください。
Application Insights から見つけるコツ
修正したアプリケーションをデプロイした後に、適当に動かして Application Insights にログを送信してみましたが、いつものように Performance => Operations の順に E2E Transaction に辿っていくと、上手くトレース結果は表示されませんでした。
何かコツがあるのではないかと思ったので、牛尾さんにいろいろ聞いてみました。このエントリを書いた理由は、この辺りのやり取りのログが流れるともったいないからです。
Dtで始まるテレメトリを開けると良いと思います。
— TsuyoshiUshio (@sandayuu) 2020年6月2日
何故そうなるかと言うと、オーケストレーターのリトライのテレメトリが出てると思います(Dtない奴) あれはFunctionHost側で勝手にトラックされてる奴で、論理的なオーケストレーションと、考えが違うのでそのまま残しています。
— TsuyoshiUshio (@sandayuu) 2020年6月2日
曰く DtActivity
や DtOrchestrator
から始まる Request を探すのが良いらしいです。確かに Logs から Request で絞り込んでみたところ、該当のログが見つかりました。
Operations には出てこないようですが、同時に送信している依存関係のテレメトリは Dependencies に出てきているので、ここから追うことも出来ました。正常系の確認は追うのに最初はコツが必要な感じですが、例外の場合は Failures から簡単に追えます。
HTTP で開始するオーケストレーターの場合は Operations から E2E Transaction を開くと、謎の HttpRequestIn
というログがあるので、これを展開することで全体のトレースを確認できます。
実際に HTTP-01 を利用して Let's Encrypt で証明書を発行した時のトレーシング結果が以下の通りです。
非常に綺麗にオーケストレーターの処理フローが確認できますし、それぞれのアクティビティで実行されている API の確認も簡単です。エラーが発生したタイミングも一目瞭然なので、運用では確実に役立ちます。
Durable Functions の分散トレーシングが便利すぎて、正式リリースされるのが待ちきれない気分です。
実際に運用している環境で使っていきたいですが、今のところは 2.2.1
と 2.2.2
でのリリース差分が取り込まれるのを待とうと思っています。