構建高併發高可用的電商平臺架構實踐1

構建高併發高可用的電商平臺架構實踐1

 

 

問題導讀: 1.如何構建高併發電商平臺架構

2.哈希、B樹、倒排、bitmap的作用是什麼?

3.作爲軟件工程師,該如何實現讀寫?

4.如何實現負載均衡、反向代理?

5.電商業務是什麼?

6.基礎中間件該如何設計?

7.對於平臺各個系統之間的異步交互,可以通過什麼實現?

8.搜索功能該考慮什麼問題?

9.實時計算需要考慮什麼因素?

10.數據存儲可以考慮使用什麼數據庫?

11.對於高併發高性能的mysql來講,可以在哪些方面進行性能方面的調優?

 

一、 設計理念 1. 空間換時間1) 多級緩存,靜態化 客戶端頁面緩存(http header中包含Expires/Cache of Control,last modified(304,server不返回body,客戶端可以繼續用cache,減少流量),ETag) 反向代理緩存 應用端的緩存(memcache) 內存數據庫 Buffer、cache機制(數據庫,中間件等) 2) 索引 哈希、B樹、倒排、bitmap 哈希索引適合綜合數組的尋址和鏈表的插入特性,可以實現數據的快速存取。 B樹索引適合於查詢爲主導的場景,避免多次的IO,提高查詢的效率。 倒排索引實現單詞到文檔映射關係的最佳實現方式和最有效的索引結構,廣泛用在搜索領域。 Bitmap是一種非常簡潔快速的數據結構,他能同時使存儲空間和速度最優化(而不必空間換時間),適合於海量數據的的計算場景。 2. 並行與分佈式計算 1) 任務切分、分而治之(MR) 在大規模的數據中,數據存在一定的局部性的特徵,利用局部性的原理將海量數據計算的問題分而治之。 MR模型是無共享的架構,數據集分佈至各個節點。處理時,每個節點就近讀取本地存儲的數據處理(map),將處理後的數據進行合併(combine)、排序(shuffle and sort)後再分發(至reduce節點),避免了大量數據的傳輸,提高了處理效率。 2) 多進程、多線程並行執行(MPP) 並行計算(Parallel Computing)是指同時使用多種計算資源解決計算問題的過程,是提高計算機系統計算速度和處理能力的一種有效手段。它的基本思想是用多個處理器/進程/線程來協同求解同一問題,即將被求解的問題分解成若干個部分,各部分均由一個獨立的處理機來並行計算。 和MR的區別在於,它是基於問題分解的,而不是基於數據分解。 3. 多維度的可用1) 負載均衡、容災、備份 隨着平臺併發量的增大,需要擴容節點進行集羣,利用負載均衡設備進行請求的分發;負載均衡設備通常在提供負載均衡的同時,也提供失效檢測功能;同時爲了提高可用性,需要有容災備份,以防止節點宕機失效帶來的不可用問題;備份有在線的和離線備份,可以根據失效性要求的不同,進行選擇不同的備份策略。 2) 讀寫分離 讀寫分離是對數據庫來講的,隨着系統併發量的增大,提高數據訪問可用性的一個重要手段就是寫數據和讀數據進行分離;當然在讀寫分離的同時,需要關注數據的一致性問題;對於一致性的問題,在分佈式的系統CAP定量中,更多的關注於可用性。 3) 依賴關係 平臺中各個模塊之間的關係儘量是低耦合的,可以通過相關的消息組件進行交互,能異步則異步,分清楚數據流轉的主流程和副流程,主副是異步的,比如記錄日誌可以是異步操作的,增加整個系統的可用性。 當然在異步處理中,爲了確保數據得到接收或者處理,往往需要確認機制(confirm、ack)。 但是有些場景中,雖然請求已經得到處理,但是因其他原因(比如網絡不穩定),確認消息沒有返回,那麼這種情況下需要進行請求的重發,對請求的處理設計因重發因素需要考慮冪等性。 4) 監控 監控也是提高整個平臺可用性的一個重要手段,多平臺進行多個維度的監控;模塊在運行時候是透明的,以達到運行期白盒化。 4. 伸縮1) 拆分 拆分包括對業務的拆分和對數據庫的拆分。 系統的資源總是有限的,一段比較長的業務執行如果是一竿子執行的方式,在大量併發的操作下,這種阻塞的方式,無法有效的及時釋放資源給其他進程執行,這樣系統的吞吐量不高。 需要把業務進行邏輯的分段,採用異步非阻塞的方式,提高系統的吞吐量。 隨着數據量和併發量的增加,讀寫分離不能滿足系統併發性能的要求,需要對數據進行切分,包括對數據進行分庫和分表。這種分庫分表的方式,需要增加對數據的路由邏輯支持。 2) 無狀態 對於系統的伸縮性而言,模塊最好是無狀態的,通過增加節點就可以提高整個的吞吐量。 5. 優化資源利用1) 系統容量有限 系統的容量是有限的,承受的併發量也是有限的,在架構設計時,一定需要考慮流量的控制,防止因意外攻擊或者瞬時併發量的衝擊導致系統崩潰。在設計時增加流控的措施,可考慮對請求進行排隊,超出預期的範圍,可以進行告警或者丟棄。 2) 原子操作與併發控制 對於共享資源的訪問,爲了防止衝突,需要進行併發的控制,同時有些交易需要有事務性來保證交易的一致性,所以在交易系統的設計時,需考慮原子操作和併發控制。 保證併發控制一些常用高性能手段有,樂觀鎖、Latch、mutex、寫時複製、CAS等;多版本的併發控制MVCC通常是保證一致性的重要手段,這個在數據庫的設計中經常會用到。 3) 基於邏輯的不同,採取不一樣的策略 平臺中業務邏輯存在不同的類型,有計算複雜型的,有消耗IO型的,同時就同一種類型而言,不同的業務邏輯消耗的資源數量也是不一樣的,這就需要針對不同的邏輯採取不同的策略。 針對IO型的,可以採取基於事件驅動的異步非阻塞的方式,單線程方式可以減少線程的切換引起的開銷,或者在多線程的情況下采取自旋spin的方式,減少對線程的切換(比如oracle latch設計);對於計算型的,充分利用多線程進行操作。 同一類型的調用方式,不同的業務進行合適的資源分配,設置不同的計算節點數量或者線程數量,對業務進行分流,優先執行優先級別高的業務。 4) 容錯隔離 系統的有些業務模塊在出現錯誤時,爲了減少併發下對正常請求的處理的影響,有時候需要考慮對這些異常狀態的請求進行單獨渠道的處理,甚至暫時自動禁止這些異常的業務模塊。 有些請求的失敗可能是偶然的暫時的失敗(比如網絡不穩定),需要進行請求重試的考慮。 5) 資源釋放 系統的資源是有限的,在使用資源時,一定要在最後釋放資源,無論是請求走的是正常路徑還是異常的路徑,以便於資源的及時回收,供其他請求使用。 在設計通信的架構時,往往需要考慮超時的控制。 二、 靜態架構藍圖

