Friday, March 9, 2018

Payment - System Design



如何設計一個 payment processor
今天幫我高中同學 mock 某家獨角 onsite 常出的這道 system design 題,他一時想不出來,就跟我說他不會。還好我去年十月去 AWS Summit 聽過一些 startup talks,他們在台上分享了他們用 AWS 解決問題的方法,使我受益匪淺。其中一家多倫多的 payment startup Pungle 就發表了他們用 AWS 解決 scalable, robust and secure real-time payment processing 的經驗,我就給他講了一遍,非常值得參考: https://youtu.be/_2i_-z-IiOk

給他 mock 過一遍之後,我才突然想到原來也可以藉由看 Amazon 上傳到 YouTube 的 real-world case studies 來學 system design。以下分享多倫多的 startup talks: https://www.youtube.com/playlist ... reG2Y6-8R0u7cN5lH63

2019-04-08 晚上補充:我覺得以 payment 來說,無論是個人對個人,個人對公司,或公司對公司都需要解決:
1. scalability (突然有大量的 requests 來時都可以即時處理)
2. reliability (盡量接近 100% availability + 失敗之後能後 retry)
3. timeliness (支付是有時間性的,最好能按照時間順序處理,這樣越早收到的交易可以越早完成)
4. no double spend (要是帳戶裡每一塊錢只能花一次)

樓主我是個新碼農,離開大學才工作了一年半,所以系統設計還沒弄太熟。想趁這個機會,總結一下我在公司裡(不是 payment 公司)在 AWS Summit 看到很多新創常見的 high level 解決方案:
1. 用 load balancer + auto-scale instances 來處理 surge in traffic。同時跑好幾個 instances 不僅可以增加 availability,當一個有 outage 其他 instances 可以幫忙頂替
2. 用一個 queue (e.g. AWS SQS) 來存放 failed jobs,instances 會從 queue 裡取出 failed jobs 再試一次。要是失敗太多次了可能就要放到另一個 queue (e.g. AWS DLQ) 然後丟 alerts 叫 ops 或工程師來看發生什麼事,手動處理,或是改 code 以後就不需要手動處理了
3. time sequencing 很重要,所以每個 job 可以放到 queue 或 event stream 裡 (e.g. SQS, AWS Kinesis or Kafka),來個 producer-consumer pattern (producer 放 jobs 到 stream 裡,consumer 取出工作來做)
4. balance check + cache 正在處理的交易或把交易細節存在 database 裡,每看到一筆新交易都要檢查有沒有正在處理或已經處理完的同一筆交易
最後又回到 1. 最後如果需要 scale 更大,可以有 mutiple load balancers,multiple producer workers (instances),multiple streams,multiple consumer workers (instances) 哈哈哈

要是地裡大神們剛好路過,希望能留下你們的看法和想法。我也好好奇 stripe,square,paypal,微信那些巨無霸公司是怎麼解決這個問題的,知道的朋友們希望你們能無私分享!謝謝!

lz知道stripe,square这样的公司,所以应该知道面试30分钟是不可能设计和描述一个完整的payment process系统的。这么一个系统,没有几百个功能,也有几十个。

系统设计的第一步,是和面试官商量,确定一个或两个或三个(不是四个或五个)功能,搞清要求,然后开始设计如何实现这些功能。功能性需求Functional requirements第一,功能设计Functional design第二,伪/实代码code and DB schema第三。这三个都完成了,才会触及到非功能性需求Non-functional requirements,诸如可靠性Reliability,可伸缩性Scalability,throughput, latency,availability(要几个9),等等。

AWS 的customer architecture showcase 视频,主要是展现非功能需求在ASW上的实现方式,可以开拓视角但不能照搬。对工作没几年的申请人,面试是注重功能性需求的。回答系统设计问题的一个大忌就是上来就画一个load balancer,或者一个AWS的新服务功能

常出的這道 system design 題的题目大概是什么样子的。是类似微信付款的系统吗?

另外不知道商业支付的量和个人支付的量之间差距是几个量级?
商业本身的数目会比个人小。
商业的需求好像种类也很多。不少于逛商城的个人。
商业的支付有一定的平稳性。个人逢五一十一元旦春节的支付会呈现很强的spikes

