59校園狂歡節技術架構剖析

longma0401 8年前發布 | 5K 次閱讀 數據庫 軟件架構

59store是一家專注校園市場的互聯網企業,以校園消費類O2O及金融作為核心業務,自成立以為每年都會舉辦一次59校園狂歡節,在2016年5月9號的59校園狂歡節創下了單日96萬訂單,近3500萬交易額。其中,59store所面臨挑戰是:在線服務是否能抵抗住零點瘋狂流量的涌入,各個業務線都有活動需求需要按時交付,各項基礎服務和眾多業務應用的高可用保障,保護第三方合作方的服務器不被59帶去的巨大流量壓垮……本文將詳細解讀59store在挑戰面前所作的準備,以及其中關鍵技術架構剖析。

一、面向服務架構

59store定位校園生活服務平臺,構建了豐富的消費場景,滿足了校園生活多方面的需求。

圖1 項目歷程

2014年年底,59創造性地推出了“夜貓店”的全新商業模式。2015年下半年,隨著生活服務平臺理念的深化,59先后推出了飲品店、零食盒、創客中心、外賣等項目,并且針對校園金融推出了白花花、白借借等金融業務。2016年開始,以信用錢包為核心,升級并擴充了若干新的金融類業務。隨著上云印店、社區的先后推出,一個校園生活服務平臺雛形初現。

在早期開發夜貓店、飲品店、零食盒的過程中,我們看重敏捷開發,快速迭代,小步快跑,不斷試錯,以至于沒有充分地考慮系統抽象,做了很多重復業務特征的實現,缺少復用和整合。隨著業務平臺化趨勢的凸顯,抽象而可持續的業務架構迫在眉睫。經過半年的不斷抽象、剝離、重構,現在59已經形成了一整套基礎服務體系,以及構建在其之上的眾多業務。

圖2 服務-應用

在備戰今年59校園狂歡節的過程中,我們不僅要應對巨大的訪問流量,而且還有新的項目和活動需要上線(代號為folivora的秒殺系統和代號為paramecium的品牌館)。得益于成熟穩定的基礎服務,我們可以非常快速地構建上層應用,而忽略底層數據結構和服務接口的創建,讓開發、維護變得輕松而愉悅。在基礎服務不斷演進成熟的過程中,我們總結出了以下幾點感受。

1. 明確標準

一個制定良好的數據結構和服務接口,會讓往后的開發、維護省去很多的潛在成本,包括但不限于常用單詞的全局統一含義、變量命名標準,接口風格統一等等。沒有這些統一的規范就好比腳底有沙子,走得越遠,腳會被磨得越破。

2. 接口細粒度

接口定義到怎么樣的細粒度,會直接影響使用者的效率。僅僅提供增刪改查的操作,或每一個功能都配備特定的接口,都會比較偏頗。在不斷摸索的過程中,59逐步統一了“原子業務化”的接口設計思想,即接口需要恰如其分地描述一個獨立的原子業務。比如create_order即生成一個訂單,包括了訂單金額,折扣,促銷,訂單狀態,相關時間,用戶信息,訂單信息,商品明細等一系列邏輯。cancel_order取消一個訂單,包括了狀態異常的判斷,不同支付方式退款,優惠券、積分的處理等。

3. 劃清職責

基礎服務層需要服務眾多業務,而不同的業務各有特點,如果基礎服務支持所有業務的個性特點,勢必會導致服務層數據結構的冗余和潛在的不穩定因素。因此我們嚴格劃分服務和應用的交付界限,服務僅僅提供所有業務場景通用的數據結構和接口,比如訂單狀態,用戶頭像,商品名稱等。簡單的個性化業務需求,可以使用服務層數據結構包含的一個業務自定義JSON字段來滿足需求。更復雜的業務個性信息則需要業務系統自身來維護,比如某個打印訂單文件空白頁檢測結果信息等。在明確職責的基礎上提供一定程度的靈活性,不斷沉淀出穩定的基礎服務。

二、秒殺系統

5月7號開始,59會發起一系列的秒殺活動來預熱59校園狂歡節,然后在5月9號達到活動高潮。對此,我們做了一系列的技術優化方案來保障秒殺業務的服務可用。

秒殺是一個讀多寫少的場景,并且瞬時下單的系統負載大,對數據的一致性要求比較高。針對這樣的業務特點,我們對獲取數據接口和下單接口做了不同的優化方案。

獲取數據接口方面,秒殺商品信息全部緩存在Redis集群中,以減緩高并發場景下的系統壓力和數據庫負載。