整個架構是分層的分佈式的架構,縱向包括CDN,負載均衡/反向代理,web應用,業務層,基礎服務層,數據存儲層。水平方向包括對整個平臺的配置管理部署和監控。

三、 剖析架構1. CDN CDN系統能夠實時地根據網絡流量和各節點的連接、負載狀況以及到用戶的距離和響應時間等綜合信息將用戶的請求重新導向離用戶最近的服務節點上。其目的是使用戶可就近取得所需內容,解決 Internet網絡擁擠的狀況,提高用戶訪問網站的響應速度。 對於大規模電子商務平臺一般需要建CDN做網絡加速,大型平臺如淘寶、京東都採用自建CDN,中小型的企業可以採用第三方CDN廠商合作,如藍汛、網宿、快網等。 當然在選擇CDN廠商時,需要考慮經營時間長短,是否有可擴充的帶寬資源、靈活的流量和帶寬選擇、穩定的節點、性價比。 2. 負載均衡、反向代理 一個大型的平臺包括很多個業務域,不同的業務域有不同的集羣,可以用DNS做域名解析的分發或輪詢,DNS方式實現簡單,但是因存在cache而缺乏靈活性;一般基於商用的硬件F5、NetScaler或者開源的軟負載lvs在4層做分發,當然會採用做冗餘(比如lvs+keepalived)的考慮,採取主備方式。 4層分發到業務集羣上後,會經過web服務器如nginx或者HAProxy在7層做負載均衡或者反向代理分發到集羣中的應用節點。 選擇哪種負載,需要綜合考慮各種因素(是否滿足高併發高性能,Session保持如何解決,負載均衡的算法如何,支持壓縮,緩存的內存消耗);下面基於幾種常用的負載均衡軟件做個介紹。 LVS,工作在4層,Linux實現的高性能高併發、可伸縮性、可靠的的負載均衡器,支持多種轉發方式(NAT、DR、IP Tunneling),其中DR模式支持通過廣域網進行負載均衡。支持雙機熱備(Keepalived或者Heartbeat)。對網絡環境的依賴性比較高。 Nginx工作在7層,事件驅動的、異步非阻塞的架構、支持多進程的高併發的負載均衡器/反向代理軟件。可以針對域名、目錄結構、正則規則針對http做一些分流。通過端口檢測到服務器內部的故障,比如根據服務器處理網頁返回的狀態碼、超時等等,並且會把返回錯誤的請求重新提交到另一個節點,不過其中缺點就是不支持url來檢測。對於session sticky,可以基於ip hash的算法來實現,通過基於cookie的擴展nginx-sticky-module支持session sticky。 HAProxy支持4層和7層做負載均衡,支持session的會話保持,cookie的引導;支持後端url方式的檢測;負載均衡的算法比較豐富,有RR、權重等。 對於圖片,需要有單獨的域名,獨立或者分佈式的圖片服務器或者如mogileFS,可以圖片服務器之上加varnish做圖片緩存。 3. App接入 應用層運行在jboss或者tomcat容器中,代表獨立的系統,比如前端購物、用戶自主服務、後端系統等 協議接口,HTTP、JSON 可以採用servlet3.0,異步化servlet,提高整個系統的吞吐量 http請求經過Nginx,通過負載均衡算法分到到App的某一節點,這一層層擴容起來比較簡單。 除了利用cookie保存少量用戶部分信息外(cookie一般不能超過4K的大小),對於App接入層,保存有用戶相關的session數據,但是有些反向代理或者負載均衡不支持對session sticky支持不是很好或者對接入的可用性要求比較高(app接入節點宕機,session隨之丟失),這就需要考慮session的集中式存儲,使得App接入層無狀態化,同時系統用戶變多的時候,就可以通過增加更多的應用節點來達到水平擴展的目的。 Session的集中式存儲,需要滿足以下幾點要求: a、高效的通訊協議 b、session的分佈式緩存,支持節點的伸縮,數據的冗餘備份以及數據的遷移 c、session過期的管理 4. 業務服務 代表某一領域的業務提供的服務,對於電商而言,領域有用戶、商品、訂單、紅包、支付業務等等,不同的領域提供不同的服務, 這些不同的領域構成一個個模塊,良好的模塊劃分和接口設計非常重要,一般是參考高內聚、接口收斂的原則, 這樣可以提高整個系統的可用性。當然可以根據應用規模的大小,模塊可以部署在一起,對於大規模的應用,一般是獨立部署的。 高併發: 業務層對外協議以NIO的RPC方式暴露,可以採用比較成熟的NIO通訊框架,如netty、mina 可用性: 爲了提高模塊服務的可用性,一個模塊部署在多個節點做冗餘,並自動進行負載轉發和失效轉移; 最初可以利用VIP+heartbeat方式,目前系統有一個單獨的組件HA,利用zookeeper實現(比原來方案的優點) 一致性、事務: 對於分佈式系統的一致性,儘量滿足可用性,一致性可以通過校對來達到最終一致的狀態。 5. 基礎服務中間件 1) 通信組件 通信組件用於業務系統內部服務之間的調用,在大併發的電商平臺中,需要滿足高併發高吞吐量的要求。 整個通信組件包括客戶端和服務端兩部分。 客戶端和服務器端維護的是長連接,可以減少每次請求建立連接的開銷,在客戶端對於每個服務器定義一個連接池,初始化連接後,可以併發連接服務端進行rpc操作,連接池中的長連接需要心跳維護,設置請求超時時間。 對於長連接的維護過程可以分兩個階段,一個是發送請求過程,另外一個是接收響應過程。在發送請求過程中,若發生IOException,則把該連接標記失效。接收響應時,服務端返回SocketTimeoutException,如果設置了超時時間,那麼就直接返回異常,清除當前連接中那些超時的請求。否則繼續發送心跳包(因爲可能是丟包,超過pingInterval間隔時間就發送ping操作),若ping不通(發送IOException),則說明當前連接是有問題的,那麼就把當前連接標記成已經失效;若ping通,則說明當前連接是可靠的,繼續進行讀操作。失效的連接會從連接池中清除掉。 每個連接對於接收響應來說都以單獨的線程運行,客戶端可以通過同步(wait,notify)方式或者異步進行rpc調用, 序列化採用更高效的hession序列化方式。 服務端採用事件驅動的NIO的MINA框架,支撐高併發高吞吐量的請求。

