線上大爆發(fā),移動訂單量占比達(dá)83%,歸功于蘇寧易購移動端統(tǒng)一接入層!
原創(chuàng)【51CTO.com原創(chuàng)稿件】近幾年,蘇寧易購隨著業(yè)務(wù)的發(fā)展,用戶使用習(xí)慣的改變,不斷強(qiáng)化移動端發(fā)展,加強(qiáng)與視頻直播,娛樂、體育營銷等各類內(nèi)容媒體的合作,創(chuàng)新營銷產(chǎn)品,不斷提升移動端日活,2017 年 3 月移動端訂單數(shù)量已占線上整體比例的 83%。
為了進(jìn)一步提高移動端訪問速度,提升用戶體驗(yàn),移動團(tuán)隊(duì)潛心研究網(wǎng)關(guān)、http2.0技術(shù),最終決定上線統(tǒng)一接入層。
下面從三個方面解析蘇寧易購移動端統(tǒng)一接入層:
- 統(tǒng)一接入層設(shè)計(jì)
- 統(tǒng)一接入層的功能、實(shí)現(xiàn)
- 統(tǒng)一接入層的性能
統(tǒng)一接入層的設(shè)計(jì)
蘇寧易購的架構(gòu)演進(jìn)
蘇寧易購的網(wǎng)絡(luò)架構(gòu)不斷發(fā)展演進(jìn),2014 年接入應(yīng)用防火墻,為 Web 應(yīng)用提供安全保護(hù)。2015 - 2016 年,整體架構(gòu)更加健壯穩(wěn)定,保障了業(yè)務(wù)需求,支撐了線上業(yè)務(wù)的飛速發(fā)展。
2017 年,隨著統(tǒng)一接入層的加入,系統(tǒng)封裝了應(yīng)用程序的內(nèi)部結(jié)構(gòu)。客戶端只需要同網(wǎng)關(guān)交互,而不必調(diào)用特定的服務(wù)。并在此基礎(chǔ)上,系統(tǒng)做了域名收斂,使用 http2.0 協(xié)議,重點(diǎn)提高了移動端的訪問速度。
統(tǒng)一接入層的架構(gòu)劃分
統(tǒng)一接入層內(nèi)部架構(gòu)分為三層:
- 代理層,有多臺代理 proxy,由 go 語言實(shí)現(xiàn),將請求向后轉(zhuǎn)發(fā);
- 一個個虛擬的集群,每個集群對應(yīng)一個業(yè)務(wù)系統(tǒng),并且管理著系統(tǒng)的服務(wù)器;
- 服務(wù)器,該服務(wù)器為目前線上各個系統(tǒng)的服務(wù)器。配置信息存儲在 zookeeper 上,后臺管理系統(tǒng)對 zookeeper 上的配置數(shù)據(jù)進(jìn)行統(tǒng)一的管理。
從上往下,統(tǒng)一接入層對移動端的請求做了接管,然后轉(zhuǎn)發(fā)到相應(yīng)的服務(wù)器上去。代理層用 go 語言實(shí)現(xiàn),主要是利用 go 的高性能,以及線程***制。后臺管理系統(tǒng)使用 Java 實(shí)現(xiàn),為了統(tǒng)一管理,使用公司內(nèi)部 passport、統(tǒng)一后臺管理等。
目前,移動端系統(tǒng)接入統(tǒng)一接入層后,iOS 和 Android 客戶端發(fā)出的請求全部收斂為一個域名,并且走 http2.0 協(xié)議。請求經(jīng) CDN 到達(dá)代理層 proxy,proxy 再將請求轉(zhuǎn)發(fā)到各個集群系統(tǒng),回源協(xié)議支持 http2.0,http1.1。
統(tǒng)一接入層功能、實(shí)現(xiàn)
統(tǒng)一接入層的一項(xiàng)重要功能是轉(zhuǎn)發(fā)請求,我們首先考慮基于 Nginx 做整個代理層,但綜合分析,其與我們團(tuán)隊(duì)技術(shù)方向不一致,修改 Nginx 成本較高,不便于定制個性化需求。
然后,我們選擇使用 go 語言,一是被其簡潔的語法所吸引,二是其性能確實(shí)強(qiáng)悍,后期的壓測數(shù)據(jù),也證實(shí)了這一點(diǎn),讓我們感到驚喜。
技術(shù)實(shí)現(xiàn)方案
下面介紹在整個實(shí)現(xiàn)過程中,我們應(yīng)用的技術(shù)點(diǎn),和接入層具備的功能:
- 采用高效的 fasthttp 組件做請求接入和轉(zhuǎn)發(fā)層,性能直逼 Ngnix,經(jīng)過測試每個轉(zhuǎn)發(fā)請求包括網(wǎng)絡(luò)傳輸平均只增加了 0.1 毫秒。
- fasthttp是 Go 的一款不同于標(biāo)準(zhǔn)庫 net/http 的 HTTP 實(shí)現(xiàn),其性能可以達(dá)到標(biāo)準(zhǔn)庫的 10 倍。
- 在匹配路由規(guī)則上,通過快速查找算法和精準(zhǔn)匹配算法的互補(bǔ),可以既保證性能又保證準(zhǔn)確性。
- 在對后端請求的轉(zhuǎn)發(fā)上,使用 TCP 鏈路復(fù)用的方式,使得請求在轉(zhuǎn)發(fā)層面上猶如同一臺機(jī)器,大量的減少網(wǎng)絡(luò)交互。
- 對于后端服務(wù)的檢活,是用主動檢活加被動檢活相結(jié)合的方式,提高了對后端服務(wù)快速容錯的能力。
- 所有的規(guī)則配置通過 zookeeper 快速配置,可以實(shí)現(xiàn)線上配置實(shí)時(shí)生效的功能。
- 對于內(nèi)部組件 filter 層,使用的 go 1.8 支持的 plugin 的方式,通過線上動態(tài)打補(bǔ)丁的方式來支持新需求的功能增加。
- 整個 proxy 基本是無狀態(tài)的,對 zookeeper 部署上也考慮了多機(jī)房同步的方案,所以整個統(tǒng)一接入層也具備多機(jī)房部署能力。
- 支持修改請求的 HOST,統(tǒng)一接入層修改了請求的域名,但一些系統(tǒng)的 Apache 上針對原域名有配置,尤其是需要登錄的接口。
為應(yīng)對這一點(diǎn),支持在后臺配置請求的原始域名,proxy 轉(zhuǎn)發(fā)時(shí),HOST 的值為原始域名,這樣一來,請求就能正確的響應(yīng),并且原系統(tǒng)不需要修改服務(wù)器配置,對接入層無感知。
轉(zhuǎn)發(fā)規(guī)則動態(tài)配置
所有配置數(shù)據(jù)(轉(zhuǎn)發(fā)規(guī)則)存放在 zookeeper 上,支持動態(tài)配置,由后臺管理系統(tǒng)統(tǒng)一管理。
- 代理(proxy),代理機(jī)器在 zookeeper 注冊臨時(shí)節(jié)點(diǎn),如果代理機(jī)器與 zookeeper 的連接斷開,臨時(shí)節(jié)點(diǎn)自動刪除,利用臨時(shí)節(jié)點(diǎn)的特性檢活 proxy。
- 轉(zhuǎn)發(fā)規(guī)則(api),存放的是 url 的路由規(guī)則,如下圖,統(tǒng)一接入層根據(jù)url轉(zhuǎn)發(fā),將匹配 / mtspre /* 的請求,轉(zhuǎn)發(fā)到集群 mtspre,并且重寫轉(zhuǎn)發(fā)后的請求地址。
- 集群(cluster),存放每個集群的信息,集群中包含的服務(wù)器和轉(zhuǎn)發(fā)策略,支持隨機(jī)和哈希兩種方式。
- 服務(wù)器(server),存放所有服務(wù)器的信息,包括檢活周期和超時(shí)時(shí)間。
- 綁定關(guān)系(bind),存放集群和服務(wù)器的綁定關(guān)系。
proxy 代理層監(jiān)聽 zookeeper 的每一個節(jié)點(diǎn),一旦節(jié)點(diǎn)數(shù)據(jù)發(fā)生變化,可以實(shí)時(shí)的獲取***的配置,立即生效,改變請求的路由策略。
為了保證可靠性,應(yīng)對 zookeeper 所在的虛擬機(jī)宕機(jī),所有配置信息入庫,并且寫文件,極端情況下,proxy可以從文件中讀取配置信息,正常啟動。
協(xié)議
移動端發(fā)出的請求統(tǒng)一走 http2.0 協(xié)議,Android 端使用 okhttp 實(shí)現(xiàn),iOS 端使用 AFNetworking。
相比 HTTP/1.x,HTTP/2,系統(tǒng)在底層傳輸做了很大的改動和優(yōu)化:
- HTTP/2 采用二進(jìn)制格式傳輸數(shù)據(jù),而非 HTTP/1.x 的文本格式。
- HTTP/2 對消息頭采用 HPACK 進(jìn)行壓縮傳輸,能夠節(jié)省消息頭占用的網(wǎng)絡(luò)流量。而 HTTP/1.x 每次請求,都會攜帶大量冗余頭信息,浪費(fèi)了很多帶寬資源。
- 多路復(fù)用,直白的說就是所有的請求都是通過一個 TCP 連接并發(fā)完成。同時(shí),流還支持優(yōu)先級和流量控制。
- Server Push:服務(wù)端能夠更快的把資源推送給客戶端。例如服務(wù)端可以主動把 JS 和 CSS 文件推送給客戶端。
HTTP/2 主要是 HTTP/1.x 在底層傳輸機(jī)制上的完全重構(gòu),HTTP/2 是基本兼容 HTTP/1.x 的語義。Content-Type 仍然是 Content-Type,只不過它不再是文本傳輸了。
域名收斂
接入統(tǒng)一接入層后,客戶端使用到的域名都收斂成一個域名,域名后面的***個目錄,標(biāo)記了該請求所屬的系統(tǒng),即路由規(guī)則,程序員據(jù)此將請求轉(zhuǎn)發(fā)到不同的系統(tǒng)。客戶端收斂域名,不僅有效的減少***訪問的DNS解析次數(shù),最主要的是為了充分利用 http2.0 的特性——多路復(fù)用。
因?yàn)橹挥幸粋€域名,所有請求只需要建立一條連接即可發(fā)送完畢,大大減少等待時(shí)間,真正實(shí)現(xiàn)并發(fā)。如下圖所示的鏈路復(fù)用,只進(jìn)行了一次 ssl 握手(紫色部分),其他請求復(fù)用此鏈路,并且同時(shí)發(fā)出。
后端服務(wù)器檢活
做請求轉(zhuǎn)發(fā),檢查后端 server 的健康性非常重要,我們目前有兩套檢活方案,同時(shí)運(yùn)行。
(1)前臺代理層 proxy 被動檢活
proxy 向后端服務(wù)器轉(zhuǎn)發(fā)請求,如果返回失敗,則將這臺服務(wù)器的 checkFailCount 加1,checkFailCount 超過 3,就會將服務(wù)器標(biāo)記為 down,不再向它發(fā)起轉(zhuǎn)發(fā)請求。默認(rèn)檢活超時(shí)是 3s,3s 之內(nèi),后端 server 沒有再次返回失敗,將 checkFailCount 清零。
(2)后臺管理系統(tǒng)主動檢活
后臺主動檢活,在后臺管理系統(tǒng)啟動時(shí)便開始運(yùn)行,可以設(shè)置檢活周期和超時(shí)時(shí)間。檢活線程根據(jù)服務(wù)器的 IP 及端口號,主動與每一臺服務(wù)器建立 socket 連接,建立連接超時(shí)則認(rèn)為服務(wù)器不可用,將其狀態(tài)標(biāo)記為 down;成功建立連接,則將狀態(tài)標(biāo)記為 up。
前后主動、被動檢活的結(jié)合,保證了在服務(wù)器不可用的時(shí)候,停止向其轉(zhuǎn)發(fā)請求。同時(shí),在服務(wù)器重新可用時(shí),將其狀態(tài)標(biāo)記為up,前臺proxy可以繼續(xù)向其轉(zhuǎn)發(fā)請求。
開關(guān)
(1)降級開關(guān)
為了保證可靠性,統(tǒng)一接入層修改了原有的網(wǎng)絡(luò)鏈路,上線必須有降級開關(guān)。目前,我們設(shè)計(jì)了一套開關(guān),可以針對 APP 版本號,以及操作系統(tǒng)類型設(shè)置開關(guān)的狀態(tài)。
開關(guān)打開時(shí),將原域名轉(zhuǎn)換成收斂后的域名,請求走統(tǒng)一接入層;關(guān)閉開關(guān),域名恢復(fù)成原域名,請求不經(jīng)過統(tǒng)一接入層,直接走原鏈路,支持線上實(shí)時(shí)切換。
(2)協(xié)議轉(zhuǎn)換開關(guān)
http2.0 的應(yīng)用還在起步階段,目前網(wǎng)絡(luò)鏈路上存在一定的風(fēng)險(xiǎn),這是我們所不能接受的,為此設(shè)計(jì)了另外一套開關(guān),可以將協(xié)議在 http2.0 和 http1.1 之間切換,將風(fēng)險(xiǎn)降低到***。
統(tǒng)一接入層性能
系統(tǒng)性能
為了測試統(tǒng)一接入層的性能,能否達(dá)到上線要求。移動團(tuán)隊(duì)對蘇寧易購 APP 端的生產(chǎn)接口進(jìn)行了壓測,場景 1 是請求走原始鏈路,場景 2 是請求經(jīng)過統(tǒng)一接入層,壓測數(shù)據(jù)如下。
請求走原始鏈路,平均 tps 為 9130,平均響應(yīng)時(shí)間是 11 ms,通過統(tǒng)一接入層的請求,tps 達(dá)到 14200,提高了 50%,響應(yīng)時(shí)間 6ms,縮短了近一半。這得益于 go 語言的高性能,快速路由選擇算法,以及后端 tcp 連接的復(fù)用。
真實(shí)用戶數(shù)據(jù)采集
為了提高系統(tǒng)的訪問性能,也為了檢驗(yàn)統(tǒng)一接入層在實(shí)際生產(chǎn)環(huán)境中的表現(xiàn),我們將部分接口接入了統(tǒng)一接入層,運(yùn)行到生產(chǎn)環(huán)境中,經(jīng)過不間斷的監(jiān)控,我們采集到了真實(shí)的用戶數(shù)據(jù)。
未接入統(tǒng)一接入層的接口,請求數(shù)據(jù):
接入統(tǒng)一接入層的接口,請求數(shù)據(jù):
圖 1 為原始鏈路接口的 top99,71% 的請求平均響應(yīng)時(shí)間為 72ms,圖 2 是接入統(tǒng)一接入層的接口,域名收斂,協(xié)議走 http2.0,然后經(jīng)過系統(tǒng)的 proxy 轉(zhuǎn)發(fā),87% 的請求平均響應(yīng)時(shí)間為 62ms,top99 數(shù)據(jù)有明顯的提高。
結(jié)語
本文主要分享了統(tǒng)一接入層的技術(shù)實(shí)現(xiàn)方案和功能,利用 go 語言的快速、高效、高性能,搭上 http2.0 的快車,為用戶提供更好的購物體驗(yàn)。上線以來,通過 24 小時(shí)不間斷監(jiān)控和采集數(shù)據(jù),統(tǒng)一接入層功能穩(wěn)定,性能提升了 20% 左右,達(dá)到了我們的預(yù)期。
但是,目前統(tǒng)一接入層處于起步階段,移動團(tuán)隊(duì)最終的目標(biāo)是接入核心系統(tǒng) 80% 以上的請求,將移動端訪問性能提升 30% 以上。相信通過團(tuán)隊(duì)的共同努力,不斷創(chuàng)新,移動端性能還可以有更大的提升。
任良成
蘇寧云商 IT 總部架構(gòu)師
主要承擔(dān)蘇寧易購 https 改造,負(fù)責(zé)統(tǒng)一接入層上線,在網(wǎng)絡(luò)性能優(yōu)化方面有很深的思考和領(lǐng)悟,現(xiàn)正和研發(fā)團(tuán)隊(duì)一起建設(shè)統(tǒng)一接入層,持續(xù)優(yōu)化網(wǎng)關(guān)層,做出更高效穩(wěn)健的網(wǎng)關(guān)。
王一硼
蘇寧云商 IT 總部高級架構(gòu)師
擁有多年 IT 平臺研發(fā)和管理工作經(jīng)驗(yàn),先后在蘇寧,阿里,惠普等大型互聯(lián)網(wǎng)和 IT 企業(yè)工作,對 SOA 企業(yè)架構(gòu),高并發(fā)高可用的系統(tǒng)設(shè)計(jì)有多年的實(shí)戰(zhàn)經(jīng)驗(yàn),專注于分布式,高并發(fā),高性能/性能調(diào)優(yōu),架構(gòu)拆分和整合,大數(shù)據(jù)等技術(shù)領(lǐng)域。
【51CTO原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請注明原文作者和出處為51CTO.com】