如何設計一個電商平臺積分兌換系統?

  目錄

  1.拉開差距的一類面試題

  2.業務需求描述

  3.對業務流程的思考

  4.物流配送進度查詢,考慮到了嗎?

  5.事務的保證

  6.消息中間件的引入

  7.重試機制的引入

  8.引入冪等性機制

  9.對這類面試題的總結

  1、拉開差距的一類面試題

  現在面試經常會遇到一類問題,面試官讓你現場設計出某個業務場景下的一個系統,這個系統往往在業務或者技術上有一定難度,主要考察的是你多年積澱下來的系統設計的能力以及技術思維的能力。

  類似的這類系統設計題目很多,比如:

  請你設計一個秒殺系統

  請你設計一個支撐百萬用戶的IM消息系統

  請你設計一個微信紅包系統

  請你設計一個電商平臺積分兌換系統

  這些題目本身都是開放式命題,沒有固定答案。遇到這種問題,一定不要慌,關鍵是在現場要思路清楚,有理有據,慢慢分析。

  本文就其中一個問題:設計一個電商平臺的積分兌換系統,來詳細闡述一下。文中會詳細指出在系統設計的時候要考慮哪些要點,給大家展示出來這類問題思考的一個過程。

  2、業務需求的描述

  假設面試官現在給出來對於這個電商平臺的積分兌換系統的相關需求如下:

  用戶在電商平臺裏平時通過購買商品、曬單評論可以有不斷的積累積分

  積累到足夠的積分後,就可以在電商平臺的積分兌換頁面中,選擇使用自己的積分來兌換一些禮品

  需求其實就這麼簡單,那麼面試官說了,針對這個業務場景給出你對這個機制實現的思考過程以及這裏要注意的一些地方。

  3、對業務流程的思考

  如何思考?首先,用戶不停的購買商品以及曬單評論,會不斷的獲取積分,那麼是不是需要一張積分表,專門用來存儲每個用戶的積分呢?

  沒錯,這個表是一定需要的,可以現場給出下述的表結構。

  積分表:

  id(自增id主鍵)

  user_id(用戶id)

  credit(積分)

  繼續來看,假設在積分兌換頁面,用戶選擇用自己的20000積分兌換一瓶洗髮水,後臺的邏輯應該如何設計呢?

  這個也是必須得現場給出一個思考過程的,這個其實看起來簡單,但是很多年紀較輕,經驗不足的朋友,可能沒法快速思考出來。

  首先你要用20000積分去進行兌換,那麼一定是必須要在積分表裏扣減掉這20000積分的吧?所以在流程設計中,首先就得有一個20000積分扣減的過程。

  其次,你用這20000積分兌換了什麼東西呢?

  所以你是不是還需要一張單獨的表,叫做積分兌換記錄表,記錄下來你這個用戶本次用多少積分兌換了一件什麼商品?

  這個積分兌換記錄表的結構如下所示,你是不是需要在下面的那個表裏插入一條記錄,說這個用戶本次用多少積分兌換了哪個商品?

  積分兌換表:

  id(自增id主鍵)

  user_id(用戶id)

  exchanged_credit(用於兌換的積分)

  product_id(兌換的商品id)

  最後,光是插入上述那條積分兌換記錄是不夠的,你必須得調用倉儲業務模塊的接口,通知倉儲業務模塊新增一條發貨申請,而且應該是積分兌換對應的發貨申請,這樣保證倉庫可以準備對應的商品進行發貨。

  這個發貨申請大致對應如下的表結構:

  發貨申請表:

  id(自增id主鍵)

  type(發貨類型,1:購買,2:積分兌換)

  credit_exchange_id(積分兌換表的id)

  product_id(要發貨的商品id)

  其實這裏的發貨申請表簡化了很多,按理說還得有發貨商品的數量等等字段,但是這裏可以簡化處理也沒事,畢竟是面試現場。

  簡單畫出來這個流程大致如下所示。

  4、物流配送進度查詢,考慮到了嗎?

  如果把上面那整個業務流程給面試官說了,就完事了嗎?

  當然不是!

  你可以站在用戶的角度考慮一下,你是不是肯定還需要查看積分兌換的記錄?這個在積分兌換表裏可以查看到你用多少積分兌換了什麼商品。

  但是你兌換商品的物流配送進度,能查看到嗎?不能。所以你應該在業務流程裏再考慮進去對應的物流配送的邏輯。

  通常來說一個基本的邏輯,就是在生產發貨申請單的時候,需要調用第三方物流公司的接口申請一個物流單,這樣倉庫管理員打包準備好商品,坐等物流公司商品收快遞就可以了。

  物流公司會根據物流單去進行配送,這個配送地址當然是用戶自己在電商平臺選擇的自己的某個地址。

  此時發貨申請單的表結構是不是如下所示?

  發貨申請表:

  id(自增id主鍵)

  type(發貨類型,1:購買,2:積分兌換)

  credit_exchange_id(積分兌換表的id)

  product_id(要發貨的商品id)

  express_no(物流單號)

  所以在生產發貨申請單時,先得調用第三方物流公司的接口申請一個物流單,這樣發貨申請單中是有一個物流單號的,而且每個積分兌換記錄都通過id跟發貨申請單關聯起來。

  這樣在頁面上對每個兌換記錄,是不是可以找到發貨申請單中的物流單號,然後根據物流單號調用第三方物流公司的接口,去獲取配送的進度?

  這就是一個非常典型的業務系統的技術實現的邏輯思考,一個經驗豐富合格的工程師,往往都具備了一定的業務思維,可以很好的根據業務系統中的用戶邏輯來考慮,反推自己的系統技術實現邏輯。

  上述整個過程,如下圖所示:

  5、事務的保證

  業務流程整個捋順之後,接下來就涉及到技術的考慮了。你得考慮一下,這種業務系統裏怎麼能沒有事務呢?

  扣減積分、新增積分兌換記錄、新增發貨申請單,這三個步驟必須是要麼一起完成,要麼一起失敗的。也就是說,這三個步驟必須是在一個事務裏的。

  現在有一個問題,對一個電商平臺自身的業務系統來說,僅僅包含積分服務。但是倉儲服務一般是獨立部署的一套系統,或者是一個獨立的服務。

  也就是說,扣減積分和新增積分兌換記錄可以在一個服務裏是一個事務,但是新增發貨申請單,他是在另外一個服務裏的,這個事務如何保證呢?

  有朋友可能馬上回答:用分佈式事務啊!先別急,咱們可以先用最簡單的模式來實現一下。

  比如積分服務在一個事務代碼塊中,先執行扣減積分、新增積分兌換記錄兩個步驟。

  然後記住,在事務代碼塊中,最後一步調用倉儲服務的接口,如果接口調用成功,那麼就可以提交事務了。如果接口調用失敗,那麼就拋異常讓事務回滾,這樣可以不可以?

  這個流程如下所示:

  積分服務 事務 {

  - 扣減積分

  - 新增積分兌換記錄

  - 調用倉儲服務

  }

  6、消息中間件的引入

  上述設計其實理論上是沒問題的,但是這裏你忽略了一個問題,在這個業務場景中,積分服務是沒有必要同步調用倉儲服務的。

  因爲積分兌換是一個用戶執行的操作,假設你的倉儲服務在生成發貨申請單的時候調用第三方物流公司的接口,被卡住了,或者失敗了,怎麼辦?

  此時可能導致用戶在頁面上看到積分兌換按鈕點擊之後,卡在那兒可能幾十秒都無法執行成功,所以這個系統如此設計是錯誤的。

  那應該怎麼做呢?你必須得在這裏引入消息中間件進行異步化的解耦,保證用戶點擊積分兌換按鈕之後,儘快返回。如下圖所示:

 

  7、重試機制的引入

  到這裏就OK了嗎?還沒呢!

  一旦引入消息中間件之後,好處是用戶點擊積分兌換按鈕,直接就是在積分服務里扣減積分以及新增積分兌換記錄,然後發送一條消息到消息中間件裏就結束了,速度很快,保證了用戶體驗。

  但是壞處就是,萬一倉儲服務執行新增發貨申請失敗了怎麼辦?

  這個時候就需要引入可靠消息服務了,他需要去保證倉儲服務一定會完成新增發貨申請這個事。

  具體的流程如下:

  積分服務發送消息給可靠消息服務,可靠消息服務在消息表中新增記錄,然後發送消息到MQ(消息中間件)

  然後倉儲服務消費消息新增發貨申請單,如果成功就回調可靠消息服務的一個接口說自己成功了,可靠消息服務就可以更新本地消息表中的記錄狀態爲成功

  如果倉儲服務長時間沒通知可靠消息服務自己成功了,可靠消息服務不停的重試再次發送消息

  通過這樣的設計,就可以保證可靠消息服務一定會無限次重試保證讓倉儲服務成功執行。再加上重試機制後,整個流程圖如下所示:

  

  8、引入冪等性機制

  最後一個問題,如果倉儲服務卡在第三方物流系統申請物流單的環節,長時間阻塞,所以沒回調通知可靠消息服務。

  但是可靠消息服務過了一段時間,感覺沒收到回調通知,就自己重試發送了消息,這樣豈不是會讓倉儲服務新增兩條發貨申請單?

  因此我們還要保證倉儲服務新增發貨申請單的冪等性,其實也非常簡單,回顧一下發貨申請單表的結構:

  發貨申請表:

  id(自增id主鍵)

  type(發貨類型,1:購買,2:積分兌換)

  credit_exchange_id(積分兌換表的id)

  product_id(要發貨的商品id)

  express_no(物流單號)

  只要在“credit_exchange_id”字段上建立一個唯一索引就可以了,保證每個積分兌換記錄只能創建一條發貨申請單,如果重複創建就會被唯一索引被阻止,這樣就可以保證這個行爲的冪等性了。

  至此,對這道系統設計題目的回答,全部結束。

  9、對這類面試題的總結

  通過這篇文章的分析,可以看到對這類開放式面試題的一個回答思路,首先得從業務上來考慮這個系統應該有哪些業務組成部分,如何實現業務流程?

  其次就是你得考慮面臨對應的業務場景的時候,這個系統會有哪些技術挑戰,各個環節可能會有哪些技術問題?

  然後應該針對這些技術挑戰和技術問題,現場給出一些你的思路。只要給出大致的思路就可以,比如應該往哪個方向去解決,應該引入哪些機制。

  說實話,大部分人是沒實際做過這類系統的。比如讓你設計一個秒殺系統,如何設計?

  試問,國內有多少人真的做過秒殺系統?其實面試官只不過是通過這個問題考察你的技術面、技術功底,對各種常規技術方案的積累,以及現場分析業務,分析技術問題,進而基於你過去的技術積累,給出合理解決方案的一個能力。

  這種能力,是一個高級Java工程師必須具備的能力,因爲如果你是一個有5年以上經驗的高級工程師,那你必須在團隊裏能獨立負責一個系統。

  此時你必須有這個能力,對項目面臨的問題,要能夠分析業務,分析技術問題,然後給出合理的技術方案和架構設計。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章