はじめに
初めまして。プラットフォーム事業本部ペイメントサービス部決済スクラムチームの小菅(@HukurouKk)です。 DMMのプラットフォーム(以下 PF)で提供している決済機能の開発、運用を担当しています。
決済スクラムチームでは、今までDMMを支えてきたレガシーシステムのリプレイスをプロジェクトの一つとして進めています。 その一環として、今回、決済フローの一部を、AWS CDKを利用し、サーバーレスアーキテクチャで構築しました。リリースから二ヶ月たったところで、AWS CDKを利用した理由や結果など以下に紹介したいと思います。
概要
DMMではポイントを購入するポイントチャージという機能があります。ポイントのチャージ方法として、クレジットカード・PayPalといった多くの支払い方法をユーザーに提供しています。
ポイントの支払い方法の中には、クレジットカードなどのように必要な情報を入力・送信して支払いが完了するものもあれば、コンビニ店頭支払いのようにユーザーがコンビニで支払い終えた時にポイントを付与されるものもあります。
コンビニ払いの場合は、ユーザーが料金を支払った後、決済代行会社からDMMに決済確定通知というリクエストを受け、ユーザーの決済完了を検知していて、通知を受けたあとは、DMM側でポイントの付与などの処理を行います。
そのリクエストを受ける基盤がレガシーな基盤そのものにあったため、そちらのリプレイスを行いました。
現状のプロダクトが持つ課題
こちらではリプレイス対象のシステムが抱えている課題を紹介します。
対障害のための機能が足りていない
システム障害によって決済確定通知の受信処理が失敗すると、「ユーザーに請求は届いてしまうが、ポイントは購入できていない」といったようにユーザーに不利益が出るような事象が発生しかねません。そのため、障害によって処理が中断したとしても、復旧を迅速にできることが必要でした。
また処理が中断することによって、開発者にとっても辛い作業が発生します。データの整合性の確認やユーザーへの影響の調査、原因調査、再発防止など、本来であれば別のことに使える時間において、復旧に付きっきりとなる状況はできる限り避ける必要があります。
モノリシックなアプリケーションのため改修しにくい
この確定通知を受ける機能はモノリシックなアプリケーションの機能の一つであり、改修にはかなり注意が必要でした。このアプリケーションでは利用しているライブラリやクラスが共通していることが多く、修正が思いがけず大きな影響を及ぼすことも少なからずあり、代行会社のリクエスト内容が変わる場合などには、改修に大きな工数がかかってしまう状態でした。
そのためマイクロサービス化が求められ、モノリシックからの脱却が必要でした。
ミドルウェアの管理が追いついていない
アプリケーションが動いている環境のミドルウェアの更新は、先述したようにアプリケーションの改修を行いにくい状態による影響を受けているため、更新作業となると大きく工数を取ってしまい、開発に影響を与えていました。
オンプレミスのサーバーを使う場合、ミドルウェアの更新作業は開発者自身でアップデートしていくことが必要不可欠になります。定期的にアップデートするように心がけていれば良いのですが、そもそもの管理自体をなくすことで負担の軽減はできないかを検討していました。また、アップデートが滞ると、脆弱性が高まるだけではなく、新しい機能が使えなくなることで、レガシープロダクトになりやすい環境を作ってしまうため、それを防ぐことも重要視されていました。
これらを解決すべく、リプレイスのための技術選定をはじめたわけですが、それについて次で紹介します。
利用したツールやアーキテクチャの説明
AWS CDK
概要
AWS CDKとは、まずAWSリソースの環境構築をテンプレートに基づいて行ってくれるClouFormationというサービスを利用する際に、そのテンプレートをプログラマブルに書くことができ、かつデプロイもそのままできるツールセットになります。2019/7/11 にGAされ、今も活発に開発が続いています。 CloudFormationでJSONやYAMLに書く内容がクラス化されており、プロパティに設定を流し込むだけでCloudFormationに変換してくれます。
使用可能言語はJavaScript・TypeScript・Python・Java・.NETとあり、決済スクラムチームではTypeScriptで開発しております。 理由としては、先述したサーバーレスアーキテクチャにて利用するAWS Lambdaというサービスと使用言語を統一したいという点と、静的型付けが利用できるものであるという点の二つを重視しての選定でした。
メリット
コードの総量が少なくて済む
一からCloudFormationを書いたのと比べての話になりますが、書く総量をかなり抑えることができます。AWS CDKのなかでクラスにデフォルト値が設定されており、権限周りの付与、冗長性のデフォルトサポートも含めて、かなりサポートしてくれているので助かります。 そのため、レビューにかかる時間なども軽減できるので開発もかなり楽になりそうな印象です。
アプリーケーションの開発のバックグラウンドのメンバーはCloudFormationよりも書きやすく感じる
主観ではありますが、YAMLやJSONでの環境構築はCloudFormationに慣れた人には使いやすいかもしれません。ただ弊社ではインフラチームは別チームに別れておりまして、AWSで構築する場合はチームで自ら構築することになりました。
そのような際にアプリケーションと同じようにプログラムで環境構築ができるのは、メリットに感じました。また、先述の言語についてもTypeScriptで統一することによって、インフラとアプリケーションの開発をより似せることができたのは恩恵が大きかったです。
AWS CDKが他のAWSツールキットの利用もサポートしてくれる。
今回はサーバーレスにすることになっていたので、他のツールキットであるSAMが比較対象になったのですが、AWS CDKにはSAMを利用するクラスが実装されており、AWS CDK内でSAMを利用可能です。 またこの実装を見て感じたこととして、AWS CDKが他のツールキットを吸収し、環境構築のツールキットとしてメインとなっていくように思えたため、SAMメインでの構築・デプロイをやめ、AWS CDKで構築・デプロイを行うようになりました。 なお結局のところ、今回のケースでは利用するメリットが見つからなかったのでSAMの導入はしていません。
Lambdaベースのサーバーレスアーキテクチャ
概要
サーバーレスアーキテクチャとは、Lambdaに代表されるFaaSなどのマネージドサービスを利用することで、EC2のような仮想インスタンスサーバーを使わずにアプリケーション開発を行う構成を指します。
このような構成にすることによって、従来自前でサーバーを準備する際に考慮しなければいけなかったことを省略できます。作業がなくなる分アプリケーションの開発だけに集中できるわけです。
ただ、サーバーレスにしたからこそ考えなければいけないこともあり、そこはトレードオフになるかと思います。 弊チームでは、記事の冒頭部分でもお話ししたとおり、サーバー運用面における、課題とサーバーレスアーキテクチャのメリットが運用面で合っていました。そのため、なるべく楽に運用していくために、サーバーレスを利用したアーキテクチャにしました。
メリット
今回は(サーバーレスのメリットには違わないのですが)、ほぼLambdaのメリットになってしまっています!
プロビジョニングなどが不要のため、インフラの拡張が容易
Lambdaの特性とも言えますが、サーバーを用意する必要がありません。ミドルウェアの準備やインスタンスの大きさなどを考慮する必要がなくなるため、他の事に時間を使うことができます。
またソースコードを乗せればすぐに利用できるLambdaでは、プロダクトの拡張に関しても容易に準備・検証できます。一方で、考えることとしてLambdaならではの部分があるので(タイムアウト時間やメモリの量、コールドスリープの考慮等)、そこは考慮が必要ですが、条件が合う設計にすれば、かなり作業を楽にできます。
スケーラビリティと可用性
Lambdaはリクエストの量に応じてスケールする機能があるので、開発者側でスケール管理をする必要はありません。また高い可用性をAWS側で保ってくれており、メンテナンスやダウンタイムなどもないため、グローバルで動くLambdaではAWSのクラウドに動かす容量さえあれば実行してくれます。このような機能は運用の際にとてもありがたいですね。
実際の利用例
実際のプロダクトはこのようになりました。クラウドはAWSを利用していて、全体的にLambdaを利用してサーバーレスアーキテクチャを実現しています。
図では省略していますが、冗長性を持たせるためにMultiAZになっています。こちらは先ほども述べましたが、AWS CDKがデフォルトで作成してくれます。
また途中で処理が中断しても処理を再実行できるようにするため、LambdaをリトライするようにSQSのキューイング、Step Functionsを利用したワークフロー管理によって実現しています。
Step Functionsは特に便利で、ワークフローをマネージドサービスで管理できます。Lambdaの再実行の有無などをハンドリングできるので、一時的なネットワークの不安定によるタイムアウトなどを受けても自動で再実行する仕組みを作っています。
最大2時間に一回、1週間リトライし続けることにして運用を続けています。こちらも通常はJSONやYAMLで設定を書かなければいけないのですが、AWS CDKではDSLがあり、そちらで簡潔に書けるのは便利でした。
注意点としては、ベンダーに依存してしまうベンダーロックインが発生してしまうことが挙げられます。ただ、どうしても落としたくない、復旧させたい処理などがある場合はこちらを利用するのをお勧めします。現在のPFの決済機能は他のPFの機能(会員基盤など)を利用することを前提にしたシステムがあるため、様々な影響を受けやすく、かつ決済機能となるとユーザーへの影響は大きくなります。それをStep Functionsを採用し、ポイント付与に関しては、できるだけ復旧することによって被害を抑えるようにしています。
また再実行させる際に注意すべきなのが、データの重複や変更しなくても良いデータの書き換えだと思いますが、それを防ぐために冪等性はアプリケーション全体で担保し、再実行しても不整合が起こらないようにしています。
モニタリング・監視について
サーバーレスの監視ということで色々チーム内でも調査、議論がいろいろとありましたが、現在はこのような形になっております。監視基盤もAWS CDKで構築しています。
基本的には各ログとメトリクスに関してはCloudWatch Logsに出力され、Kinesisを介して、LambdaでDatadogに送り、モニタリングしています。 ログとメトリクスにて異常値やエラーなどが発生した際もDatadog Alertが発火し、Slackに通知されるようになっています。
また今回はX-Rayも導入しています。
X-Rayは、分散アプリケーションの可視化、サービス間のリクエスト、レスポンスの監視ができるトレースできるサービスです。
レスポンスタイムや各コンポーネントの処理時間などについてもわかりやすいサービスマップを作成してくれるので、導入するだけでわるっとわかってしまうような代物です。 これによって、どこがボトルネックになって、パフォーマンスが低下しているかを分析できるため、原因調査の一助になると思い、導入しました。
実際、X-Rayのおかげでどのくらい処理に時間がかかるかがわかり、対応方針が決めやすくなった場面は多かったので、情報は取れるだけ取っておくべきだと感じています。
今後の課題
ここではリリースしてから二ヶ月立った時点での運用面での課題を紹介したいと思います。
実行失敗時のリトライフローがまだ完璧ではない
失敗をカバーできるようにリトライ処理などをだいぶ配置したのですが、運用したところ、それでもまだ完全ではありませんでした。API Gatewayの直後のLambdaの実行がS3にも入る前に落ちてしまうと、ログには出力されてはいますが、復旧しにくくなってしまいます。ネットワークが不安定だと発生する場合があるようです。 現状では件数は少ないため、決済代行会社のリトライ処理に頼るなどしてほぼ回避できているのですが、改善はしていきたい所存です。
CloudFormationの知識がないとAWS CDKを書くのは慣れが必要
CloudFormationを結局は吐き出し、アウトプットされたものを利用して構築するので、CloudFormationの知識が必要です。
また今までの構築ツールなどと比べると書き方はかなり違うため、書き始めるのに躊躇しがちな傾向が弊チームでは見られ、AWS CDKのタスクが振られてもなかなか混乱しがちな状況があります。
AWS CDKがGAされてから半年程度なので、ディレクトリ構成などのベストプラクティスがまだそれほど多くないため、開発者自身でどのような構成にしていくか考えていく必要もあります。
とりあえず調べてみたいという場合は、いったん練習でAPI Gateway + Lambdaみたいな構成を作ってみるのがおすすめすすめです。かなりコード量が少なくなるのを実感できますので、導入時のイメージが湧きやすいと思います。
まとめ
AWS CDKはAWSを利用することが多いのであれば、利用する価値のあるツールセットかと思います。状況次第ではだいぶコードの量を減らせますし、デプロイも任せることができるのでインフラ周りを1ツールで賄うことができます。
サーバーレスアーキテクチャに関しては、負荷がかかった時の挙動確認をしておきたいなど懸念事項が増える場合もあります。ですが、実際ちゃんと確認すべきことを実際にきちんとクリアし、運用してみると楽さを感じることができました。
また、さらに楽に運用していくために監視などをしっかりと用意すれば、後々の運用の助けになるとおもいます。X-Rayも分散アーキテクチャの可視化という点でかなり便利なので、使ってみてください。
それでは、充実したAWS CDK、サーバーレスライフを!