我也不曉得商業和個人支付的 scale 差多少耶,非常好奇。

這種題目大概是說像 stripe 那種提供商家可以直接在網上接受信用卡或銀行帳戶支付的 API 和 backend 喔,不過其實設計微信支付也是個很好的系統設計問題。

payment其实是个频次相当低的服务。就算一天有1亿笔交易,一秒钟也才1000多个请求。也就是比一台数据库的连接上限多一点。如果是初步的设计,首先应该考虑怎样保证transaction的consistency以及错误恢复的措施。然后才是考虑规模化。

payment作为交易中间人是肯定的。但是是否也承担着银行的角色呢?一个transaction是由银行1,银行2,和WePay三方来参与吗?

假设一下场景。A从B那里买油条。微信先从A银行那里支出x元,然后放入B的银行,再通知双方支付完成吗?

银行在交易中承担什么承诺
查了查:微信支付在2018年的日均总支付交易量超过10亿次

10 0000 0000次
86400秒
11500次/秒

假设银行的API为:
boolean withdraw(account_no, to_bank_routing, to_bank_account, amount)
boolean deposit(from_bank_routing, from_bank_account, account_no, amount)

每个transaction是个two phase commit
[Bash shell] 纯文本查看 复制代码
?
withdraw from buyer account to WeChat account
if failed, abort
// withdraw succeeded, amount is in WeChat account
deposit to seller account
if succeeded, return success
// deposit failed
deposite back to buyer account
return transaction failed.
美国公司很少有这个体量的支付需求,面试的时候还是要避免给自己挖坑。面试应该尽量从单机可以处理的数据量开始设计,然后再扩展。不过即使是10k的qps,也不算一个很高频的服务,最大的瓶颈应该是数据库的连接上限,这时候要考虑数据库sharding和读写分离。简单地用用户名sharding,将用户平均分布在不同的数据库里应该就可以了。反正只要知道sharding的策略总是能找回用户订单的

你说的很有道理。有个地方需要往细里走一走。数据库里存什么,是transaction的信息和一系列的状态。
因为wepay不应该是银行。就是一个中间商。而且这银行是多家的。比如A的是连着建行而B是人行。
所以我们的数据库里每个transaction的状态要经历这样一个过程:

initialized   表示我方已经收到A要买B的东西的请求 下一站:要么withdrawn,要么failed

withdrawn     表示钱已经由A的银行账户进入我方(wechat)的银行账号。
              下一站:要么depositfailed要么succeeded

depositfailed 表示钱从我方(wechat)的银行账号没能进入B的账号。
              下一站:要么depositfailed,这时钱从A那里已经进入我方(wechat)
               的银行账号需要继续retry把钱放入B的账号。要么succeeded,要么failed

succeeded     表示A的钱已经进入B的账号。交易成功。通知用户A和B

failed        A的钱没有进入B的账号。交易失败。通知用户A和B

银行的结算服务应该是异步的。银行的服务器应该只做一件事,就是把帐记下来,然后再通过异步服务来结算。毕竟对银行来说,不出错才是最重要的。
user profile这种东西还是要放在dynamo这样的key value store里面吧
可以用,但是我认为没有什么特别的好处。用关系型数据库也可以。而且Dynamo是个eventually consistent的系统,一不小心又是给自己挖坑。。。

银行的结算不应该是异步的。而必须是同步的。想象一下A账号没钱,可是B把油条给了他。

另外interview里可能不想,但是生产中,对于交易量的spikes不能轻视。微信支付2018年10亿次,虽然平均11500次/秒,但是早上,中午,下午和晚上应该是高发期。

我确实想多了,读写的并发要求都不高,没必要上key value store

我们把payment processor这个东西抛开不谈。你如果试过在银行转款,钱也不是马上到对方的账户的,它是有一个时间差的,尤其是跨行操作。但是你的账是不会乱的。所以我认为银行的结算是异步的。异步的原因可能是因为结算涉及大量的锁操作,还涉及到不同银行间的通信,同步的话性能会很差。所以是采取先记账后结算的方法。A的银行系统只要记住A要把钱交出去,至于B的银行晚一点知道B要收钱也是没有影响的。如果中间多了payment processor,好处就是如果双方都是payment的用户,那他们就能知道这笔交易的发生。
还有一个问题就是,虽然payment processor的访问量很高,但是银行不止一家,所以银行的服务器访问量是远低于payment的,很难跟着payment一起讨论。最起码不能把payment的访问量等同于银行服务器的访问量

