メルペイの様々な決済手段でどのように決済の整合性を保とうとしているかは15日目の記事で紹介しました。Service)を分けています。今回はこのお客さまの残高を正しく管理するためのマイクロサービスがいかにして正確に増減をしているかを説明します。お客さまの残高を増減させるという機能を提供しています。Serviceで処理を行っています。Serviceでは「1つの取引において残高を増減させる」という機能に集中しています。お客さまの残高にはメルペイ残高、売上金から購入されたり先日のゴールデンウィークに行われたポイント還元で付与されたポイントなどいくつかの種類があります。これらを一つの取引毎に増減させる必要があります。実装の方法にはいくつか考えられますが、以下のように残高の種類ごとに追加、消費などのメソッドを実装する方法が一番シンプルです。この方法で実装すると以下のようなメリットがあります。どの残高でも似たような処理を行うので、共通化がしやすくなるそれぞれの残高の処理が独立なので、残高の種類の追加や削除が他に影響を与えないですがこの方法にはメルペイでは採用できなかったデメリットもあります。それぞれの残高の処理が別々なので一つの取引で複数の種類で決済する場合に複雑になるメルペイでは決済時にポイントとメルペイ残高を合わせて支払うことができます。そのようなケースでは「ポイントの支払は成功したが、残高の支払いは失敗した」という状況が起こりえます。この場合に決済がなかった状態に戻すには正常に終了したポイントの消費を取り消す処理をしなければいけません。以下のような状況を考慮する必要があります。Serviceでは別の方法を採用しています。採用している方法は追加、消費、失効という大きな機能を提供します。その中のパラメータとしてそれぞれの種類で金額がいくらという指定をします。この方法では以下のようなメリットがあります。最初の方法で問題になった複数の残高で決済する場合に、全てを1つのDBトランザクションの中で処理することができるそのためどこかで失敗した場合にはDBのロールバック処理で全てを安全に元の状態に戻すことができるただこの方法でもデメリットはあって以下のことで最近は苦しんでいます。消費について消費は残高を減らす前に実際に減らすことが可能か確認する必要があります。買い物をする前に財布の中身を確認する様な感じです。実際に支払える金額があれば、その金額を仮押さえという形で状態を変えます。その後別のリクエストとして実際に消費するリクエストを受けてお客さまの残高を減らします。冪等性の担保15日目の記事でも説明されていたように、決済のステートマシンはフェーズ毎に複数回リトライをすることを前提に作られています。Serviceも1度の取引に対して複数回リクエストを受けることを想定した作りにする必要があります。Serviceとしては何回も同じ操作を繰り返し、多重付与や多重決済の原因になります。それを避けるためにリクエストごとではなく取引毎に異なるIDを付与してもらう必要があります。そのIDが既に処理済みの取引IDであれば、実際に処理しなくても、あたかも処理したかのように結果だけを返せばよい仕組みです。冪等性キーはその名の通りリクエストにおける冪等性を担保するためのIDです。同じ冪等性キー、同じリクエストパラメーターならば同じリクエストだと認識できます。処理は最初に成功したときだけ行われ、結果はDBに保存されます。それ以降は実際に処理をせずに同じ結果だけを返すようにしています。逆に同じパラメーターを持ったリクエストが来ても異なる冪等性キーを持つ場合、別々の取引として扱います。Serviceを利用する他のマイクロサービスは安心してリトライすることができるようになります。Keyによってリクエストの冪等性は担保されるようになりました。Serviceではデータ整合性や、お問い合わせ調査、他のマイクロサービスとのデータ突合処理のために適切に処理の履歴を保存する必要があります。Serviceがお客さまの残高をどのような仕組みで変更し、記録しているかをお話します。Serviceでの残高の操作は全て3種類に抽象化されると説明しました。これらの操作が行われる毎に、異なる2種類の履歴にレコードを追加することで、お客さまの残高の移動が正しく行われたかを確認することができるようにしています。この履歴を利用して、経理グループと正しく決済できているか確認しています。金額が変動したあと、お客さまがいくら持っているかを記録する方法それぞれについて説明していきます。操作の種類と金額の絶対値を保存する方法それぞれの種類の残高が変動するたびに、お客さまのIDや取引の種類や取引額、取引のIDなどと保存しています。お客さまの今の所持金額を知るためには、これの履歴を全て足し合わせれば正確に値を出すことができるはずです。図にすると以下のようになります。この方法ですと、差分の積み上げを計算するだけなので、任意の期間にいくら決済されたかも簡単に知ることができます。金額が変動したあと、お客さまがいくら持っているかを記録する方法それぞれの種類の残高が変動するたびに、取引のIDなどと共に今お客さまがどれくらいの残高を持っているかのスナップショットを保存しています。それと同時に直前のスナップショットのIDも保存しています。することで最新から順々にたどることで途中でおかしな履歴がないか、履歴間の差分が正しいかを確認することができます。最後にお客さまの残高を正しく管理することはメルペイに限らず全てのサービスにおいて最重要の課題であると言えます。メルペイでは冪等性によってリクエストの同一性やリトライへの対応を担保し、2種類の履歴を保存することで、なにか異常があった場合にどの取引が異常を引き起こしたのか、どの時点から影響を受けているのかをすばやく発見できるようにしていることを説明しました。この世に完璧な仕組みはありませんが、これからも安心安全にメルペイを使っていただけるようにできる限りの方法でお客さまの残高を管理していければと思います。