波司登云原生微服務(wù)治理探索
01
背景
Aliware
波司登創(chuàng)始于1976年,專注于羽絨服的研發(fā)、設(shè)計(jì)、制作,是全球知名的羽絨服生產(chǎn)商。波司登用一系列世人矚目的輝煌成績(jī)證明了自己的實(shí)力:連續(xù)26年全國(guó)銷量領(lǐng)先,連續(xù)22年代表中國(guó)向世界發(fā)布防寒服流行趨勢(shì),產(chǎn)品暢銷美國(guó)、法國(guó)、意大利等72個(gè)國(guó)家,全球超過2億用戶。作為羽絨服革命的旗手,波司登引領(lǐng)了行業(yè)內(nèi)的“三次革命”。
在產(chǎn)品力和銷售成績(jī)單背后,波司登在生產(chǎn)、倉(cāng)儲(chǔ)、物流、銷售各環(huán)節(jié)已完成數(shù)字化轉(zhuǎn)型和創(chuàng)新改造。除生產(chǎn)端的智能生產(chǎn)工廠,波司登對(duì)倉(cāng)儲(chǔ)和物流環(huán)節(jié)也進(jìn)行智能化改造,提升小單快反、拉式補(bǔ)貨的比重,最大限度減少困擾服裝企業(yè)多時(shí)的“庫(kù)存”問題;為了精準(zhǔn)分發(fā)銷售端產(chǎn)品,波司登建立數(shù)據(jù)中臺(tái),打通全渠道數(shù)據(jù),賦能消費(fèi)者研究、商品企劃、渠道匹配等?,F(xiàn)在,波司登每件羽絨服從生產(chǎn)到抵達(dá)消費(fèi)者,背后都是一段數(shù)字之旅。 02
云原生技術(shù)發(fā)展
Aliware
隨著波司登數(shù)字業(yè)務(wù)的飛速發(fā)展,背后的 IT 技術(shù)也在不斷更新迭代。波司登極為重視客戶對(duì)服務(wù)的體驗(yàn),并將系統(tǒng)穩(wěn)定性、業(yè)務(wù)功能的迭代效率、問題的快速定位和解決視為構(gòu)建核心競(jìng)爭(zhēng)力的基石。服飾行業(yè)會(huì)積極參與各大電商平臺(tái)的促銷活動(dòng),業(yè)務(wù)流量的波峰波谷現(xiàn)象明顯,如果由于資源分配不合理導(dǎo)致高峰時(shí)期訂單溢出、運(yùn)力不足,會(huì)極大影響顧客和商家的體驗(yàn)。此外,波司登自研了用戶運(yùn)營(yíng)平臺(tái)(用戶洞察系統(tǒng)、內(nèi)容管理系統(tǒng)、用戶管理 CRM 系統(tǒng)及用戶小程序)、零售運(yùn)營(yíng)平臺(tái)(線上平臺(tái)訂單管理 OMS 系統(tǒng)、線下渠道管理系統(tǒng)、門店收銀 POS 系統(tǒng))、商品運(yùn)營(yíng)平臺(tái)(訂單處理中心 OPC、庫(kù)存計(jì)算中心 ICC、商品訂貨系統(tǒng)、商品運(yùn)營(yíng) iMOS 系統(tǒng)、采購(gòu)制造 GiMS 系統(tǒng)、物流管理 EWM 系統(tǒng)、機(jī)器人調(diào)度 WCS 系統(tǒng)) 等諸多垂直業(yè)務(wù)功能,在市場(chǎng)需求的快速變化下,產(chǎn)品功能創(chuàng)新和迭代效率問題也是對(duì)技術(shù)架構(gòu)的一大挑戰(zhàn)。 這些現(xiàn)狀的解法和云原生架構(gòu)帶來的核心能力不謀而合,在波司登系統(tǒng)改造上云的過程中,CIO 戴建國(guó)親自帶隊(duì),圍繞著云原生技術(shù)體系,推動(dòng)波司登的各條業(yè)務(wù)線進(jìn)行技術(shù)升級(jí)改造,加快數(shù)智化發(fā)展進(jìn)程。在技術(shù)選型上,波司登始終遵循著2條原則:
全面擁抱開源開放的主流技術(shù)標(biāo)準(zhǔn)。 使用開源開放的主流技術(shù)標(biāo)準(zhǔn)可以確保技術(shù)方案的成熟度,更便捷的從開發(fā)者社區(qū)獲取技術(shù)資源和最佳實(shí)踐,也能夠幫助企業(yè)更好的招募技術(shù)人才。此外,這樣的策略也避免了被封閉技術(shù)體系和特定云廠商所捆綁。
盡可能利用云計(jì)算的價(jià)值。 將穩(wěn)定性保障、底層技術(shù)實(shí)現(xiàn)、技術(shù)組件維護(hù)、彈性伸縮等非功能性需求盡可能交給云廠商解決,讓技術(shù)團(tuán)隊(duì)將更多的精力投入到業(yè)務(wù)創(chuàng)新上。這2個(gè)原則并不矛盾,相反,它們之前可以非常好的融合,是所有使用云計(jì)算的企業(yè)用戶都值得借鑒的架構(gòu)選型標(biāo)準(zhǔn)。比如 Kubernetes 就是典型的滿足開源開放標(biāo)準(zhǔn)的技術(shù)標(biāo)準(zhǔn),阿里云提供的 Kubernetes 產(chǎn)品可以簡(jiǎn)化用戶的搭建成本,更好的與云計(jì)算資源進(jìn)行集成。同時(shí)用戶依然可以基于開源 Kuberntes 的標(biāo)準(zhǔn)協(xié)議與 API 使用云產(chǎn)品,這就是2條選型原則相互融合的最好體現(xiàn)。
03
容器化改造
Aliware
云原生趨勢(shì)下,Kubernetes 毫無疑問已經(jīng)成為了企業(yè)新一代云 IT 架構(gòu)的基礎(chǔ)設(shè)施。從2021年開始,波司登就開啟了微服務(wù)和容器化改造計(jì)劃,將 IT 系統(tǒng)的底座逐步從虛擬機(jī)遷移到 Kubernetes。 在 Kubernetes 平臺(tái)的選擇上,基于技術(shù)選型的2條原則,波司登選擇了阿里云容器服務(wù) ACK 。ACK 以阿里云可靠穩(wěn)定的 IaaS 平臺(tái)為底座,向下封裝了 30+ 款云產(chǎn)品,形成了自動(dòng)化運(yùn)維和云平臺(tái)交互的新界面,從而提升企業(yè)業(yè)務(wù)系統(tǒng)的彈性和自動(dòng)化運(yùn)維能力。
基于容器服務(wù) ACK 的易用性以及集成能力,波司登IT系統(tǒng)容器化改造工作比預(yù)想中的要順利得多。對(duì)于每一個(gè)業(yè)務(wù)系統(tǒng)而言,從虛擬機(jī)遷移到 Kubernetes ,僅僅是底層的承載發(fā)生了變化,不會(huì)涉及到太多的改造成本。在關(guān)鍵的容器網(wǎng)絡(luò)實(shí)現(xiàn)上,容器服務(wù) ACK 通過云原生 Terway 網(wǎng)絡(luò)模式,直接基于阿里云的虛擬化網(wǎng)絡(luò)中的彈性網(wǎng)卡資源來構(gòu)建的容器網(wǎng)絡(luò),將容器和虛擬機(jī)納入同一層網(wǎng)絡(luò)中,便于業(yè)務(wù)云原生化遷移。這樣完全可以對(duì)傳統(tǒng)架構(gòu)實(shí)現(xiàn)漸近式容器化改造,在不中斷業(yè)務(wù)的前提下一點(diǎn)一點(diǎn)的從虛擬機(jī)往 Kuberntes 上搬。在容器化改造的過程中,當(dāng)波司登技術(shù)團(tuán)隊(duì)遇到疑難問題的時(shí)候,可以第一時(shí)間從阿里云獲得最佳實(shí)踐指導(dǎo),包括集群規(guī)劃、平臺(tái)運(yùn)維、應(yīng)用適配、安全防護(hù)、可觀測(cè)等多個(gè)方面,這也更進(jìn)一步的提升了容器化改造的速度。
目前,波司登的自研系統(tǒng)已經(jīng) 100% 基于 Kubernetes。相比傳統(tǒng)的基于虛擬機(jī)部署方式,
容器化幫助波司登在資源利用率上提升了30%,在運(yùn)維效率上提升了40%。
波司登的技術(shù)團(tuán)隊(duì)也在容器化改造的過程中,掌握了管理超大規(guī)模Kubernetes集群的能力,并促成了更多云原生新技術(shù)的運(yùn)用。
04
統(tǒng)一微服務(wù)架構(gòu)
Aliware
與容器化改造幾乎同步進(jìn)行的是對(duì)微服務(wù)架構(gòu)的統(tǒng)一。在此之前,波司登的各個(gè)業(yè)務(wù)單元多種技術(shù)棧并存,彼此之間相互通訊復(fù)雜度高,項(xiàng)目成員的交接往往要耗費(fèi)巨大的精力,極大程度上阻礙了數(shù)字化轉(zhuǎn)型的進(jìn)展,因此微服務(wù)架構(gòu)統(tǒng)一勢(shì)在必行。在 CIO 戴建國(guó)的帶領(lǐng)下,波司登經(jīng)歷了1年多時(shí)間完成了這一項(xiàng)艱巨的工作,雖然投入精力巨大,但收益是立桿見影的,而且可以持續(xù)發(fā)揮作用:不論是內(nèi)部團(tuán)隊(duì)還是三方 ISV ,在技術(shù)框架上都有統(tǒng)一的標(biāo)準(zhǔn)可以遵循,各團(tuán)隊(duì)共享技術(shù)棧后,研發(fā)效率成倍提升。 關(guān)系到未來多年的 IT 戰(zhàn)略,在微服務(wù)架構(gòu)的選型上,高開放性、高成熟度、高普及度這三條標(biāo)準(zhǔn)缺一不可,考慮到波司登以 Java 為主要開發(fā)語言,Spring Cloud Alibaba就成為了微服務(wù)框架的最佳選擇。
Spring Cloud Alibaba 致力于提供微服務(wù)開發(fā)的一站式解決方案,包含開發(fā)分布式應(yīng)用微服務(wù)的必需組件,方便開發(fā)者通過 Spring Cloud 編程模型輕松使用這些組件來開發(fā)分布式應(yīng)用服務(wù)。這些組件一部分以 SDK 的形式集成到代碼中,一部分以中間件的形式獨(dú)立運(yùn)行,后者往往可以選擇托管版云產(chǎn)品,以降低開發(fā)者的工作量。比如阿里云微服務(wù)引擎 MSE 就提升了開箱即用的注冊(cè)配置中心 Nacos,以及云原生網(wǎng)關(guān)。
05
微服務(wù)架構(gòu)的挑戰(zhàn)
Aliware
微服務(wù)對(duì)單體架構(gòu)進(jìn)行了拆分,不同模塊之間通過網(wǎng)絡(luò)進(jìn)行通訊,本質(zhì)上來講,這并沒有降低系統(tǒng)的復(fù)雜度,反而讓系統(tǒng)復(fù)雜度大幅度提升,在管理難度上也為開發(fā)者提出了更高的挑戰(zhàn)。隨著微服務(wù)架構(gòu)的深入使用,波司登技術(shù)團(tuán)隊(duì)遇到了2個(gè)難題:
性能問題定位困難 。 隨著業(yè)務(wù)規(guī)模的增長(zhǎng),對(duì)于每一個(gè)來自用戶的請(qǐng)求,鏈路變得越來越長(zhǎng),這也代表著應(yīng)用之間的調(diào)用關(guān)系變得越來越復(fù)雜。傳統(tǒng)的依賴于單機(jī)業(yè)務(wù)日志的監(jiān)控手段根本無從下手,這就需要建立全新的鏈路跟蹤機(jī)制,幫助開發(fā)者全面洞察系統(tǒng)運(yùn)行狀態(tài),并在系統(tǒng)遇到異常的時(shí)候快速的定位和解決問題。這個(gè)挑戰(zhàn)相對(duì)比較容易解決,阿里云的 ARMS 應(yīng)用監(jiān)控提供了無侵入式方案實(shí)現(xiàn)微服務(wù)鏈路跟蹤,在易用性、功能性、穩(wěn)定性上都有突出的表現(xiàn)。波司登把部署在容器服務(wù) ACK 的微服務(wù)應(yīng)用一鍵接入 ARMS 應(yīng)用監(jiān)控后,接下來要做的事情就主要是熟練掌握工具,并配合 Promethues/Grafana 實(shí)現(xiàn)統(tǒng)一大盤,并利用報(bào)警平臺(tái)實(shí)現(xiàn)事件閉環(huán),ARMS 也通過開箱即用的方式在云上提供了相關(guān)工具。
應(yīng)用變更頻繁造成事故 。 為了適應(yīng)互聯(lián)網(wǎng)業(yè)務(wù)需求的不斷變化,應(yīng)用變更在大型微服務(wù)架構(gòu)中,是極為頻繁的工作。新應(yīng)用的上線、新版本的發(fā)布、新配置的推送、應(yīng)用擴(kuò)容、應(yīng)用縮容,這些都屬于應(yīng)用變更的范疇。微服務(wù)架構(gòu)的復(fù)雜性以及業(yè)務(wù)的快速迭代,讓波司登的技術(shù)團(tuán)隊(duì)在每次應(yīng)用變更中都疲憊不堪,因?yàn)榻^大多數(shù)生產(chǎn)環(huán)境的事故都由應(yīng)用變更導(dǎo)致。這個(gè)難題不能簡(jiǎn)單靠云產(chǎn)品來解決,需要技術(shù)團(tuán)隊(duì)深入剖析每一次事故的根因,針對(duì)性的進(jìn)行優(yōu)化,并建立一整套安全變更的行政機(jī)制,確保每一次變更都能讓團(tuán)隊(duì)高枕無憂。第2個(gè)難題屬于微服務(wù)治理的范疇,微服務(wù)治理是微服務(wù)化深入的必經(jīng)之路,涵蓋流量治理、服務(wù)容錯(cuò)、安全治理等多個(gè)領(lǐng)域,幫助更低成本、更穩(wěn)定、更高效地開發(fā),運(yùn)維微服務(wù)應(yīng)用。在波司登的實(shí)戰(zhàn)經(jīng)驗(yàn)中,上下線有損問題和安全變更問題造成的業(yè)務(wù)影響最大,波司登的技術(shù)團(tuán)隊(duì)圍繞著這幾個(gè)問題進(jìn)行了深入探索。
06
下線有損問題
Aliware
微服務(wù)化之后,有一個(gè)問題長(zhǎng)期困擾著波司登的技術(shù)團(tuán)隊(duì):每次有應(yīng)用下線的時(shí)候,都會(huì)導(dǎo)致一部分前端用戶的請(qǐng)求失敗。應(yīng)用縮容和版本更新這2種情況都會(huì)產(chǎn)生應(yīng)用主動(dòng)下線行為,這兩種情況對(duì)于波司登的業(yè)務(wù)系統(tǒng)都是每天都要執(zhí)行的日常工作。為了盡可能的保障用戶體驗(yàn),波司登最先考慮的是讓版本更新都在用戶量相對(duì)比較少的凌晨進(jìn)行,以縮小問題的影響面,但這其實(shí)并不能太好的解決問題。一方面,為了提升資源利用率,應(yīng)用縮容基本上發(fā)生在白天;另一方面,凌晨進(jìn)行版本變更加重了 IT 團(tuán)隊(duì)的負(fù)擔(dān),若是遇到了新版本的 bug,也不利于團(tuán)隊(duì)進(jìn)行保障,始終不是長(zhǎng)久之計(jì)。因此還是要從根本上找到問題的原因,通過技術(shù)方式解決問題。 我們通過下面這個(gè)圖看一下微服務(wù)節(jié)點(diǎn)下線的正常流程

