Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

サーバーレスの常識を覆す Azure Durable Functionsを使い倒す

https://serverless.connpass.com/event/95334/

  • Login to see the comments

サーバーレスの常識を覆す Azure Durable Functionsを使い倒す

  1. 1. サーバーレスの常識を覆す Azure Durable Functionsを使い倒す 2018/08/22 Serverless Meetup Fukuoka #2 @tsubakimoto_s
  2. 2. 松村優大 (MLBお兄さん) • 株式会社オルターブース • Microsoft MVP (Developer Technologies) • C#/PHP/Azure/AWS • 島根県出身 3031歳 2
  3. 3. 本日の内容 • Serverless Services on Microsoft Azure • Azure Durable Functions • デモ 3
  4. 4. Serverless Services on Microsoft Azure https://azure.microsoft.com/ja-jp/overview/serverless-computing/ https://azure.microsoft.com/ja-jp/campaigns/serverless/ 4
  5. 5. 5https://www.youtube.com/watch?v=cOFlSvnupQM
  6. 6. 6 Azure Functions Logic Apps Event Grid
  7. 7. 7 Platform as a Service アプリケーション コード ロジック トリガー
  8. 8. Azure Functions 8 イベントドリブン型のコードを実行でき るサービス。従来のホスティングプラン の他、実行時間・実行回数に対する従量 課金プランが提供されている。 Webhookをはじめ、Microsoft Azure、 Microsoft Graph、サードパーティの サービスと連携することができる。
  9. 9. Language Runtime v1.x Runtime v2.x C# GA Preview Node.js GA Preview F# GA - Java - Preview Python Experimental - PHP Experimental - TypeScript Experimental - .cmd, .bat Experimental - Bash Experimental - PowerShell Experimental - 9
  10. 10. Language Runtime v1.x Runtime v2.x C# GA Preview Node.js GA Preview F# GA - Java - Preview Python Experimental - PHP Experimental - TypeScript Experimental - .cmd, .bat Experimental - Bash Experimental - PowerShell Experimental - 10 仕様変更もある
  11. 11. 通常のFunctionsの実装 11 トリガー(入力) バインド(出力) 単一処理の軽量な コードが望ましい
  12. 12. Azure Durable Functions The primary use case for Durable Functions is simplifying complex, stateful coordination problems in serverless applications. 12 【de:code 2018】AD02 Serverless の世界を進化させるイノベーション - Durable Functions https://youtu.be/QuXO5plBiFM
  13. 13. Visual Studio • Visual Studio 15.3~ • Azure開発のワークロード • Azure Storage Emulator • 拡張機能 Microsoft.Azure.WebJobs.Extensions.DurableTask • C#での開発に適している 13https://docs.microsoft.com/ja-jp/azure/azure-functions/durable-functions-install
  14. 14. Visual Studio Code • Azure Functions Core Tools 2.x • Azure Storage Emulator • 拡張機能 Microsoft.Azure.WebJobs.Extensions.DurableTask • C#, Node.jsでの開発に適している 14https://docs.microsoft.com/ja-jp/azure/azure-functions/durable-functions-install
  15. 15. Durable Functions Pattern 1. 関数チェーン 2. ファンアウト/ファンイン 3. 非同期のHTTP API 4. 監視 5. 人による操作 15https://docs.microsoft.com/ja-jp/azure/azure-functions/durable-functions-overview
  16. 16. パターン1 : 関数チェーン 16 本来、Queueでつないで連鎖する一連の 関数を、Queueなしで実行できる機能。
  17. 17. ドキュメントのサンプルでは動かない 17
  18. 18. Durable Functionsの仕組み • クライアント関数(OrchestrationClientAttribute) • 関数全体の実行トリガーとなる • オーケストレーター関数(OrchestrationTriggerAttribute) • アクティビティ関数を呼出し、結果の受取を行う • アクティビティ関数(ActivityTriggerAttribute) • 実際の処理を行う作業単位 18
  19. 19. 19 [FunctionName("F1")] public static async Task<HttpResponseMessage> HttpStart( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")]HttpRequestMessage req, [OrchestrationClient]DurableOrchestrationClient starter, ILogger log) { string instanceId = await starter.StartNewAsync("F2", null); log.LogInformation($"Started orchestration with ID = '{instanceId}'."); return starter.CreateCheckStatusResponse(req, instanceId); } [FunctionName("F2")] public static async Task<List<string>> RunOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context) { var outputs = new List<string>(); outputs.Add(await context.CallActivityAsync<string>("F3", "Tokyo")); outputs.Add(await context.CallActivityAsync<string>("F3", "Osaka")); outputs.Add(await context.CallActivityAsync<string>("F3", "Fukuoka")); return outputs; } [FunctionName("F3")] public static string SayHello([ActivityTrigger] string name, ILogger log) { log.LogInformation($"Saying hello to {name}."); return $"Hello {name}!"; } クライアント関数 オーケストレーター関数 アクティビティ関数
  20. 20. パターン2 : ファンアウト/ファンイン 20 複数の関数を並列に実行してすべてが 完了するまで待機するパターン。
  21. 21. パターン3 : 非同期のHTTP API 21 長時間実行する関数の“状態”を取得する ためのAPIを公開する。
  22. 22. Durable FunctionsのAPIレスポンス(JSON) 項目 説明 id オーケストレーションインスタンス の ID statusQueryGetUri オーケストレーションインスタンス の状態を取得するURL sendEventPostUri オーケストレーションインスタンス のイベントを発生させるURL terminatePostUri オーケストレーションインスタンス を終了させるURL 22
  23. 23. 例 23 { "id": "2b729f0beb2c44358a9f1c2a75197322", "statusQueryGetUri": "http://localhost:7071/runtime/webhooks/DurableTaskExte nsion/instances/2b729f0beb2c44358a9f1c2a75197322?taskHu b=DurableFunctionsHub&connection=Storage&code=2bYl3HewP In8QZMTYiPA0ifHuJ6WSR/t38v1923ru8S8LzbXFNaaCg==", ... }
  24. 24. statusQueryGetUri (待機中) 24 { "instanceId": "2b729f0beb2c44358a9f1c2a75197322", "runtimeStatus": "Pending", "input": null, "customStatus": null, "output": null, "createdTime": "2018-08-15T20:58:47Z", "lastUpdatedTime": "2018-08-15T20:58:47Z" }
  25. 25. statusQueryGetUri (実行中) 25 { "instanceId": "2b729f0beb2c44358a9f1c2a75197322", "runtimeStatus": "Running", "input": null, "customStatus": null, "output": null, "createdTime": "2018-08-15T20:58:47Z", "lastUpdatedTime": "2018-08-15T20:58:48Z" }
  26. 26. statusQueryGetUri (完了) 26 { "instanceId": "2b729f0beb2c44358a9f1c2a75197322", "runtimeStatus": "Completed", "input": null, "customStatus": null, "output": [ "Hello Tokyo!", "Hello Seattle!", "Hello London!" ], "createdTime": "2018-08-15T20:58:47Z", "lastUpdatedTime": "2018-08-15T20:59:01Z" }
  27. 27. パターン4 : 監視 27 外部の関数を監視し、関数の状態によっ て後続の処理を変える。
  28. 28. パターン5 : 人による操作 28 イベントが呼び出されるまで関数の実行 を止める。 例)上司の承認が必要なワークフロー
  29. 29. 29 [FunctionName("Approval_Run")] public static async Task RunOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context) { bool approved = await context.WaitForExternalEvent<bool>("Approval"); if (approved) { /* approval granted */ } else { /* approval denied */ } } [FunctionName("Approval_Request")] public static async Task RequestApproval( [QueueTrigger("approval-queue")] string instanceId, [OrchestrationClient]DurableOrchestrationClient client) { await client.RaiseEventAsync(instanceId, "Approval", true); } オーケストレーター関数 外部イベント関数
  30. 30. 30 [FunctionName("Approval_Run")] public static async Task RunOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context) { bool approved = await context.WaitForExternalEvent<bool>("Approval"); if (approved) { /* approval granted */ } else { /* approval denied */ } } [FunctionName("Approval_Request")] public static async Task RequestApproval( [QueueTrigger("approval-queue")] string instanceId, [OrchestrationClient]DurableOrchestrationClient client) { await client.RaiseEventAsync(instanceId, "Approval", true); } ここで処理が止まり “Approval”という イベント呼出しを待つ
  31. 31. 31 [FunctionName("Approval_Run")] public static async Task RunOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context) { bool approved = await context.WaitForExternalEvent<bool>("Approval"); if (approved) { /* approval granted */ } else { /* approval denied */ } } [FunctionName("Approval_Request")] public static async Task RequestApproval( [QueueTrigger("approval-queue")] string instanceId, [OrchestrationClient]DurableOrchestrationClient client) { await client.RaiseEventAsync(instanceId, "Approval", true); } キューにインスタンスID をセットする
  32. 32. 32 [FunctionName("Approval_Run")] public static async Task RunOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context) { bool approved = await context.WaitForExternalEvent<bool>("Approval"); if (approved) { /* approval granted */ } else { /* approval denied */ } } [FunctionName("Approval_Request")] public static async Task RequestApproval( [QueueTrigger("approval-queue")] string instanceId, [OrchestrationClient]DurableOrchestrationClient client) { await client.RaiseEventAsync(instanceId, "Approval", true); } 指定したインスタンスIDの “Approval”イベントを呼出す
  33. 33. 33 [FunctionName("Approval_Run")] public static async Task RunOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context) { bool approved = await context.WaitForExternalEvent<bool>("Approval"); if (approved) { /* approval granted */ } else { /* approval denied */ } } [FunctionName("Approval_Request")] public static async Task RequestApproval( [QueueTrigger("approval-queue")] string instanceId, [OrchestrationClient]DurableOrchestrationClient client) { await client.RaiseEventAsync(instanceId, "Approval", true); } イベントの結果を受けて 後続の処理を実行
  34. 34. 34 [FunctionName("Approval_Run")] public static async Task RunOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context) { bool approved = await context.WaitForExternalEvent<bool>("Approval"); if (approved) { /* approval granted */ } else { /* approval denied */ } } [FunctionName("Approval_Request")] public static async Task RequestApproval( [QueueTrigger("approval-queue")] string instanceId, [OrchestrationClient]DurableOrchestrationClient client) { await client.RaiseEventAsync(instanceId, "Approval", true); } 文字列やオブジェクトを 渡すことも可能
  35. 35. 価格モデル • App Serviceプラン • 使用するリソースに対する課金 • 常時接続可能(AlwaysOn) • 従量課金プラン • 関数の実行時間と実行回数に対する課金 • 無料枠あり • Cold Startやオートスケールの考慮が必要 35
  36. 36. 36 [FunctionName("Approval_Run")] public static async Task RunOrchestrator( [OrchestrationTrigger] DurableOrchestrationContext context) { bool approved = await context.WaitForExternalEvent<bool>("Approval"); if (approved) { /* approval granted */ } else { /* approval denied */ } } ここで処理が止まり “Approval”という イベント呼出しを待つ 待機中の時間(=イベントが呼び出されるまで)は課金対象になる? 課金対象にならない
  37. 37. デモ https://github.com/tsubakimoto/serverless-meetup-fukuoka-v2 37
  38. 38. 38 Application Insights Azure Functions Blob Storage SlackWeb Browser 上司の承認 結果の通知
  39. 39. 私が思う アンチパターン 39 if 条件1 条件2 条件3 条件4 条件5 output1 output2 output3 output4 output5 トリガー ひとつのFunctionで複数の出力を行うやつ
  40. 40. 40 output output output output output 単処理になるように分解する
  41. 41. 宣伝 41
  42. 42. 42
  43. 43. 43
  44. 44. 44 https://fukuten.connpass.com/event/95744/
  45. 45. ご清聴ありがとうございました 45

×