現在的銀行結算還不是同步的,所以才有 NSF, pending/withholding funds, 跟 actual balance 這些東西 哈哈哈

我們公司 back office 每天 end of day 都會 sftp 傳 bank file (fixed length file) 給幫我們處理 all EFT transfers 的銀行,裡頭每一行記錄著每一筆 fund transfer,然後有不同客戶不同銀行的 institution number, transit number, account number, amount 等等的資料。要是我們從客戶銀行裡扣錢,但是錢扣不成,他的銀行就會 charge NSF fee,我們這邊也會 mark fund transfer as rejected


我说的同步就是指的是A的银行要同意A的油条钱要被划走。帐不必立刻结(这些细节很有意思,但是不影响)wepay方必须得到A银行的同意或者拒绝的回复。很容易想象得到,A银行会立刻在他们内部的系统里更新A剩余的balance。即:(A原来的balance-油条钱)available for further withdrawal的。

我同意银行分散后的每个单个银行的压力会较小。但是所谓的交易量的spikes是我方(wechat方)需要第一波承受的。既然我们在讨论wechat的支付系统,银行是外部的,那么就必然要考虑(我明白你的point,随着面试官的指点再深入)wechat本身要承受的压力

NSF 是 non sufficient funds 喔!通常是轉帳或是開支票戶口不夠錢的時候被銀行罰的 NSF fee 就是這個

https://stripe.com/blog/auth-capture
There are some caveats: occasionally, a bank will show an authorization as an actual charge. As such, using this in cases where the customer doesn’t expect to be charged can be confusing. It’s worth thinking carefully about your use-case. (We’re of course happy to help.)

We don’t charge any fees on uncaptured charges, and fees after you capture are the same as any other charge.
https://securionpay.com/blog/credit-card-capture-definition/
  1. The credit card authorization — This is when the transaction is verified by the credit card company. They check the customer’s credit card validity and whether they have sufficient funds for the transaction. When everything’s fine, the transaction is then authorized and the total amount of transaction is deducted and held from the customer’s credit line account. Note that the money is not transferred to the merchant account yet. This is when credit card capture comes in.
  2. Credit card capture — This is when a merchant “tells” the credit card company that transaction has been completed between them and the customer. Now, money can be transferred.












http://www.softwareprojects.com/resources/conversion-traffic-to-cash/t-processing-payments-authorize-vs-capture-vs-settle-2030.html
Void (VOID):

Similar to refund, with the only difference that you are refunding a transaction that took place today (it didn't Settle yet).

When voiding a transaction, you can only void the full amount of the order. 

If you need to credit back a portion of the order, wait a day until the payment settles, then issue a refund.
https://support.cybersource.com/cybskb/index?page=content&id=C35&actp=RSS

Authorization

You request an authorization when a customer makes a purchase. An authorization, provided by the customer’s card issuing bank, confirms the cardholder’s ability to pay, ensuring that the customer's credit card account is in good standing with sufficient funds to complete the purchase.

Capture

After providing a service/product to the customer, you ‘capture’ the relevant information from the authorization and submit it in a capture/settlement request that your processor uses to initiate a funds transfer between the customer's credit card account and your checking account.

Sale

A sale combines the authorization and capture process in one transaction. Credit card associations require that you submit a sale transaction request only when you fulfill an order immediately. For example, when selling an item over the counter in a retail store. Transactions that include physical shipments are not fulfilled until shipment, usually sometime after the customer ‘purchases’ the product, and so would not qualify as a sales transaction.
https://www.infoq.com/presentations/stripe-api-pci
https://www.slideshare.net/InfoQ/the-architecture-that-helps-stripe-move-faster


https://www.infoq.com/presentations/Square

https://www.quora.com/What-is-the-technology-stack-behind-Square
There's a lot more Java and Golang and a lot less Postgres and JRuby/REE. Luckily, Square's been open sourcing a lot of projects, which can give you a much more accurate view of the technologies used to build the service


https://www.infoq.com/presentations/Square

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts