1. 程式人生 > >帶你認識一下“京東到家-網關係統”

帶你認識一下“京東到家-網關係統”

京東到家三週年活動已然結束,在這2年裡,我們的網關係統經歷過了618,1020,雙11,雙12,415等多個非常有意義的考試,回顧起來依舊讓人覺得很刺激,每次考前我們和市場部都做了大量的效果預估、壓測&擴容,但是活動當日依舊是驚心動魄,瞬時數以100倍的流量湧入(有成千上萬薅羊毛黨的入侵,有技術黑客的攪局,有友商的友情壓力測試,有通過全站push帶來的使用者同一時間瞬時訪問),閘道器作為後臺伺服器的第一道牆,如何站好這第一班崗呢?接下來帶你一起認識一下“京東到家-網關係統”

網關係統是什麼

京東到家提供給App端的HTTP介面有上千個,涉及到的系統也有上百個,大家都知道公網HTTP介面面臨著諸多的挑戰,我舉幾個例子:

  • 異常處理-已經剛剛發版的app中寫錯了一個後端的url,致使某項功能不能使用;
  • 版本控制-歷史上釋出的版本不再維護了需要強制下線或者強制升級; 流量控制-異常流量的識別與限流;
  • 登陸驗證-閘道器做統一的登陸與校驗;
  • 資料安全-介面資料互動時需要加密驗籤,保障使用者資料安全;
  • 流量控制-必要的時候進行限流對後端系統進行保護

上述功能如果每個系統都各自實現一套來說,時間人力成本都是不值當的,實現方式的差異性也會造成聯調時出現的種種奇葩問題,基於這樣的前提,京東到家孵化出了這個基礎平臺-網關係統應運而生,所有系統均需要做的基礎工作交由閘道器來處理,業務系統只關心自身業務邏輯就可以了。

閘道器一定需要麼

這是一個比較有爭議的話題,不過業界有一個共識,當系統達到一定量級時有一個基礎閘道器統一處理異常處理、資料安全、流量控制、版本控制會比較好,後端的業務系統只用關心自身業務邏輯就好了。閘道器其實就是業務系統的一個前置層,把一些業務系統需要處理的通用邏輯前置到閘道器,避免業務系統的重複開發,提高開發效率。

網關係統的架構

本文討論的環節為圖中的物理閘道器,整體架構如下
物理閘道器架構圖

資料處理流程如下
資料處理流程

京東到家的物理閘道器獨立部署,其最核心功能是請求的轉發,每一個請求進入到閘道器後都會經歷上面的處理流程。首先進行必要的引數校驗,校驗通過後,進行封版和引數防篡改驗證,上述校驗通過後,閘道器會通過傳過來的引數去配置中心獲取到後端的跳轉地址,如果能取到對應的轉發url,下一步閘道器做轉發前的最後校驗,包括登陸驗證,封流量校驗,防刷校驗,全部通過後,閘道器對進入的請求按照請求方式做POST或GET轉發。

訪問示例
http://gw.o2o.jd.com/client?functionId=productsearch/searchKey&body={%22key%22:%22asdf%22,%22pageSize%22:20}&appName=paidaojia&appVersion=1.3.0&channel=AppStore&deviceId=79516EBF-4DE6-4478-9521-F06B405A6F6E&deviceModel=iPhone&deviceToken=79516EBF-4DE6-4478-9521-F06B405A6F6E&networkType=wifi&partner=AppStore&platCode=IOS&platVersion=8.4&screen=1242*2208&signKey=7e995f08f403fa84c3e0b6c7c6e13631

必傳引數解釋說明
body={},app請求後端系統的業務引數,閘道器不解析,不更改。
deviceId=,裝置id,標示裝置的唯一標識。
functionId=為方法ID,閘道器會通過配置系統配置這個functionID指向到後端set化的叢集域名
signKey=7e995f08f403fa84c3e0b6c7c6e13631,是防篡改簽名,閘道器會對其做校驗,每個app對應的Md5key值是不一樣的。
appName=pdj,有了appName引數,這樣一套閘道器就可以支援多個app了
appVersion=4.2,必傳,代表應用的版本號。
deviceToken=**,必傳,作為傳送訊息的唯一標識。
platCode=ios,標示是ios還是安卓 。
channel=AppStore
deviceModel=iphone
networkType=wifi,代表網路型別。
partner=AppStore,推廣渠道。
screen=尺寸。

值得一提的設計細節
1) 錯誤碼定義
為什麼特別強調一下這個問題呢,現在都是SOA架構,系統與系統間的關係愈來愈複雜,使用者看到的一個頁面可能由後端10個或者更多的系統支撐著,任何一個系統出現問題,都會影響到使用者頁面的展示,那麼如何保障出現問題時,快速定位是哪個系統哪個介面的問題呢,錯誤碼格式:系統代號+介面代號+錯誤情況代號

錯誤碼示例
APP提示語(使用者看到的) 真實的錯誤原因
網路繁忙,請稍後再試[000000] httpstatus非302,404,500,502
網路繁忙,請稍後再試[000011] 請求後端服務超5s read time out
網路繁忙,請稍後再試[000044] 請求後端返回httpstatus:404
網路繁忙,請稍後再試[000050] 請求後端返回httpstatus:500
網路繁忙,請稍後再試[000052] 請求後端返回httpstatus:502
網路繁忙,請稍後再試[000090] 加密驗證未通過
網路繁忙,請稍後再試[000091] 請求方式不對
網路繁忙,請稍後再試[000092] 未配置functionId
網路繁忙,請稍後再試[000093] functionId當前版本沒有配置url

2) 閘道器與配置中心的互動
閘道器functionId與後端系統url的對應關係全部儲存在配置中心(也是一個應用,獨立部署),為了最大限度提高配置中心的可用性和訪問速度問題,配置中心的配置資訊在閘道器機器啟動時就會全量載入到閘道器jvm記憶體中,之後如果配置中心的配置新增或者修改,我們採用zookeeper的通知機制來更新jvm記憶體中的配置資訊。

3) 日誌查詢
日誌對於一個系統來說,重要性不容忽視,線上的突發問題定位、日常的問題排查、責任定位都需要用到,但作為日PV過億的系統,很多系統都會因效能考慮不提供日誌,其實我不是太贊成這一思路的,首先效能的問題應該是想辦法解決效能,不能因為採集了日誌,結果影響了效能,基於這樣的大前提,我們的日誌採用了Log4j2(官方號稱比Log4j效能提升了10倍),配合動態開關來控制列印日誌的級別,可以在一些特殊情況下控制日誌的輸出。
另外一個知識點就是現在我們的應用伺服器通常有幾個或者幾十個,日誌的集中化管理與關鍵字檢索查詢也顯得非常麻煩,目前京東到家使用了業界比較成熟的ELK技術(ELK由ElasticSearch、Logstash和Kiabana三個開源工具組成)

4) 高可用保證
京東到家網關係統的日常現狀(其中X>1,Y>1)
PV:X億/日
峰值:Y十萬/分鐘
作為一個億級PV的系統,每秒鐘都會有上千次的訪問,保證系統的高可用呢?比如說可能會遇到網路、硬體、軟體的故障,或者程式自身的升級,如何最小化的降低對使用者的感知呢
網路故障,京東到家所有公網域名都是分運營商(移動、聯通、電信、香港)進行設定DNS的,任何一家運營商的網路出現問題都可以快速切換到其它運營商
硬體故障,首先我們伺服器通過前置HAProxy+Nginx雙層架構,閘道器伺服器水平擴容便無後顧之憂,另外採用同機房多伺服器+擴機房混合部署,防止伺服器或者機房故障
程序升級,程序升級有多方面的原因,比如新功能上線或者修復bug,我們如何避免由於程序升級過程中造成的訪問波動呢,這個也是SoEasy的,前面提到HAProxy,這裡會維護一個VIP與後端伺服器的對映關係,每次上線前可以通過VIP控制檯進行摘掉一部分機器待無流量後再進行上線升級操作,待這部分正常啟動後重新再掛到VIP上,並對外提供服務,依次完成剩餘的一部分機器即可,當然了,由於需要修改系統引數、程式引數造成的程式重啟也可以腫採取該策略。

截流

限流