2) 路由Router 在大多數的數據庫切分解決方案中,爲了提高數據庫的吞吐量,首先是對不同的表進行垂直切分到不同的數據庫中, 然後當數據庫中一個表超過一定大小時,需要對該表進行水平切分,這裏也是一樣,這裏以用戶表爲例; 對於訪問數據庫客戶端來講,需要根據用戶的ID,定位到需要訪問的數據; 數據切分算法, 根據用戶的ID做hash操作,一致性Hash,這種方式存在失效數據的遷移問題,遷移時間內服務不可用 維護路由表,路由表中存儲用戶和sharding的映射關係,sharding分爲leader和replica,分別負責寫和讀 這樣每個biz客戶端都需要保持所有sharding的連接池,這樣有個缺點是會產生全連接的問題; 一種解決方法是sharding的切分提到業務服務層進行,每個業務節點只維護一個shard的連接即可。 見圖(router)

路由組件的實現是這樣的(可用性、高性能、高併發) 基於性能方面的考慮,採用mongodb中維護用戶id和shard的關係,爲了保證可用性,搭建replicatset集羣。 biz的sharding和數據庫的sharding是一一對應的,只訪問一個數據庫sharding. biz業務註冊節點到zookeeper上/bizs/shard/下。 router監聽zookeeper上/bizs/下節點狀態,緩存在線biz在router中。 client請求router獲取biz時,router首先從mongodb中獲取用戶對應的shard,router根據緩存的內容通過RR算法獲取biz節點。 爲了解決router的可用性和併發吞吐量問題,對router進行冗餘,同時client監聽zookeeper的/routers節點並緩存在線router節點列表。 3) HA 傳統實現HA的做法一般是採用虛擬IP漂移,結合Heartbeat、keepalived等實現HA, Keepalived使用vrrp方式進行數據包的轉發,提供4層的負載均衡,通過檢測vrrp數據包來切換,做冗餘熱備更加適合與LVS搭配。Linux Heartbeat是基於網絡或者主機的服務的高可用,HAProxy或者Nginx可以基於7層進行數據包的轉發,因此Heatbeat更加適合做HAProxy、Nginx,包括業務的高可用。 在分佈式的集羣中,可以用zookeeper做分佈式的協調,實現集羣的列表維護和失效通知,客戶端可以選擇hash算法或者roudrobin實現負載均衡;對於master-master模式、master-slave模式,可以通過zookeeper分佈式鎖的機制來支持。 4) 消息Message 對於平臺各個系統之間的異步交互,是通過MQ組件進行的。 在設計消息服務組件時,需要考慮消息一致性、持久化、可用性、以及完善的監控體系。 業界開源的消息中間件主要RabbitMQ、kafka有兩種, RabbitMQ,遵循AMQP協議,由內在高併發的erlanng語言開發;kafka是Linkedin於2010年12月份開源的消息發佈訂閱系統,它主要用於處理活躍的流式數據,大數據量的數據處理上。 對消息一致性要求比較高的場合需要有應答確認機制,包括生產消息和消費消息的過程;不過因網絡等原理導致的應答缺失,可能會導致消息的重複,這個可以在業務層次根據冪等性進行判斷過濾;RabbitMQ採用的是這種方式。還有一種機制是消費端從broker拉取消息時帶上LSN號,從broker中某個LSN點批量拉取消息,這樣無須應答機制,kafka分佈式消息中間件就是這種方式。 消息的在broker中的存儲,根據消息的可靠性的要求以及性能方面的綜合衡量,可以在內存中,可以持久化到存儲上。 對於可用性和高吞吐量的要求,集羣和主備模式都可以在實際的場景應用的到。RabbitMQ解決方案中有普通的集羣和可用性更高的mirror queue方式。 kafka採用zookeeper對集羣中的broker、consumer進行管理,可以註冊topic到zookeeper上;通過zookeeper的協調機制,producer保存對應topic的broker信息,可以隨機或者輪詢發送到broker上;並且producer可以基於語義指定分片,消息發送到broker的某分片上。 總體來講,RabbitMQ用在實時的對可靠性要求比較高的消息傳遞上。kafka主要用於處理活躍的流式數據,大數據量的數據處理上。 5) Cache&BufferCache系統 在一些高併發高性能的場景中,使用cache可以減少對後端系統的負載,承擔可大部分讀的壓力,可以大大提高系統的吞吐量,比如通常在數據庫存儲之前增加cache緩存。 但是引入cache架構不可避免的帶來一些問題,cache命中率的問題, cache失效引起的抖動,cache和存儲的一致性。 Cache中的數據相對於存儲來講,畢竟是有限的,比較理想的情況是存儲系統的熱點數據,這裏可以用一些常見的算法LRU等等淘汰老的數據;隨着系統規模的增加,單個節點cache不能滿足要求,就需要搭建分佈式Cache;爲了解決單個節點失效引起的抖動 ,分佈式cache一般採用一致性hash的解決方案,大大減少因單個節點失效引起的抖動範圍;而對於可用性要求比較高的場景,每個節點都是需要有備份的。數據在cache和存儲上都存有同一份備份,必然有一致性的問題,一致性比較強的,在更新數據庫的同時,更新數據庫cache。對於一致性要求不高的,可以去設置緩存失效時間的策略。 Memcached作爲高速的分佈式緩存服務器,協議比較簡單,基於libevent的事件處理機制。 Cache系統在平臺中用在router系統的客戶端中,熱點的數據會緩存在客戶端,當數據訪問失效時,纔去訪問router系統。 當然目前更多的利用內存型的數據庫做cache,比如redis、mongodb;redis比memcache有豐富的數據操作的API;redis和mongodb都對數據進行了持久化,而memcache沒有這個功能,因此memcache更加適合在關係型數據庫之上的數據的緩存。 Buffer系統 用在高速的寫操作的場景中,平臺中有些數據需要寫入數據庫,並且數據是分庫分表的,但對數據的可靠性不是那麼高,爲了減少對數據庫的寫壓力,可以採取批量寫操作的方式。 開闢一個內存區域,當數據到達區域的一定閥值時如80%時,在內存中做分庫梳理工作(內存速度還是比較快的),後分庫批量flush。

原文發佈於微信公衆號 - about雲(wwwaboutyuncom)

原文發表時間:2014-05-25

本文參與騰訊雲自媒體分享計劃,歡迎正在閱讀的你也加入,一起分享。

發表於 2018-03-26

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