Monzo Tech Blog
2016
Mondo時代
開発者向けAPIのプロトタイプを公開したよ、という記事
フルスクラッチで24/7稼働する銀行システムをどう作ったか
Head of EngineeringのOliverがKubeConでも発表している https://www.youtube.com/watch?v=YkOY7DgXKyw
ベストなテクノロジーでベストな銀行を作る
常に接続可能である
数ヶ月でなく数時間単位での新機能のリリースが期待される
複数のマーケットで事業を行うならそれぞれのユニークな要求に答えなければならない
チームもばらばらにならなければならない
他チームと調整することなく開発やデプロイができる
最初は3人の開発者しかいなかった
実用的な方法を選んだ
ただし将来どうなっているかを常に考え、変化できるようにした
4つの重要なフォーカスすべき点を特定した
Cluster management
サーバ管理には効率的で自動化された方法が必要
フォールトトレラントでスケーラブルなシステムを作るなら、サーバの故障やユーザの要求に応じてサーバを足したり弾いたりできないといけない
クラスタスケジューラによる抽象化
リソース要求に応じてスケールアップ・ダウンを行う
理想的にはすべてのシステムがスケジューラ上で動く
ステートレスなアプリもステートフルなアプリも同様にデプロイしたい
サーバをkillしてもすぐにスケジューラが補填するようなresilienceを得た
コスト節約のメリットもあった
かつてはJenkinsでビルドタスクを実行してたが非効率でコストもかかっていた
今やKubernetesのもとでビルドジョブが走り、それは既存のインフラのうちの空いているリソースを用いる
Polyglot services
Goがマイクロサービスには適していて、Monzoでも支配的ではある 他の言語を必要に応じて使う
異なるスキルセットのエンジニアを採用する
Dockerのおかげで言語によらず簡単にパッケージ化してデプロイできるようになった
一般的には共有されるコードはライブラリとして抽象化することが推奨されるが、polyglot systemではそれはうまくいかない
新しい言語を導入するたびに別の言語のライブラリをコピーしていたらオーバーヘッドもでかいし管理不能になる
その代わりに、共有コードをサービスにカプセル化する
分散ロックを取得するために、サービスは素のRPCを介してetcdをフロントするロックサービスを呼び出すことができる すべてのサービスが「共有インフラ」(データベースやメッセージキューを含む)と通信することで、いちいちライブラリ化しなくてもRPC呼び出しだけでサービスが作れる RPCを一つの共通コンポーネントにすることで、コードの共有による結合の問題を回避しつつ、コードの再利用のメリットを得ることができます RPC transport
強固なRPCレイヤを持つことが、複数のデータセンターや大陸をまたいで存在するマイクロサービスシステムの命運を握る
コンポーネントの失敗に対応し、レイテンシを最小化し、ランタイムの挙動をわかりやすくする
多数の言語でサービスを書く上で重要なプロトコルはHTTPだった
どの言語も標準ライブラリでサポートしている
とはいえマイクロサービスで悩ましい点はある
単純なラウンドロビンではなく失敗とレイテンシを最小化できるホストを選ぶのが望ましい
すべてのリクエストのたびにコネクションをオープンするのはレイテンシにネガティブインパクトがあるので使い回したい
ルーティング
RPCシステムの実行時の挙動を変更できるのはとても協力
個別のサービスを特定のユーザにのみ機能させる
Finagleが最も優れたRPCシステムだった
JVM上で動くアプリを書かなくても恩恵を受けられた
各サービスは直接ではなくlinkerdと通信する
linkerdはロードバランシングもするし、自動リトライもする
おかげで各アプリはRPC用のライブラリを書かなくて良くなった
Asynchronous messaging
メッセージキューを使うことでバックエンドがperformant and resilientになる メッセージが絶対にロストしないことを保証する
Monzoカードのトランザクションを「承認」または「拒否」するために、数十ミリ秒以内に決済ネットワークに応答したい 加盟店データの更新、プッシュ通知の送信、ユーザーのフィード(タイムライン)への取引の挿入などは、非同期的に行われる
非同期性は決してスキップしてはいけない
自動的に回復できないエラーが起きた場合でも、問題を修正してプロセスを再開できなければならない
Highly availabel
メッセージの送り手は"fire-and-forget"できなければならない
ダウンストリームのconsumerの状態は気にしない
Scalable
サービスを止めたりハードウェアを更新することなくキャパシティを追加できなければならない
メッセージキューは他のサービス同様に水平スケールできなければならない Persistent
メッセージキューのノードが落ちても、consumerが失敗してもリトライ可能で、データはロストしてはいけない
Playback
過去のある時点からリプレイできると古いデータの処理が可能になり便利
Kafkaはこれらの要件を満たした
メッセージキューとしては一般的ではないが、ユースケースにはまった
最高のユーザー体験と効率的な内部のオペレーションのためにはデータが重要
ユーザーから連絡が来る前に直面してる課題に気付けるか
ローン審査で過去のクレジットスコアに頼らずより良い評価ができるか
leanなデータチームを持っている
Autonomy
障害物がなくアイデアに没頭できるときがフルにポテンシャルを発揮するとき
すべてのデータエンジニアはすべてのデータ(個人情報はマスクされている)にアクセスできる
Cutting-edge managed analytics infrastructure
分析用のフルマネージドなインフラ基盤を使うことでメンテナンスに時間を使わない
分析とミッションクリティカルな本番環境が分離されている
Automation
自動化し、社内の誰でもアクセス可能
2017
毎年イギリスでは1300万人の成人がメンタルヘルスの問題を抱える
Positive Friction
通常摩擦は良いものではないが良い効果を生み出すものもある
UKで1998年、Tylenolの錠剤パッケージを変更したところ、誤って摂取することによる自殺が43%減少した blister package: 瓶じゃなく一粒ずつ取り出すタイプのやつ
Monzoは古めかしい銀行と違って散らかってない感じなのでその滑らかさと、セーフティバリアをどのように両立させるのか
簡単なのは設定画面にオプションを追加してみること
深夜に購入した商品について翌朝通知する機能
双極性障害の人は深夜に不要な買い物をし、翌日以降に後悔する傾向がある 一部の取引はキャンセルが可能
介護者が取引を確認して承認する機能
家族とか信頼できる人が大きい出費を抑える
これらはまだ探索的な試み
事前に予測して経済活動を防止する機会もある
安定した給与振り込みが停止したことに気付き、ユーザーのフィードに通知を表示する
節約方法とか節約に有効な機能とかを、ユーザーを責めたりすることなく教える
Head of Financial Difficultiesがユーザーコミュニケーションを行い、Monzoは金融トラブルの窓口ではなくサポーターであることを理解してもらう
給与が途切れたことは必ずしも解雇やメンタルヘルスの決定的な証拠ではないが、失業状態は債務問題と結びついている
メンタルヘルスを抱える人の四分の一が負債問題を抱えている
コミュニケーション手段をユーザーに選んでもらう
チャット、メール、電話
希望時間帯
すべてのユーザーの100%の希望を叶える完璧なプロダクトは作れないが、人々が隙間から落ちていくのを見過ごすのは悪徳
ohbarye.icon コメント欄が荒れている
英国では毎年520億ポンドの費用をかけて金融犯罪対応をしている
2015年11月にプリペイド式デビットカードの販売を開始、これらのカードは10万枚以上発行
top up fraudの手口
犯罪者は、盗まれたカード情報をネットで購入しMonzoのカードを上乗せして、盗まれたカードから出ていくお金をお店で使ったり、ATMで現金を引き出す
その後、後に本物のカード所有者からチャージバックを受けることになるので、その分をポケットから出していることになる
ルールと機械学習ベースの詐欺検知システムを組み合わせて使用することで、過去6ヶ月間でトップアップ詐欺の発生率を大幅に減少
現在の不正の発生率は、金融サービス業界の平均よりも桁違いに低い
決済プロセスにおける追加のステップで、加盟店が有効にするかどうかを決めることができる
有効にすると、顧客はカードを発行した銀行にリダイレクトされ、さらなる認証を受けることができる
3Dセキュアを経由した取引は、カードを発行した銀行が独自の認証を行っているため、取得した加盟店に請求されることはない
その代わり、不正行為の責任は通常、発行銀行に移る
3Dセキュアの利点にもかかわらず、加盟店は、ユーザーエクスペリエンスが悪いために使用を嫌がることがある
Monzoカードに他のデビットカードからの資金が上乗せされている場合、Monzoはその取引を行う加盟店となるがすべてのユーザーが3Dセキュアを経由することを要求したくない
その代わり、当社の詐欺エンジンは、特定のトップアップがどれだけリスクが高いと考えられるかに基づいて判断し、トップアップのごく一部のみを3Dセキュアを経由して行う
当社の詐欺エンジンは現在、十分な精度を備えており、6月の高値が0.84%であったのに対し、毎月の財務上の損失はトップアップ量全体の0.01%未満となった
世界最高の銀行を作るためには、まっとうな顧客に影響を与えない方法で金融犯罪に対処する必要
細心の注意を払っている指標の1つは、誤って本物の顧客を追放してしまう偽陽性の数 2016年5月と6月には、3人の詐欺師に対して6人の真正なユーザーを禁止していましたが、現在は3人の詐欺師に対して1人の真正なユーザーしか禁止していない
1. Instantly freeze (or unfreeze) your card
2. Real-time response from customer service
3. It should help you save money!
4. Send money to friends with a single swipe
5. No charge on foreign payments.
プロセシングシステム内製はコストもかかるし複雑なのでやらなかった
顧客に直接メリットがない
考えを改め、12ヶ月かけて内製した
今後新たに口座を開設する場合はすべて内製されたシステムを経由することになる
ohbarye.icon 過去の口座は元々のプロセシングシステムで処理されるぽい
自分たちがコントロールする最新のテクノロジーの上で独自のプラットフォームを開発し続けることがMonzoの戦略
支払いが失敗する理由
支払いと返金の仕組み
なぜ支払いが失敗するのかを理解するには、支払いの仕組みを理解する必要がある
店頭で何かを購入するとき、または現金を引き出すときに、Monzoは加盟店から認証を要求される
承認するとお客様の口座にお金が入るので、他のことにお金を使うことができなくなる
アプリに表示される残高からこの金額を差し引くが、実際にはまだお金はアカウントから出ていかない
In-app balanceとactual balanceは異なる
加盟店が支払い回収するために戻ってくるには1週間ほどかかることもあるが、通常は48時間で完了する
これで実際の残高も減少する
Monzoアプリでpending transactionと表示されている場合、マーチャントはお金を囲い込んでいるがまだ回収されていない
pending transactionは回収するときに消える
加盟店はいずれかの方法で返金を行うことができる
authorization reversal
もし顧客が返金を求めたときに加盟店がまだお金を回収していない場合、単に承認を取り消すことができ、回収予定枠のお金を解放することができる
credit presentment
資金が回収されている場合は、顧客の口座に資金を戻すことで返金を行わなければならない
UIではどちらの返金方法も、フィードの項目に金額が緑色で表示され、その前に「+」が表示される
支払いが失敗する可能性があるのは「決済端末」「加盟店の銀行」「決済ネットワーク(Mastercard)」「Monzo」「加盟店の銀行に戻る途中」の5つの場所、決済チェーンのいずれか 決済端末 -> 加盟店の銀行
カードをスワイプしたり暗証番号を入力したりすると、簡単なチェック(正しい暗証番号を使用しているかどうかの確認など)を行い、支払いを承認するか拒否するかを決定する
支払いが承認されると加盟店の銀行へ
加盟店の銀行 -> カードネットワーク
支払いが承認されると、加盟店の銀行からカードネットワーク(当社ではMastercardを使用しています)に承認要求メッセージが送信される
カードネットワーク -> Monzo
カードネットワークは請求を拒否することができる
OKならMonzoに送信される
Monzo ->
Monzoも請求を拒否できる
承認する場合、Monzoが顧客の口座にお金を振り込み、加盟店の銀行へ戻すレスポンスで結果を知らせる
到達までに時間がかかりすぎると、タイムアウトエラーが発生し、端末がトランザクションを拒否する
残高が少ない
十分なお金が口座にない状態で何かを買おうとした場合、私たちはそれが私たちに届いたときに承認リクエストを拒否し、その後、決済端末(またはATM)はカードを拒否する
一つだけ例外がある
加盟店が認証リクエストを送信しない場合、私たちは取引を拒否する機会がない
TFLのような一部の加盟店では、Mastercardが課したルールに従う限り、意図的に送信しないことが認められている 他の加盟店でも、端末がインターネットに接続できない場合は、このようなことが起こる可能性がある
いずれにしても、加盟店は囲い込みを行わずにお金を集めるだけ
チップ&PIN取引を行う際、端末はカード所有者であることを証明するために暗証番号を入力するように要求する
ATMでは、入力された内容を暗号化して当社に送信し、当社のバックエンドシステムで確認する
店頭では、カードのチップに保存されている暗証番号と顧客が入力した内容を照合するだけ
支払いやATMでの引き出しの際には、カードのチップが日付、時間、取引額、ランダムな数字を組み合わせて、カードのチップにプログラムされた秘密鍵を使ってこのデータを暗号化する
暗号化されたデータは、Cryptogramとして知られていて、それぞれ異なるデータを使用して作成されるため一意
同じキーを使って同じデータを暗号化し、カードのCryptogramと比較する
一致した場合は、受信したリクエストが本物だと示されたのでリクエストを承認する
一致しない場合は、リクエストを拒否する
CVC1と呼ばれるCVCの最初のコードは、カードの裏面の磁気ストライプにエンコードされている 磁気ストライプを使って支払いをすると、トラックデータからCVCを確認し、有効でない場合は支払いを拒否します
オンラインでお支払いをするとき、ほとんどのウェブサイトでは、カードの背面にあるCVC2として知られている3桁のCVCを入力するように求められる 間違っていれば支払いを拒否する
磁気ストライプ無効化
カードの裏面の磁気ストライプには、表側の長い番号(「プライマリアカウント番号」)やカード認証コード(CVC)など、カードに関する情報が含まれている
この情報は暗号化されていないため、詐欺師は正規のATMや決済端末に取り付けられた「スキマー」を使って簡単に盗むことができ、白紙のカードの磁気ストライプに印刷して偽造することができる
そのため、通常は磁気ストライプによる引き出しを断っている
イギリスでは、加盟店がより新しくより安全なチップ&PIN技術を使用しているため、これは英国での支払いには影響しない アメリカやインドなど一部の国では、磁気ストライプ技術がまだ広く使用されている これらの場所のいずれかに旅行している場合は、アプリを使ってカードの磁気ストライプを一度に24時間有効にすることができる
ohbarye.icon 雑なタイトル
2015年9月から4回ハッカソンを行い、Slackチャンネルには2000人以上が参加しており、APIと統合している個人プロジェクトは100近くにのぼる 今年は19万人以上の顧客に機能提供することに重点を置くのでpublic pAPI作業に多くの時間を割くことができない
既存のAPIの上に開発者が公開アプリケーションを構築することをまだ許可していない理由
APIの下位互換性のない変更を行う予定がある
最初のプロトタイプは、当座預金のためにうまく機能しない漏れのある抽象化だらけ
私たちがサポートする余裕のない製品に他の企業に頼ってほしくない
APIの初期段階では、他のスタートアップ企業が投資家向けの説明会で「Monzoとの統合」を盛り込んでいたが、全員にとってストレスになった 私たちのAPIをまだシステムの重要なコンポーネントとして扱いたくなかった
PSD2は来年に迫っており、銀行のAPIがどのように使われるかが大きく変わる可能性がある 誰かがMonzoのAPIで素晴らしいものを作っても、それが規制に準拠していないという理由でシャットダウンされてしまうことは避けたい
ohbarye.icon 正直
2018
この時点で開発者50人
人数が増えたのでfeature teamになった
2週間ごとにリリースする
リリース前には数日間コードフリーズする
iOSとAndroidを交互にリリースしている
フィードバックを得てからもう一方に出したり
同時に機能提供して話題作りをしたり
Monzo間の支払いについて
こんな感じのリクエストが飛ぶ
code:json
POST /p2p-payments/create_transfer
{
"from": "user_x",
"to": "user_y",
"amount": 500,
"description": "Lunch 🍣"
}
銀行ライセンス前に提携していた事業者が2つ
payment processor
ユーザーの残高を記録し、カードネットワークに接続する
issuing bank
ユーザーのお金を保管する
Monzoのプリペイドカードのユーザーが支払いを行ったり受け取ったりすると、payment processor会社が残高を更新し、issuing bankへの送金や発行銀行からの送金を行う
例えば、ある人がプリペイドカードでお金を受け取ったとき、私たちはその人の口座の残高をpayment processorで増やすが、実際のお金はissuing bankiに送られて保存されていた
プリペイドカードからプリペイドカードへの送金
payment processorに送金元から引き落とし、送金先へ入金のリクエストを送る
正味の影響はないのでissuing bankに対して何かする必要はない
2017年10月に当座預金(内製のpayment processorであり、第三者のissuing bankは存在しない)を開始してからの送金は工夫が必要 前述の通り
当座預金→当座預金
Monzo内の台帳を更新すれば良い
当座預金→プリペイド
プリペイド→当座預金
最も複雑
今ではすべて当座預金にしてプリペイドは廃止したので当座預金どうし以外の送金に関するコードは消せる
移行期間中の暫定処置ではあったがユーザー体験のためには必要な複雑性だった
ohbarye.icon 日本と違って当座預金がメジャーなのか 1週間の間に、108のマイクロサービス、2つの社内ウェブツール、6つのソフトウェアライブラリを対象に、183のプルリクエストを行いました。11人のエンジニアがコードを貢献し、さらに27人のエンジニアがコードレビューに従事し、382件のレビューを行いました。合計で、26,948行のコードが追加され、116,835行が削除されました
90%のマイクロサービスは見ればわかる
バックエンドエンジニア全員が、元の作成者に相談することなく、自信を持って大部分のサービスにバグのない変更を加えることができる
10%は癖があり、経験豊富なエンジニアであっても扱いづらい
古いマイクロサービスフレームワークの削除
87 のサービス (700 以上のうち) が、新しいサービスの標準である typhon の代わりに、私たちの古いマイクロサービスフレームワーク mercury をまだ使っていた
これらのサービスは私たちのプラットフォームの残りの部分と完全に互換性がありますが、この互換性を管理するためのコードが必要で、このコードが過去に問題を引き起こしてた
これらのサービスはまた、異なる方法で構造化されており、エンジニアが書き慣れていないより多くの「定型的な」コードを必要とすることが多く、間違いを犯す可能性が高いことを意味する
セキュリティメカニズムのアップグレード
34 のサービスでは、旧来の認証メカニズム (誰が何をすることを許可されているかを内部的にも外部的にも決定するために使用するコード) がまだ使用されていた
安全ではあったが、私たちの新しいライブラリでは、より詳細な権限が与えられ、開発者にとってより良い体験を提供している
2019
実は2016, 2017にもやったことがあった
既存のMonzoアプリを通じて投資を実行できるよう数ヶ月かけて実行した
大きな課題は4つ
増大するトラフィック対応
最も極端なシナリオを想定して、最短5分で最大10万件の投資を行い、最初の1分ほどで1秒間に1,000件の投資が急増することを想定して準備
通常の日には、1秒間に10~20人がMonzoのアプリを開いている
試算では、1秒間に300人以上、つまり平均的な負荷の15~30倍を準備する必要がある
クラウドファンディングの処理のために誰かの支払いをブロックしてはいけない
すべてをリアルタイムに処理するのではなく2層で対応
潜在的な投資家に投資が実行可能か知らせるpre-investment層
非同期に資金を移動させるfinal investment layer
2000万ポンドを上限とする
資金調達ラウンドをリードする機関投資家と合意した総額2,000万ポンドを超える投資を受け入れることはできなかった
上限を超えないようにリアルタイムに集計するシステムを組む必要があった
Goのatmic packageを使うcrowdfunding-totalサービスを作り、インメモリでインクリメント 毎秒集計結果をetcdに吐き出す
プロセスが再起動しても問題ないよう定期的にディスクにフラッシュする
ユーザーは投資のための資金を用意しないといけない
銀行機能がダウンしないようにする
cacheと二層レイヤーの工夫によりサーバがダウンしない自信
まれにレースコンディションの問題で、投資成功したと思ったが失敗するケースがあったが銀行がダウンするより遥かにまし
既存の製品ではなく自前でテスト用のクライアントを構築した
iOS, Androidアプリと近いリクエストを飛ばすため
Charles Proxyでリクエストを観察した
クライアントからは最大4並列でリクエストが飛ぶのでそれも再現
一連のクライアントの操作をジョブと定義し、リクエストを再現
クライアントに相当するものはKubernetes上に1サービスとしてデプロイされた
名前はオフィスに居る犬のBingo
2017年に当座預金を開始したとき、私たちは独自のFPSプロセッサーを構築したが、3rd partyによって構築・運営されている既製品ゲートウェイを使用することを選択した
FPS障害にも関連
新たなインフラの構築
データセンターとハブを物理的に接続し、FPSの(そして当社の)セキュリティ要件を満たすようにする
外部テスト(FPSを使用)
正しい方法で支払いメッセージを送信し、応答できるかどうかを確認し、異なる事態が発生した場合にゲートウェイがそれを処理できるかどうかを確認する
内部テスト
新しいゲートウェイが次の5年間(およびそれ以降)の支払い量を処理できることを確認するための「負荷テスト」を含む
私たちは10月の初めにFaster Paymentsの観点からの「認定」に合格し、その後、残りの時間をゲートウェイの移行ステップの練習と独自のより具体的な障害テストに費やした
独自のMastercardプロセッサー、FPSプロセシングシステムにより、顧客の2つの主要な支払い方法はMonzo下にある
メリット
FPSを通る取引を完全に可視化できるようになった
Monzoは2つのデータセンターを同時に稼働させており、「アクティブ・アクティブ」と呼ばれるセットアップを行っています。これは、1つのサイトが何らかの理由でダウンしても、ファスターペイメントに接続されており、支払いの送受信が可能であることを意味する
必要に応じて、rolling updateが可能
2020
既製品のゲートウェイではMonzoのトランザクションをさばけなくなってきたため移行を決断
この移行はいつものMonzoの業務とは異なる点があった
自前のデータセンターを構築
AWS内で動くシステムと接続できなくても稼働するようなstand-in機能を構築 データセンター内で動くアプリケーションはモノリスにした 2021
2018年に作ったキャリアフレームワーク "progression framework" (エンジニアの等級制度) を更新した エンジニアやマネジャーにとって辛いもので40%のエンジニアが役に立たないと言っていた
ハイパフォーマーのエンジニア像ではなくただのチェックリストになっていた
5つの問題点
too specific 細かすぎ
too many things 項目が多すぎ
platform/infrastructure roleとproduct teamの違いを意識してない
framingとexpectationの設定がない。現在地を示すGPSにはなったが方向性を示すコンパスではなかった
成長につれてロールが持つスコープが広がることを考慮してなかった
変更点
会社の成功への貢献、インパクトをベースにした
個人の成長につれて大きくなるスコープ
大きいインパクトを出すには広いスキルとふるまいが必要になる
インパクトだけでなく、how(どうやってインパクトをだすか)も重視した
マネジャーはバラバラの個人ではなく、チームにつく
技術的な取り組みと機能開発の優先度をつける
隣接するプロジェクトと協力する
“The goal of the engineering manager is to create an autonomous, high performing team - to foster an environment where decisions are delegated and can be made and communicated effectively. It is not the role of the manager to make these decisions, but to ensure they are made.”
ソフトウェアのクオリティを測定する試み
1,800のmicroservicesに対し、継続的かつ自動的に計測され、各サービスオーナーに提示される
クオリティに責任を持つのはサービスオーナーのため
ドキュメントの品質、テストの品質、可観測性など、関連するさまざまなカテゴリのグレードで計算
過剰適応を防ぐため、結果は点数ではなくラベル(Needs improvement, Good etc.)