-
下線前,消費(fèi)者根據(jù)負(fù)載均衡規(guī)則調(diào)用服務(wù)提供者,業(yè)務(wù)正常。
-
服務(wù)提供者節(jié)點(diǎn) A 準(zhǔn)備下線,先對(duì)其中的一個(gè)節(jié)點(diǎn)進(jìn)行操作,首先是觸發(fā)停止 Java 進(jìn)程信號(hào)。
-
節(jié)點(diǎn)停止過程中,服務(wù)提供者節(jié)點(diǎn)會(huì)向注冊(cè)中心發(fā)送服務(wù)節(jié)點(diǎn)注銷的動(dòng)作。
-
服務(wù)注冊(cè)中心接收到服務(wù)提供者節(jié)點(diǎn)列表變更的信號(hào)后會(huì),通知消費(fèi)者服務(wù)提供者列表中的節(jié)點(diǎn)已下線。
-
服務(wù)消費(fèi)者收到新的服務(wù)提供者節(jié)點(diǎn)列表后,會(huì)刷新客戶端的地址列表緩存,然后基于新的地址列表重新計(jì)算路由與負(fù)載均衡。
- 最終,服務(wù)消費(fèi)者不再調(diào)用已經(jīng)下線的節(jié)點(diǎn)。
看似無懈可擊的邏輯,但在微服務(wù)系統(tǒng)的實(shí)際運(yùn)行過程中,會(huì)存在一些微妙的差別。其本質(zhì)在于,從服務(wù)提供者確認(rèn)下線,到服務(wù)消費(fèi)者感知到服務(wù)提供者下線之間,存在時(shí)間差,這個(gè)時(shí)間差就是導(dǎo)致服務(wù)調(diào)用失敗的窗口期。比如 Spring Cloud 使用的 Ribbon 負(fù)載均衡默認(rèn)的地址緩存刷新時(shí)間是 30 秒一次,那么意味著即使服務(wù)消費(fèi)者實(shí)時(shí)地從注冊(cè)中心獲取到下線節(jié)點(diǎn)的信號(hào)在負(fù)載均衡的地址緩存沒有刷新前,依舊會(huì)有一段時(shí)間會(huì)將請(qǐng)求發(fā)送至老的服務(wù)提供者中。
了解到下線有損問題的本質(zhì)后,波司登技術(shù)團(tuán)隊(duì)嘗試對(duì)微服務(wù)應(yīng)用進(jìn)行了一些改造。對(duì)所有的微服務(wù)應(yīng)該都增加一個(gè)向外暴露的 /offline 接口,并把對(duì)這個(gè)接口的調(diào)用加入到 Kubernetes 的 Prestop 腳本中,這樣可以在 /offline 接口中加入服務(wù)注銷相關(guān)的邏輯。/offline 接口要實(shí)現(xiàn)的第一件事情是主動(dòng)從注冊(cè)中心下線,這件事很好做,只需要一段代碼,但這并不夠,因?yàn)榉?wù)的消費(fèi)者依然需要在一段時(shí)間后才能從注冊(cè)中心感知到這個(gè)事情。所以 /offline 接口還要實(shí)現(xiàn)主動(dòng)通知服務(wù)消費(fèi)方的邏輯,而這件事情在 Spring Cloud 框架中實(shí)現(xiàn)起來要復(fù)雜一些,因?yàn)闆]有 channel 模型,服務(wù)提供方還不能真正實(shí)現(xiàn)主動(dòng)通知服務(wù)消費(fèi)方的需求,只能通過間接的方式實(shí)現(xiàn)。在請(qǐng)求的 Response Header 中帶上 ReadOnly 標(biāo)簽,服務(wù)消費(fèi)者收到 ReadOnly 標(biāo)簽后,會(huì)主動(dòng)刷新負(fù)載均衡緩存,保證不再有新的請(qǐng)求訪問下線過程中的服務(wù)提供者。這其中會(huì)存在少量的漏網(wǎng)之魚,也就說明,依然有少量請(qǐng)求會(huì)失敗。
此外,在下線的過程中,還有一部分請(qǐng)求屬于在途請(qǐng)求:服務(wù)提供方已經(jīng)收到了請(qǐng)求,但還沒有處理完成。要徹底解決下線有損的問題,需要服務(wù)提供者端等待所有在途請(qǐng)求處理都完成之后,再完成下線動(dòng)作。具體等多久,這個(gè)時(shí)間是不確定的,所以漏網(wǎng)之魚始終存在,問題并沒有完全解決。
由于 /offline 接口的實(shí)現(xiàn)需要侵入代碼,而收效又有限,最終沒有能夠在波司登大面積推廣,這樣就只能繼續(xù)從業(yè)務(wù)上容忍下線有損問題了。
07
上線有損問題
Aliware
與下線有損問題相對(duì)應(yīng)的是上線有損問題,擴(kuò)容、應(yīng)用新版本發(fā)布、Pod 重新調(diào)度都會(huì)產(chǎn)生應(yīng)用上線行為,相比下線有損問題,上線有損問題很容易被忽視,這是因?yàn)樯暇€有損問題只有在高并發(fā)大流量的場(chǎng)景中才會(huì)暴露出來,其中最典型的場(chǎng)景就是高峰期的應(yīng)用彈性伸縮。 互聯(lián)網(wǎng)應(yīng)用的用戶流量存在明顯的波峰波谷,波司登也積極參與大促類營(yíng)銷活動(dòng)來提升品牌曝光度,高峰期的應(yīng)用彈性伸縮是一項(xiàng)常規(guī)技術(shù)手段。但波司登的技術(shù)團(tuán)隊(duì)發(fā)現(xiàn)應(yīng)用彈性伸縮所達(dá)到的效果往往不及預(yù)期,其具體的表現(xiàn)是新擴(kuò)容出來的應(yīng)用實(shí)例在啟動(dòng)后會(huì)有3-5分鐘左右的性能瓶頸期,在這一段時(shí)間內(nèi),會(huì)造成部分用戶訪問延遲劇增,在極端大流量場(chǎng)景下甚至拖垮了整個(gè)應(yīng)用的性能,存在雪崩效應(yīng)的風(fēng)險(xiǎn)。 通過排查,波司登研發(fā)團(tuán)隊(duì)找到了應(yīng)用上線后存在性能瓶頸期的多個(gè)原因:
異步連接資源阻塞 。在 jstack 日志中,發(fā)現(xiàn)不少線程阻塞在 taril/druid 等異步連接資源準(zhǔn)備上,這是因?yàn)閼?yīng)用實(shí)例啟動(dòng)后,數(shù)據(jù)庫(kù)與 Redis 連接池中的連接未提前建立的情況下,就會(huì)接收來自上游的流量負(fù)載,從而導(dǎo)致大量線程阻塞在連接的建立上,在大流量場(chǎng)景下性能問題會(huì)更加突出。解決問題的思路是預(yù)建數(shù)據(jù)庫(kù)連接等異步建連邏輯,保證在業(yè)務(wù)流量進(jìn)來之前,異步連接資源一切就緒。
ASMClassLoader 類加載器阻塞 。由于 ClassLoader 加載類的代碼其默認(rèn)是同步類加載,在高并發(fā)場(chǎng)景下會(huì)有大量線程阻塞在 fastjson 的 ASMClassLoader 類加載器加載類的過程中,從而影響服務(wù)端性能,造成線程池滿等問題。解決的思路是類加載器被加載前開啟其并行類加載的能力。
JVM JIT 編譯引起 CPU 飆升 。當(dāng)虛擬機(jī)發(fā)現(xiàn)某個(gè)方法或代碼塊運(yùn)行特別頻繁時(shí),就會(huì)把這些代碼認(rèn)定為熱點(diǎn)代碼,為了提高熱點(diǎn)代碼的執(zhí)行效率,在運(yùn)行時(shí),虛擬機(jī)將會(huì)把這些代碼編譯成與本地平臺(tái)相關(guān)的機(jī)器碼,并進(jìn)行各層次的優(yōu)化。這是 JVM 提升性能的重要技術(shù)手段,但JIT編譯本身會(huì)消耗大量計(jì)算資源,造成編譯期間的 CPU 使用率飆升。解決這個(gè)問題最好的方式是小流量預(yù)熱,讓 Java 應(yīng)用在啟動(dòng)后可以先接收少部分流量,達(dá)到觸發(fā) JIT 編譯的條件,在編譯完成之后再接收正常的業(yè)務(wù)流量。
日志同步打印導(dǎo)致線程阻塞等其它問題 。 通過應(yīng)用代碼優(yōu)化實(shí)現(xiàn)無損上線,并不是一件簡(jiǎn)單的事情,需要植入大量非功能性邏輯。特別在小流量預(yù)熱這項(xiàng)技術(shù)上,需要讓所有上游應(yīng)用感知到應(yīng)用上線的事件后,動(dòng)態(tài)調(diào)整負(fù)載均衡規(guī)則,改造工作量極大。因此波司登的技術(shù)團(tuán)隊(duì)并沒有自行從代碼層實(shí)現(xiàn)無損上線,而是往無代碼侵入的方向?qū)ふ覠o損上線的最優(yōu)解。 08
安全變更問題
Aliware
隨著波司登微服務(wù)架構(gòu)的不斷演進(jìn),系統(tǒng)支持的業(yè)務(wù)也越來越復(fù)雜,與此同時(shí),業(yè)務(wù)的迭代速度也發(fā)生了翻天覆地的變化。在進(jìn)行微服務(wù)改造之前,新版本發(fā)布的頻度是以月為單位,這跟現(xiàn)在每周有多個(gè)應(yīng)用需要發(fā)布新版本的情況完全不在一個(gè)數(shù)量級(jí)。在經(jīng)歷了多次新版本發(fā)布導(dǎo)致的生產(chǎn)事故之后,波司登的技術(shù)團(tuán)隊(duì)吸取了之前的教訓(xùn),參考阿里巴巴的安全變更經(jīng)驗(yàn),提出了安全變更”可灰度、可監(jiān)控、可回滾“的原則,這就對(duì)波司登技術(shù)團(tuán)隊(duì)的變更管理提出了更高的要求。特別是在灰度策略上,簡(jiǎn)單的應(yīng)用滾動(dòng)更新不能控制業(yè)務(wù)流量通往新版本的比例,不能夠滿足安全變更的要求,需要有更高階的灰度技術(shù)來支撐。 為了實(shí)現(xiàn)灰度過程中的路由可控,波司登最初采取的方式是通過物理隔離的方式構(gòu)建2套環(huán)境,每套環(huán)境都包含了全部的微服務(wù)應(yīng)用,以及 Message Queue、Redis 等其他中間件。通過前置的網(wǎng)關(guān)層實(shí)現(xiàn)流量路由,決定用戶的流量發(fā)送到正式環(huán)境還是灰度環(huán)境,路由的規(guī)則可以基于流量特征進(jìn)行匹配,也可以設(shè)置為百分比。
這套架構(gòu)搭建完成之后,是能夠非常好的勝任安全變更原則的,每次有新版本發(fā)布的時(shí)候,都可以基于可控的流量進(jìn)行小規(guī)模驗(yàn)證。通過充分的驗(yàn)證之后再?zèng)Q定是否放大進(jìn)入新版本的流量比例,或者及時(shí)回滾。
但隨著物理隔離方案的推廣,其局限性也越來越明顯的暴露出來。首先這樣的架構(gòu)存在嚴(yán)重的資源浪費(fèi)問題,雖然可以盡可能利用云計(jì)算的彈性能力適配流量規(guī)模,但也只是降低了一部分資源,不能從根本上解決資源浪費(fèi)的問題。而且需要用到的中間件產(chǎn)品往往不能像微服務(wù)應(yīng)用一樣靈活的彈性伸縮。
此外,更重要的問題在于隔離方案需要整條業(yè)務(wù)線甚至全公司統(tǒng)一版本發(fā)布節(jié)奏,因?yàn)榇蠹抑挥幸惶坠蚕淼幕叶拳h(huán)境。微服務(wù)架構(gòu)的規(guī)模越大,團(tuán)隊(duì)之間的分工會(huì)越明確,每個(gè)團(tuán)隊(duì)所負(fù)責(zé)的微服務(wù)應(yīng)用在整個(gè)微服務(wù)架構(gòu)中所占的比重也就越小。這樣的方案在多團(tuán)隊(duì)協(xié)同作戰(zhàn)的時(shí)候,極難協(xié)調(diào)多個(gè)團(tuán)隊(duì)的版本發(fā)布節(jié)奏,實(shí)際上嚴(yán)重拖慢了業(yè)務(wù)系統(tǒng)的創(chuàng)新迭代速度。
因?yàn)槲锢砀綦x方案在實(shí)際生產(chǎn)中的局限性,業(yè)界更為推崇的是邏輯隔離方案。當(dāng)需要對(duì)某一個(gè)微服務(wù)應(yīng)用發(fā)布版本的時(shí)候,可以獨(dú)立部署灰度版本,通過調(diào)用鏈路上的流量控制使得灰度流量能在灰度環(huán)境和正式環(huán)境間流轉(zhuǎn),實(shí)現(xiàn)灰度微服務(wù)應(yīng)用的正常運(yùn)行,幫助業(yè)務(wù)方進(jìn)行新功能驗(yàn)證。邏輯隔離方案不需要做整套環(huán)境的冗余,大量節(jié)省了資源成本。更為關(guān)鍵的是,邏輯隔離方案可以讓不同的團(tuán)隊(duì)各自決定自己的灰度節(jié)奏,并不需要所有團(tuán)隊(duì)都在同一個(gè)容器期進(jìn)行灰度驗(yàn)證。這樣不僅可以大幅度提升業(yè)務(wù)系統(tǒng)創(chuàng)新迭代速度,還能更進(jìn)一步降低變更所帶來的風(fēng)險(xiǎn),因?yàn)槁氊?zé)分享以后,每個(gè)團(tuán)隊(duì)都可以擁有更長(zhǎng)的灰度窗口期,灰度驗(yàn)證過程中遇到了問題也能更精確的定位到責(zé)任方。
然而邏輯隔離的技術(shù)實(shí)現(xiàn)極為復(fù)雜,物理隔離方案僅需要在網(wǎng)關(guān)層控制路由策略,而邏輯隔離需要每一個(gè)微服務(wù)應(yīng)用都必備識(shí)別灰度標(biāo)識(shí)并動(dòng)態(tài)控制路由策略的能力。在 Spring Cloud 框架下,微服務(wù)應(yīng)用之間相互調(diào)用的負(fù)載均衡機(jī)制由 Ribbon 實(shí)現(xiàn),實(shí)際上屬于應(yīng)用層 SDK 的能力范圍。動(dòng)態(tài)控制路由策略相當(dāng)于動(dòng)態(tài)控制 Ribbon 的負(fù)載均衡策略,改造起來會(huì)有比較大的工作量。
邏輯隔離機(jī)制更為復(fù)雜的技術(shù)實(shí)現(xiàn)在于灰度標(biāo)識(shí)的全鏈路透?jìng)?,也就是針?duì)每一個(gè)用戶請(qǐng)求,如果在微服務(wù)應(yīng)用間流轉(zhuǎn)的過程中被打上了灰度標(biāo)識(shí),這個(gè)灰度標(biāo)識(shí)就必須在接下來的鏈路中一直傳遞下去。比如上圖 B 服務(wù)的灰度服務(wù)在調(diào)用 C 服務(wù)的時(shí)候,因?yàn)?C 服務(wù)并沒有灰度版本,所以加到了 C 服務(wù)的穩(wěn)定版本,但接下來的 D 服務(wù)是同時(shí)存在穩(wěn)定版本和灰度版本的。這里就存在一個(gè)潛在的需求:凡是經(jīng)過了服務(wù) B 灰度服務(wù)的流量,都應(yīng)該發(fā)往服務(wù) D 的灰度版本。這個(gè)需求能夠?qū)崿F(xiàn)的必要條件,就是灰度標(biāo)識(shí)的全鏈路透?jìng)鳌?/span>
微服務(wù)應(yīng)用之間的灰度標(biāo)識(shí)全鏈路透?jìng)骺梢越柚?ARMS 等鏈路監(jiān)控工具而實(shí)現(xiàn),存在一定的代碼改造工作量。但更為復(fù)雜的是,如果鏈路中存在基于消息中間件的異步調(diào)用,就不能僅僅通過調(diào)整應(yīng)用層的負(fù)載均衡機(jī)制來控制路由策略了,需要對(duì)消息中間件的服務(wù)端和客戶端都進(jìn)行適配,存在大量改造工作量。跟無損上線一樣,波司登的技術(shù)團(tuán)隊(duì)也沒有急于求成對(duì)應(yīng)用層代碼進(jìn)行大刀闊斧的改造,而是與阿里云團(tuán)隊(duì)共同探討更優(yōu)雅的解決方案。
09
MSE 微服務(wù)治理方案
Aliware
微服務(wù)引擎 MSE 是阿里云面向業(yè)界主流微服務(wù)生態(tài)提供的一站式微服務(wù)平臺(tái),包括注冊(cè)配置中心、云原生網(wǎng)關(guān)和微服務(wù)治理3款可以獨(dú)立輸出的產(chǎn)品。對(duì)于注冊(cè)配置中心和云原生網(wǎng)關(guān),波司登已經(jīng)比較熟悉了,分別為微服務(wù)架構(gòu)提供了 Nacos 以及 Kubernetes Ingress 服務(wù)。關(guān)于第3款產(chǎn)品微服務(wù)治理,波司登的技術(shù)團(tuán)隊(duì)有過深入的研究,對(duì)于解決安全變更領(lǐng)域的多個(gè)難題都能帶來幫助,但對(duì)于微服務(wù)應(yīng)用全面接入 MSE 微服務(wù)治理,波司登還是存在一些顧慮。
主要的顧慮點(diǎn)集中在技術(shù)改造復(fù)雜度、侵入性、穩(wěn)定性等方面,波司登的技術(shù)團(tuán)隊(duì)與阿里云的專家團(tuán)隊(duì)經(jīng)過深入的溝通,對(duì)所有潛在風(fēng)險(xiǎn)點(diǎn)逐一進(jìn)行了評(píng)估。經(jīng)過大量的預(yù)研后,波司登決定將微服務(wù)應(yīng)用全面接入MSE微服務(wù)治理。這個(gè)方案除了在功能層面能夠滿足波司登微服務(wù)治理的需求之外,波司登的技術(shù)團(tuán)隊(duì)更看中的是這幾個(gè)方面的特性:
無侵入。 MSE 微服務(wù)治理能力基于 Java Agent 字節(jié)碼增強(qiáng)的技術(shù)實(shí)現(xiàn),無縫支持市面上近5年的所有 Spring Cloud 的版本。研發(fā)團(tuán)隊(duì)不用改一行代碼就可以使用,甚至在研發(fā)階段都不需要考慮應(yīng)用部署的時(shí)候是否接入 MSE 微服務(wù)治理,讓研發(fā)團(tuán)隊(duì)更聚焦于業(yè)務(wù)的創(chuàng)新。這是一個(gè)非常重要的特性,體現(xiàn)了這套方案的開放度,也能確保方案不會(huì)有廠商鎖定問題。
接入簡(jiǎn)單。 用戶只需在阿里云容器的應(yīng)用市場(chǎng)安裝 pilot 組件,就可以通過 MSE 控制臺(tái)對(duì)一個(gè)命名空間的所有 Java 應(yīng)用開啟治理功能,這個(gè)時(shí)候 pilot 組件會(huì)自動(dòng)為 Java 應(yīng)用所在的 Pod 注入 Agent 。當(dāng)然,更通用的方式是通過 Kubernetes 的聲明式描述,來控制每個(gè)應(yīng)用是否開啟治理功能,也就是對(duì) Pod 的 yaml 文件加上一行注解,這樣能更方便的和 CI/CD 工具集成。當(dāng)然關(guān)閉服務(wù)治理功能也是非常容易的,只需在控制臺(tái)關(guān)閉服務(wù)治理,或者修改 yaml 文件上的注解就行,不需要改變業(yè)務(wù)的現(xiàn)有架構(gòu),根據(jù)需要隨啟隨停。
高穩(wěn)定性。 同時(shí)服務(wù)于阿里集巴的內(nèi)部應(yīng)該以及多個(gè)外部客戶,經(jīng)過了大規(guī)模實(shí)戰(zhàn)驗(yàn)證。
可觀測(cè)能力。 提供完整的流量可視化視圖,支持全局看板、網(wǎng)關(guān)實(shí)例監(jiān)控、日志檢索、業(yè)務(wù) TOP 榜、日志投遞、以及報(bào)警管理等功能。能夠幫助用戶直接的了解到微服務(wù)治理能力開啟后產(chǎn)生的效果,更全面的了解微服務(wù)應(yīng)用的運(yùn)行狀態(tài)。
支持混合云場(chǎng)景。 不論是在線下 IDC,還是其他云上部署的微服務(wù)系統(tǒng),只要網(wǎng)絡(luò)可以通,也能夠享受到治理能力的增強(qiáng),用法保持一致。
擁抱云原生。 與 Kubernetes 體系完美集成,無損上下線使得應(yīng)用在彈性伸縮的過程中保持流量無損,通過 Jenkins 構(gòu)建 CI/CD 實(shí)現(xiàn)在 Kubernetes 環(huán)境下的金絲雀發(fā)布,基于 Ingress 實(shí)現(xiàn)全鏈路灰度等。
10
無損下線
Aliware
MSE 實(shí)現(xiàn)無損下線的原理很簡(jiǎn)單,流程如下:
當(dāng)一個(gè)微服務(wù)應(yīng)用實(shí)例接收到下線指令后,紅色字段標(biāo)識(shí)的3個(gè)步驟由 Agent 自動(dòng)實(shí)現(xiàn)
從注冊(cè)中心下線。 這一步執(zhí)行完之后,服務(wù)的所有消費(fèi)者有機(jī)會(huì)從注冊(cè)中心感知到下線行為,但在 Spring Cloud 體系中,這個(gè)感知存在時(shí)間差,并不能立即通知所有消費(fèi)者,所以我們不能單純依賴這個(gè)步驟實(shí)現(xiàn)無損下線。
主動(dòng)通知所有消費(fèi)者。 這是最為關(guān)鍵的一步,Agent 繞過注冊(cè)中心,直接給所有消費(fèi)者發(fā)送了實(shí)例下線的通知,這樣消費(fèi)方能夠立即感知到下線行為。
消息者更新負(fù)載均衡。 收到實(shí)例下線通知后,服務(wù)的消費(fèi)方將下線的實(shí)例從負(fù)載均衡實(shí)例列表中移除,從而不再發(fā)請(qǐng)求到下線的實(shí)例。這幾個(gè)步驟都完成以后,收到下線指令的應(yīng)用實(shí)例才會(huì)在處理完所有在途請(qǐng)求的情況下,進(jìn)入真正的下線狀態(tài)。所以整個(gè)過程不會(huì)有任何一次服務(wù)請(qǐng)求失敗的情況發(fā)生。這項(xiàng)技術(shù)不需要修改任何一行代碼,就能在版本更新或應(yīng)用縮容的時(shí)候提升用戶體驗(yàn),增加微服務(wù)系統(tǒng)的穩(wěn)定性。
如果一個(gè)微服務(wù)應(yīng)用處在鏈路的入口位置,通過 Ingress 暴露給用戶,這個(gè)時(shí)候并不存在掛上了 Agent 的服務(wù)消費(fèi)者應(yīng)用,無損下線機(jī)制還能正常工作嗎?答案是肯定的,如果 Ingress 這一層是由 MSE 云原生網(wǎng)關(guān)實(shí)現(xiàn)的,所有的適配工作都已經(jīng)完成,無損下線機(jī)制依然可以完美運(yùn)行。 11
無損上線
Aliware
MSE 實(shí)現(xiàn)無損上線也是基于類似的原理:
-
微服務(wù)消費(fèi)者可以快速感知微服務(wù)提供方的上下線事件
- Agent 可以動(dòng)態(tài)更新微服務(wù)消費(fèi)方的負(fù)載均衡規(guī)則
因此,用戶可以為每一個(gè)微服務(wù)消費(fèi)者配置一定時(shí)長(zhǎng)的預(yù)熱窗口期,比如2分鐘。在這一段時(shí)間內(nèi),如果感知服務(wù)提供方的實(shí)例新上線,就在窗口期通過小流量對(duì)新上線的實(shí)例進(jìn)行預(yù)熱,并逐步增量流量規(guī)模,直到窗口期結(jié)束后恢復(fù)正常的流量比例,這樣就可以規(guī)避 Java 應(yīng)用啟動(dòng)初期所存在的性能問題。
完整的流程如下:
不論是無損上線還是無損下線,都通過從 MSE 的控制臺(tái)清晰的觀察到微服務(wù)治理帶來的效果。

全鏈路流量治理
Aliware
通過 MSE 微服務(wù)治理,長(zhǎng)期困擾波司登的安全變更問題得到了解決,因?yàn)椴ㄋ镜且恢痹谧非蟮倪壿嫺綦x灰度方案可以通過 Agent 技術(shù)輕松實(shí)現(xiàn)。為了實(shí)現(xiàn)邏輯隔離灰度,可以先從金絲雀發(fā)布開始入手,金絲雀發(fā)布在業(yè)界有廣泛的使用,是應(yīng)用版本更新的常用灰度手段。金絲雀發(fā)布會(huì)對(duì)流量進(jìn)行比例分割,一開始為新版本的實(shí)例分配較小比例的流量,經(jīng)過一段時(shí)間的運(yùn)行,確認(rèn)新版本運(yùn)行正常后再逐步提高所分配流量的比例,直到最終全量切流。通過這種方式做發(fā)布可以在新版本出現(xiàn)問題時(shí)控制影響面,提高系統(tǒng)的穩(wěn)定性。 金絲雀發(fā)布通常通過流量染色和版本打標(biāo)來實(shí)現(xiàn)。在 MSE 的實(shí)現(xiàn)中,流量染色可以通過識(shí)別流量特征而實(shí)現(xiàn),在下圖的例子中,可以通過 HTTP Header 里面的具體字段來決定一個(gè)請(qǐng)求是否進(jìn)行灰度染色。而版本打標(biāo)是利用 Kubernetes 的聲明式部署實(shí)現(xiàn)的,通過在 Pod 上添加 Annotation ,可以讓對(duì)應(yīng)的版本打上灰度標(biāo)識(shí)。這樣就可以限制只有被染過色的流量才會(huì)進(jìn)入打上了灰度標(biāo)識(shí)的版本,從而實(shí)現(xiàn)新版本業(yè)務(wù)的小規(guī)模驗(yàn)證,一旦發(fā)現(xiàn)新版本存在任何問題,可以及時(shí)回滾,把對(duì)業(yè)務(wù)的影響降至最低。
金絲雀發(fā)布最終會(huì)演變成全鏈路流量治理能力,從而真正實(shí)現(xiàn)基于邏輯隔離機(jī)制的高階灰度方案。對(duì)于穿梭在微服務(wù)鏈路上的流量,一旦被染色,就能將染色信息傳遞到整條鏈路。這個(gè)機(jī)制和泳道非常類似,微服務(wù)在同一時(shí)間點(diǎn)可能存在多個(gè)并存的業(yè)務(wù)版本,每條泳道象征著一個(gè)業(yè)務(wù)版本,只有經(jīng)過染色的流量,才會(huì)進(jìn)入到對(duì)應(yīng)泳道中。
波司登經(jīng)過半年時(shí)間的實(shí)戰(zhàn)探索,在 MSE 微服務(wù)治理的幫助下,最終駕馭了大規(guī)模微服務(wù)架構(gòu)的全鏈路流量治理能力,并形成了成熟的流程機(jī)制,通過全鏈路流量治理對(duì)每一次應(yīng)用變更進(jìn)行充分的灰度驗(yàn)證。有了這項(xiàng)技術(shù)之后,每個(gè)團(tuán)隊(duì)都可以靈活的決定應(yīng)用變更的時(shí)間周期,但對(duì)于安全變更的要求變得更高了,一旦造成了生產(chǎn)事故,在行政上會(huì)有更嚴(yán)厲處罰措施。因此需要每個(gè)團(tuán)隊(duì)在實(shí)施應(yīng)用變更的時(shí)候,都通過全鏈路流量治理確保穩(wěn)定性,這樣即使新版本存在漏洞,對(duì)于整體業(yè)務(wù)的影響也能控制在極低的范圍內(nèi)。這項(xiàng)技術(shù)被各團(tuán)隊(duì)廣泛采納后,
波司登的業(yè)務(wù)迭代頻率實(shí)現(xiàn)了2倍以上的提升,因?yàn)閼?yīng)用變更導(dǎo)致的生產(chǎn)事故降低了 70% 以上。
13
全鏈路穩(wěn)定性治理
Aliware
另一個(gè)被波司登廣泛使用的微服務(wù)治理能力是全鏈路穩(wěn)定性治理,對(duì)于波司登這樣需要頻繁舉辦線上運(yùn)營(yíng)活動(dòng)的企業(yè),全鏈路穩(wěn)定性治理是非常重要的技術(shù)。MSE 提供的全鏈路穩(wěn)定性治理,在流量防護(hù)方面形成可拓展閉環(huán),能夠通過故障識(shí)別模型發(fā)現(xiàn)不同層次的問題,如接口層的狀態(tài)碼與異常類型、操作系統(tǒng)層的指標(biāo)異常。在識(shí)別出問題后,發(fā)出異常告警,方便用戶進(jìn)行針對(duì)性的流量治理,如進(jìn)行自適應(yīng)限流防護(hù)或場(chǎng)景化限流防護(hù);防護(hù)規(guī)則設(shè)置后,系統(tǒng)便按照預(yù)設(shè)的閾值與防護(hù)手段保護(hù)系統(tǒng),而系統(tǒng)防護(hù)的效果可通過監(jiān)控查看,另一方面,也可通過監(jiān)控反向?qū)徱暳髁糠雷o(hù)規(guī)則設(shè)置的合理性,及時(shí)調(diào)整。
對(duì)于防護(hù)策略以及防護(hù)規(guī)則的設(shè)定,波登司主要通過全鏈路壓測(cè)獲得參考。波司登通過阿里云 PTS 模擬用戶流量,對(duì)系統(tǒng)進(jìn)行了多次全鏈路壓測(cè)。在壓測(cè)的過程中不斷優(yōu)化微服務(wù)架構(gòu)各個(gè)環(huán)境的容量配比,確定系統(tǒng)在真實(shí)業(yè)務(wù)中表現(xiàn)出來的系統(tǒng)上限,同時(shí)也確定在大流量場(chǎng)景下需要使用到的流量防護(hù)策略。為了更進(jìn)一步提升微服務(wù)系統(tǒng)在高并發(fā)大流量場(chǎng)景的性能,并提升資源利用率,波司登還充分利用了 ACK 集群的彈性伸縮能力,在業(yè)務(wù)高峰期讓應(yīng)用和集群資源同時(shí)實(shí)現(xiàn)自動(dòng)水平擴(kuò)擴(kuò)展,并在業(yè)務(wù)高峰期自動(dòng)回收資源。
除了在業(yè)界廣泛運(yùn)用的單機(jī)流控手段(包括并發(fā)控制、自適應(yīng)防護(hù)、熔斷、主動(dòng)降級(jí)、熱點(diǎn)防護(hù)等一系列技術(shù))和網(wǎng)關(guān)流控手段之外,波司登還深入使用了MSE提供的數(shù)據(jù)庫(kù)治理能力,特別是基于 SQL 的流控、降級(jí)、容錯(cuò),避免嚴(yán)重的慢 SQL 發(fā)生后拖垮整個(gè)數(shù)據(jù)庫(kù),對(duì)線上業(yè)務(wù)產(chǎn)生阻斷性的風(fēng)險(xiǎn)。
在全鏈路穩(wěn)定性治理和彈性伸縮的幫助下,再加上頁(yè)面靜態(tài)化、請(qǐng)求攔截、數(shù)據(jù)隔離、異步處理等常規(guī)技術(shù)手段,波司登已經(jīng)建立起在秒殺業(yè)務(wù)場(chǎng)景中支撐百萬級(jí)并發(fā)量的技術(shù)能力,并確保雙11活動(dòng)過程系統(tǒng)的穩(wěn)定運(yùn)行。
14
總結(jié)
Aliware
技術(shù)能力的不斷進(jìn)步,幫助波司登使用數(shù)字化手段對(duì)業(yè)務(wù)進(jìn)行不斷創(chuàng)新,并取得了一系列重要的戰(zhàn)果。數(shù)字化能力的提升也直接體現(xiàn)在銷量與利潤(rùn)上,波司登在羽絨服的銷售額和銷售量上都登上了全球第一,連續(xù)5年實(shí)現(xiàn)了營(yíng)收與利潤(rùn)的雙位數(shù)增長(zhǎng)。波司登的技術(shù)團(tuán)隊(duì)在云原生微服務(wù)治理方面的不斷探索,讓他們?cè)诔笠?guī)模微服務(wù)架構(gòu)領(lǐng)域沉淀寶貴經(jīng)驗(yàn),但這只是支撐業(yè)務(wù)高速發(fā)展所經(jīng)歷的多項(xiàng)技術(shù)變革中的一個(gè)重要組成部分。波司登會(huì)繼續(xù)擁抱云計(jì)算,通過更先進(jìn)、更高效的技術(shù),更數(shù)字化的運(yùn)營(yíng)方式,引領(lǐng)服飾行業(yè)激發(fā)創(chuàng)新活力,與各行各業(yè)的時(shí)代變革者共同成長(zhǎng)。
推薦閱讀:
掘地三尺搞定 Redis 與 MySQL 數(shù)據(jù)一致性問題
再有人問你什么是分庫(kù)分表,直接把這篇文章發(fā)給他
后端思維篇:如何應(yīng)用設(shè)計(jì)模式優(yōu)化代碼
后端思想篇:設(shè)計(jì)好接口的36個(gè)錦囊!
歡迎關(guān)注微信公眾號(hào): 互聯(lián)網(wǎng)全棧架構(gòu) ,收取更多有價(jià)值的信息。