秒殺下單接口的瞬時訪問量大,對數據的一致性要求高,因此我們做了特殊的設計。假設一個商品秒殺庫存有5件,庫存的信息會被存儲在一個Redis集群中,并且留有一定冗余,比如記錄秒殺商品庫存為8件。多臺秒殺計算節點分布式部署,使得其可以線性水平擴展,保障高可用,不會成為性能瓶頸。下單請求會被分發到任意一臺服務器,然后檢測當前秒殺商品是否已秒完,如果是,則直接返回已秒完,如果不是,則直接調用訂單服務接口下單。由于我們放入了比實際秒殺庫存更多的請求進來,所以在下單過程中如果發現秒殺商品無庫存,同樣會給用戶報出已秒完。

圖3 秒殺系統架構

針對秒殺應用,行業的慣用做法是使用隊列來削峰,從而減緩系統負載。不過經過團隊討論,我們決定簡化系統設計為如上敘述。主要有以下幾個方面的考慮:1、系統可以在秒殺下單邏輯一開始便判斷業務邏輯是否需要繼續(即是否已秒完),如果已秒完則立即返回,不繼續后續業務邏輯執行,這隱含地做了“削峰”的工作。并且系統結構比使用消息隊列的方案更簡單。消息隊列方案至少包含一個消息隊列存儲秒殺請求,生產者、消費者的邏輯實現,以及商品被秒殺完后,消息隊列中請求的處理和后續到來請求的處理邏輯等。2、調用下單模塊沒有使用隊列來“削峰”,因為業務決定我們每場秒殺的商品庫存不多,數據庫可以承受得起這樣的并發量。

三、數據庫拆分

在推進服務化架構之前,59所有的數據庫表都集中在同一個數據庫實例中。隨著業務的飛速增長,數據庫承受了非常大的壓力,瓶頸效應凸顯。于是在服務化一開始,我們便做了分庫優化。

首先是拆: 針對業務特點,將獨立的業務模塊逐步抽離,比如數據統計,APP支持,活動模塊等。并且新上線的項目會嚴格把控存儲位置和依賴關系,能獨立的數據庫表便不放在主庫中。其次是合:基礎訂單服務,商品服務等使用的分布式數據庫獨立部署。

在構建分布式數據庫的過程中,我們 選用mycat作為數據庫拆分中間件 ,它可以提供良好的針對分片規則的數據庫拆分服務。對于商品服務而言,幾乎所有的場景(不管是賣家管理自己商品,或者買家瀏覽店鋪商品),都需要通過賣家ID獲得商品列表。所以以商品owner_id作為分片規則水平拆分,即可以滿足需求。關于訂單服務,常見業務場景不僅包括買家通過買家ID獲取自己的訂單列表,也包括賣家通過賣家ID獲取自己的訂單列表。因此從任何一個維度劃分都不能滿足另一方的需求。針對這個問題,59的解決方案如下。

圖4 數據庫拆分

我們 定義了買家庫和賣家庫,兩者通過MySQL的binlog機制保持數據同步 。買家庫表定義了一個sharding字段作為分片規則,被劃分成了32個分片。sharding是用戶ID的后若干位,從而在買家庫,通過用戶ID的訂單檢索可以非常方便地使用到分片規則,提升檢索性能。賣家庫我們暫時沒有做水平拆分,而是一個數據庫實例。在賣家ID上建立索引,從而在賣家庫通過賣家ID獲取訂單列表同樣可以有不錯的性能表現。買家庫沒有在賣家ID建立索引,同步機制僅僅同步數據,而不同步結構。賣家庫是一個只讀實例,當賣家需要修改一個訂單信息的時候,需要在買家庫進行操作。如何在已知訂單ID的情況下,檢索訂單的請求可以使用到買家庫的分片規則便成為最后一個問題。我們的解決方案是:訂單ID中包含了sharding信息,從而在修改一個訂單信息的時候可以輕松應用到分片規則。

當訂單數據量非常龐大的時候, 冷數據歸檔 會帶來很大的性能提升。結合校園市場特點,用戶4年一個大周期,1學期一個小周期,以每一學期作為時間節點來歸檔冷數據會帶來最佳的用戶體驗。

四、最后

在59store的技術成長歷程中,任何的技術選型、技術方案、技術優化都是業務來驅動的。從最開始的一個單獨的PHP應用,到現在60多個服務、應用,從最開始的一臺VPS,到現在數百臺云服務器,技術始終在59的發展歷程中扮演著至關重要的作用。不同的階段,技術的主要矛盾點是不同的,如何準確的拿捏和把握,值得每一個創業的技術人揣摩和體會。

 

 

來自:http://mp.weixin.qq.com/s?__biz=MzA4NDc2MDQ1Nw==&mid=2650238086&idx=1&sn=9c89eea6065833b12a33f556e219ba43&chksm=87e18e60b0960776a1c50ecbb8fbd8220989e4326413c625228ae05261e072ba1aede93070af&scene=0#wechat_redirect

 

 本文由用戶 longma0401 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!