精品国产一级在线观看,国产成人综合久久精品亚洲,免费一级欧美大片在线观看

Shopify的閃購限流解決方案

責任編輯:editor004

作者:薛命燈

2017-03-03 11:28:48

摘自:INFOQ

閃購,或者秒殺,對于現代互聯網用戶來說已經是一件司空見慣的事情。Shopify是加拿大著名的電子商務軟件解決方案提供商,來自Shopify性能工程團隊的Emil Stolarsky分享了Shopify的閃購限流解決方案。

閃購,或者秒殺,對于現代互聯網用戶來說已經是一件司空見慣的事情。雙十一、各大節慶日、限量供應的緊俏產品上線,大量用戶在同一時間涌入網站搶購,突如其來的流量給網站帶來了很大壓力。那么各大電商網站是如何處理流量爆發的?

Shopify是加拿大著名的電子商務軟件解決方案提供商,來自Shopify性能工程團隊的Emil Stolarsky分享了Shopify的閃購限流解決方案。

第一波閃購和來自卡戴珊家族的閃購挑戰

Shopify成立于2006年,在它成立的第二年,也就是2007年,Shopify經歷了第一波閃購。Super Bowl在美國的收視率多年來一直名列前茅,在比賽結束之后,冠軍球隊的球迷們會涌入網站購買冠軍球隊的紀念T恤,Shopify因此第一次經歷了閃購流量給網站帶來的沖擊。在那之后,應對像Super Bowl那樣的閃購流量便成為家常便飯。

來自卡戴珊家族的Kylie Jenner也是Shopify的用戶,她在Shopify上售賣自己設計的化妝品。因為她的粉絲數量眾多,每次有新產品上線,粉絲們都會不約而同地沖入網站搶購。黑色星期五的熱賣不過每年一次,但像Kylie這樣的閃購幾乎每周都在發生。在2016年2月的一次閃購中,瘋狂的流量沖垮了她的店鋪,同時也拖垮了整個數據庫。因為數據庫是共享的,直接導致其它店鋪也跟著遭殃。這一事件引起了媒體的關注。Shopify需要找到更好的方案來避免同樣的事故再次發生。

秘密武器:Nginx+Lua

在Shopify架構的最外層,是Nginx和OpenResty的Lua模塊。他們將這個模塊集成到Nginx的事件模型里,然后編寫Lua腳本來處理請求消息流和響應消息流,有點類似Rack中間件。這樣做的好處在于,寥寥幾個工程師所做的修改就能夠影響到整個站點,而且不需要對應用做大手術。

下面給出一個代碼片段例子,通過Lua腳本在響應消息頭里添加一個元數據。

events { worker_connections 42;}http { server { listen 8080; header_filter_by_lua_block { ngx.header['X-Epoch'] = ngx.time() } location / { return 200 'Hello, World!'; } }}

類似的方法可以適用于很多場景,包括將HTTP路由到多個數據中心、對請求消息流進行分片、防御DDoS攻擊。

  結算限流

Shopify團隊通過使用Lua腳本在Nginx層解決負載問題,但他們仍然需要一個回壓策略,因為再強大的服務器也無法滿足無限制的流量增長。

回壓的概念其實很簡單,試想一個具有第二個出口的容器,為了不讓倒入容器的液體溢出,可以通過第二個出口排出一部分液體。當一個應用無法處理更多的負載時,那么就可以通過一種友好的方式通知客戶端暫緩請求的發送。速率限定就是一個很常見的回壓用例。為了避免API被過度調用,可以通過速率限定對其進行限制。API的速率限定可以返回簡單的錯誤碼給客戶端,但出于用戶體驗的考慮,對于網站的回壓來說,需要使用一些精心設計的頁面來代替簡單的錯誤碼。

回壓策略產生了一定的效果,不過結算流程涉及了大量的寫操作,仍然會拖垮部分店鋪。最開始,他們為每個結算流程在MySQL數據庫里創建一條記錄,后續的每個步驟都會操作這條記錄。當然,更為理想的方案是把整個結算流程的寫操作合并到一起,變成一個最終的操作。不過時間緊迫,他們無法在短時間內實施這個方案,因為閃購活動一個接著一個,如果他們要實施這個方案,必然會引起服務中斷,對閃購活動造成影響。所以在完全使用新方案之前,他們需要一個能夠快速實施的臨時過渡方案。

漏桶算法

Shopify在系統的最外層使用了漏桶算法(leaky bucket algorithm)對用戶流量進行限流。系統根據自身的處理能力設置了一個流量上限,在某一段時間內,最多只有這么多的請求會進入到系統內部,超出的請求將被拒絕服務。對于那些被拒絕的請求,系統需要通知客戶端何時再重試。

為了獲得良好的用戶體驗,被拒絕的請求被重定向到一個排隊頁面。排隊頁面是由Shopify的平臺用戶提供的,Shopify在頁面里注入了一段JavaScript腳本,這段腳本對“/checkout”端點發起輪詢,如果輪詢請求通過了漏桶,客戶端會分配到一個經過安全簽名的cookie,用于識別后續的session。如果客戶端JavaScript被禁用,他們會使用meta refresh代替。

  結算隊列