網關係統,我們正在做?
持續優化,優化每個請求在閘道器的耗時,在閘道器轉發請求到後端時,需要做比較多的校驗,且需要和外部的會話中心和防刷系統等互動,後續優化儘量降低對外部系統的強依賴,能非同步化的非同步化。也可適當優化tomcat引數(IO->NIO->AIO),提高響應速度。
風控對接,單純從技術手段有些攻擊手段是無法徹底解決的,頂多是可以增加攻擊的成本的複雜度,比如暴力破解、社會工程學等,我們目前逐步與風控系統資料對接,風控系統有一套非常強大的使用者識別體系,集合了使用者,裝置,瀏覽,訂單,優惠,支付等環節的資料,對風險使用者進行星級打分,最終實現閘道器與風控的資料共享利用。
優化日誌,方便問題查詢,統一日誌的輸出格式,增加類似traceId的欄位,通過這一欄位可以看到每一個請求在閘道器的完整的呼叫日誌鏈,方便問題定位與查詢。
完善監控,增加依賴的核心繫統的監控,及閘道器機器效能的監控,防止網路或者機器的原因導致閘道器可用率降低

截流限流的思路
2. 多個賬號,一次性發送多個請求
很多公司的賬號註冊功能,在發展早期幾乎是沒有限制的,很容易就可以註冊很多個賬號。因此,也導致了出現了一些特殊的工作室,通過編寫自動註冊指令碼,積累了一大批“殭屍賬號”,數量龐大,幾萬甚至幾十萬的賬號不等,專門做各種刷的行為(這就是微博中的“殭屍粉“的來源)。舉個例子,例如微博中有轉發抽獎的活動,如果我們使用幾萬個“殭屍號”去混進去轉發,這樣就可以大大提升我們中獎的概率。
這種賬號,使用在秒殺和搶購裡,也是同一個道理。例如,iPhone官網的搶購,火車票黃牛黨。

應對方案:
這種場景,可以通過檢測指定機器IP請求頻率就可以解決,如果發現某個IP請求頻率很高,可以給它彈出一個驗證碼或者直接禁止它的請求:
1. 彈出驗證碼,最核心的追求,就是分辨出真實使用者。因此,大家可能經常發現,網站彈出的驗證碼,有些是“鬼神亂舞”的樣子,有時讓我們根本無法看清。他們這樣做的原因,其實也是為了讓驗證碼的圖片不被輕易識別,因為強大的“自動指令碼”可以通過圖片識別裡面的字元,然後讓指令碼自動填寫驗證碼。實際上,有一些非常創新的驗證碼,效果會比較好,例如給你一個簡單問題讓你回答,或者讓你完成某些簡單操作(例如百度貼吧的驗證碼)。
2. 直接禁止IP,實際上是有些粗暴的,因為有些真實使用者的網路場景恰好是同一出口IP的,可能會有“誤傷“。但是這一個做法簡單高效,根據實際場景使用可以獲得很好的效果。
3. 多個賬號,不同IP傳送不同請求
所謂道高一尺,魔高一丈。有進攻,就會有防守,永不休止。這些“工作室”,發現你對單機IP請求頻率有控制之後,他們也針對這種場景,想出了他們的“新進攻方案”,就是不斷改變IP。

有同學會好奇,這些隨機IP服務怎麼來的。有一些是某些機構自己佔據一批獨立IP,然後做成一個隨機代理IP的服務,有償提供給這些“工作室”使用。還有一些更為黑暗一點的,就是通過木馬黑掉普通使用者的電腦,這個木馬也不破壞使用者電腦的正常運作,只做一件事情,就是轉發IP包,普通使用者的電腦被變成了IP代理出口。通過這種做法,黑客就拿到了大量的獨立IP,然後搭建為隨機IP服務,就是為了掙錢。
應對方案:
說實話,這種場景下的請求,和真實使用者的行為,已經基本相同了,想做分辨很困難。再做進一步的限制很容易“誤傷“真實使用者,這個時候,通常只能通過設定業務門檻高來限制這種請求了,或者通過賬號行為的”資料探勘“來提前清理掉它們。
殭屍賬號也還是有一些共同特徵的,例如賬號很可能屬於同一個號碼段甚至是連號的,活躍度不高,等級低,資料不全等等。根據這些特點,適當設定參與門檻,例如限制參與秒殺的賬號等級。通過這些業務手段,也是可以過濾掉一些殭屍號。

心靈寄語:唯有認真對待每一次考試,方能臨陣不亂