我相信在很多系統上,很多效能瓶頸會在 database ,尤其是一些帳戶系統,如果無法解決扣款時 ACID 的相關議題,那壓力其實最終都會壓在 database 的單點上,在敝公司設計這相關系統時,我使用了另一個方式來做設計。當然下面介紹的東西,要用其他語言實現也不是不行,不過敝公司是選擇使用 golang 實現就是了。

首先我們先看下面的圖,這是一張我個人覺得蠻標準的一個扣款系統大致上的架構

debit-system-normal

就如上面所講的,當大量 request 進來時,紅色區塊(wallet)的地方,會造 loading 最重的地方,而且如果當 database latency 開始拉高時,會開始出現雪崩效應,連帶的連前面的 application 、 load balance,都會因為 database 而開始出現堆連線的情況。在這種情況下,整個系統全部 crash 都有可能。

接下來我們試著想想,如何不讓 database latency,而且可以讓 application 可以很快的處理完連線,並且釋放掉它,避免堆連線的情況,所以我導入了 Message Quene,來幫助我達成這件事情,我們先看看架構圖

debit-system-finish

關於 Message Quene 我列了下面優點

  • 解偶 (A服務不用認識服務 etc…)
  • 靈活性 (B服務需要知道服務的一些資訊,不需要A服務另外開接口)
  • 擴展性 (可以做到類似gearman 派工分散處理)
  • 緩衝 (一瞬間大量耗資源處理的需求進來,可以buffer住)
  • 異步處理 (大量耗資源處理需求進來,不會讓請求端卡住)

由上面可以看到,透過 Message Quene 的協助,並且用出 producer、consumer 來協助減壓 wallet,在這個設計的理念上 user 其實並沒有馬上收到扣款成功的 response ,而是透過其他機制來做通知,user 當下只會收到扣款『預約』,並不代表完成扣款,當然這個機制,就看商業上的需求,也許可以用 websocket 即時同知,或是請 user 去其它頁面來做查詢。

敝公司在 Message Quene 的選擇上,是選擇 nsq,為什麼選擇它呢?

  1. golang 撰寫
  2. 非常容易 scalable
  3. 架設非常容易

當然 Message Quene 在市面也有非常多的選擇,這邊稍微列一下我所知道的

  • RabbitMQ
  • NSQ
  • Kafka
  • Redis

運用 Message Quene 可以就可以非常容易使用事件驅動(event trigger),在運用上非常的彈性,我非常推薦在系統的架構設計上,加入這個元素,可以讓整個系統更富有彈性。