Shopify使用漏桶算法成功地對流量進行了限流,但新的問題又接踵而至。有的顧客需要在排隊頁面等上40分鐘,而整個閃購過程可能也只有短短的40分鐘,甚至更短(在國內,緊俏的商品通常在幾分鐘內就被搶購一空,有的甚至是秒光),這對于顧客來說是一種很糟糕的體驗。

問題是,真有那么多人在排隊嗎?竟然要排上40分鐘那么久?后來Shopify意識到一個問題,他們讓用戶在排隊頁面等待,并通過向“/checkout”端點發起輪詢再次發出結算請求,但輪詢的時間間隔是隨機的,所以有可能出現一直被拒絕的情況。所以這種排隊是不平等的,如果有人結算成功就跟中了彩票一樣幸運,而那些等了40分鐘的人只能怪他們運氣不好。

Shopify需要一個公平的排隊機制。

時間戳

為了讓排隊機制更加公平,Shopify為每一個結算請求啟用了時間戳。每個用戶在發起第一個結算請求時會獲得一個時間戳,如果請求沒有通過漏桶,那么時間戳就會被保存起來。當用戶再次發起輪詢,之前保存的時間戳就會被用來做比對,時間戳排名靠前的會優先通過漏桶。這么一來,對于獲得較早時間戳的用戶,當他們的請求再次達到,可以確保不會落在時間戳靠后的請求后面。

這種方式雖然提高了公平性,但引入了數據存儲,很容易成為新的故障點。而且如果系統需要跨多個數據中心,數據中心之間的數據復制會拖慢整個系統。所以他們需要找到一個不數據存儲的解決方案。

新的方案是使用閾值。閾值是什么?可以打個形象的比喻:有個很受歡迎的餐廳,每次去這家餐廳吃飯的顧客人數都超出了它的服務能力,所以顧客需要排隊。排隊的顧客人手一個號碼牌,每過一段時間,服務員就會出來喊道:“請第X號之前的顧客到里面用餐”。這樣,餐廳就不需要每次比對顧客之間的號碼牌,而是比較號碼牌和服務員嘴里所說的那個號碼。服務員每次所喊的號就是閾值,這個值會根據系統的處理能力動態變化,而顧客手里拿的號碼牌就是那個時間戳,這個時間戳會被放在經過安全簽名的cookie里,所以就沒必要存儲時間戳了。那么接下來的問題變成了該如何計算這個閾值。

PID控制器

為了計算出這個動態的閾值,也就是服務員口中的那個號碼,Shopify在系統中使用了PID控制器。閾值需要根據實時的流量情況和系統處理能力進行動態調整,PID控制器是實現動態調整的關鍵組件。PID控制器是一個無限循環的自反饋組件,假設給定了一個預期的系統狀態,PID控制器會計算當前狀態與預期狀態之間的差距(也就是系統錯誤值),對當前狀態進行糾正,向預期狀態靠攏。系統狀態不斷地發生變化,PID控制器根據反饋計算錯誤值,再次把系統帶向預期狀態,不斷重復這樣的過程。

關于PID控制器的工作原理,也有一個形象的比喻。想象一下房間的溫控系統,假設預期溫度為23度,當房間實際溫度為22度時,控制器發現此時的溫度與預期狀態相差1度(也就是說錯誤值為1度),加熱器就會被啟動,通過提升溫度來糾正錯誤值。過了一會兒,溫度上升到24度,控制器發現此時的溫度超過了預期狀態(又出現了錯誤值),于是加熱器被關閉,空調被打開,通過降溫來糾正錯誤值。控制器不斷地檢測房間溫度,讓溫度保持在預期的狀態,這就是PID控制器的工作原理。

公平性比較

通過以下兩張圖片可以看出新的排隊方案與之前的排隊方案在公平性方面的差異。圖中黃色代表平均排隊時間,藍色代表P95排隊時間,紫色代表中值排隊時間。

從圖1可以看出,不公平的排隊方案各條線之間的間隔較大,這也意味著用戶的排隊等待時間相差較大。

圖2的各條線幾乎是重合的,也就是說用戶的排隊等待時間幾乎是相等的。

鏈接已復制,快去分享吧

企業網版權所有?2010-2024 京ICP備09108050號-6京公網安備 11010502049343號

  • <menuitem id="jw4sk"></menuitem>

    1. <form id="jw4sk"><tbody id="jw4sk"><dfn id="jw4sk"></dfn></tbody></form>
      主站蜘蛛池模板: 花莲市| 吉林省| 涪陵区| 施秉县| 明溪县| 南阳市| 长葛市| 通山县| 舞阳县| 安阳县| 包头市| 长武县| 民权县| 涿州市| 宁南县| 九江市| 岚皋县| 根河市| 五家渠市| 高州市| 罗城| 岳普湖县| 尉犁县| 玛纳斯县| 晋宁县| 会同县| 泰州市| 寻甸| 宜章县| 都昌县| 天津市| 沅江市| 崇文区| 东安县| 诸暨市| 淮阳县| 保康县| 瑞昌市| 铅山县| 兴安盟| 共和县|