億級流量架構演進實戰 - 從零構建億級流量 API 網關 01
這不是一個講概念的專欄,而且我也不擅長講概念,每一篇文章都是一個故事,我希望你可以通過這些故事瞭解我當時在實際工作中遇到問題和背後的思考,架構設計是種經驗,我有幸參與到多個億級系統的架構設計中,有所收穫的同時也希望把這些收穫分享與大家。
2013 年,我在做 APP 服務端的平臺化轉型,故事就從這裏開始。
在最開始做網關時,我並沒有一開始就明確說要做個 API 網關,而是做着做着發現這是個網關。因爲當時我是在做服務端的平臺化轉型,最開始時只是提供了客戶端登錄、獲取插件列表、插件啓動授權幾個簡單的 API,其中客戶端登錄是通過 RSA 和 AES 非對稱加密算法來實現,登錄之後平臺頒發 token 給客戶端,有了 token 之後,客戶端就通過 OAuth 2.0 協議來調用獲取插件列表、插件啓動授權等 API,不過由於最開始沒想清楚,提供出去的 API 接口定義和格式不統一,雖然都是 json 格式,但幾乎每個 API 都有自己的的格式定義,即每個 method 在服務端都實現了一個 Servlet 服務,客戶端天天是要這接口要那接口,搞了上百個接口還是被客戶端碾着走,更糟糕的是代碼越來越臃腫還老出問題。
後來就想爲何不把接口定義和格式統一了,就只提供一個 Serlvet 服務,通過解析 API 接口參數在後端進行服務的分發,這樣至少可以減少每個 API 都寫一遍 Servlet 的工作,當時的這個架構是 C/S 的架構,客戶端通過公網訪問彈內的服務器,這個功能上線其實是上線了一個新的 API,之後客戶端的新功能都必須使用新的 API,老的 API 在客戶端線上的版本逐步下線後,服務端再對老的 API 進行清理,當整個架構逐漸形成之後,服務端的開發效率得到了顯著的提升,也是這時,我覺得這其實是個網關的雛形,所以整個平臺演進的過程,在這一階段我總結爲:統一服務接口。
1。什麼是網關?
現在來談談 API 網關,關於 API 網關的定義,有很多的說法,其字面意思就是系統的統一 API 入口。說白了,就是將客戶端的所有請求統一通過 API 網關接入服務端,並完成認證、授權、安全、流控、熔斷、調度、轉發、監控等處理過程。API 網關的價值,就是爲實現更加安全、高效和穩定的 API 調用提供服務保障。
就我當時負責的平臺而言,統一了服務接口還不能說是做了一個網關,因爲這僅僅是實現了網關統一接入組件的一個點,那網關的統一接入組件又是什麼?下面我們先聊下網關的每一個組件,以及每一個組件的職責。
API 網關的核心組件
從 API 調用的過程來看,我把 API 網關劃分爲四個組件:
-
統一接入組件,管理所有的請求接入,負責認證鑑權、安全、校驗、限流、降級和熔斷等,它就像 API 網關的護城河;
-
服務調度組件,管理請求的路由和調度,負責協議解析、路由、轉換、映射和服務編排等,它是外部請求調度後端服務的中間樞紐,也是 API 網關的大腦(只有大腦才知道哪個 API 應去哪裏調度);
-
服務發佈組件,管理 API 的註冊和訂閱,負責服務發現、服務訂閱和服務更新等,它是 API 網關的心臟(心臟會不斷的把 API 信息同步給網關);
-
服務監控組件,是對所有 API 請求的統一監控,負責日誌、監控、告警和統計分析等,它是 API 網關的守衛。
這裏我畫了一張 API 網關的架構示意圖。
統一接入組件
當時,統一了服務接口的確實現了 API 的統一接入點,但很快也暴露出了新的問題 —— 這個接入點很快就過熱了,之前的登錄 API 和插件 API 都是分開的,現在統一後,有些 API 出故障後影響面很大,印象非常深刻的一次是客戶端上線了一個定時查詢待出庫訂單數的功能,結果整個服務端全面打爆,服務重啓很快又被打爆,這其實是統一之後服務端沒有及時跟上必要的限流、熔斷等防禦手段。
所以,那次之後,服務端進行了第一次的系統拆分 —— 網關和服務中心。
2。分層架構
平臺提供的所有端能力進行服務下沉,搭建服務中心新系統,原系統作爲網關將重點負責 API 接入、安全、流控、熔斷、路由、分發、調度、監控等功能。除了垂直拆分,還做了水平拆分,即對平臺 API 和業務 API 進行了隔離,簡單說,就是提供了兩個 Servlet。當時,還沒有微服務化的概念,只是想着隔離平臺調用與業務調用的相互影響,能解決當時的問題。後來,在認識了微服務之後,有一種後知後覺的感覺,這次系統的拆分使得平臺整體的穩定性得到很大的提升,不過後來玩微服務有點玩壞了,而這就是後話了。
重構之後的網關架構比較整潔,在實現上,統一接入組件採用的是類似於責任鏈的方式,由於這時期的 API 調用主要是 HTTP 請求,所以網關是基於 Servlet 來提供 API 服務的,通過攔截器進行安全、流控、熔斷等功能的實現。
其中 FrequencyPipe 是負責流控和熔斷的攔截器,這裏必須得說一下,畢竟是這裏栽了跟頭。常見的限流算法有漏斗算法和令牌桶算法,我的理解,令牌桶常用於控制併發,無論何時,令牌的總數是固定的,每次調用開始都需要申請,調用結束都需要釋放;漏桶適用於控制 QPS,漏桶可以在每秒生成 m 個令牌,每次調用開始都需要申請,但調用結束不需要釋放,不過問題就是如果上一秒的調用沒有結束,實際調用會大於當前生成的 m 個令牌控制的調用量。
在實現上,當時瞭解 Guava 的 RateLimiter 與 Semaphore 都可以實現,通過對比,網關使用的是 Guava 的 Semaphore 令牌桶策略來控制併發數,不過,遇到的問題就是每次重啓都會有瞬時的流量超過併發數。而在後來隨着微服務與網關越來越火,又有 Hystrix 或 Sentinel 提供了更強大的功能,比如 Hystrix 的線程熔斷和 Sentinel 的異常熔斷等等。
3。高可用架構
日誌的作用不言而言,網關的調用日誌是必不可少的。而且下定決心要做全鏈路的日誌,是已經被各種查問題逼的不勝其煩的情況下了,你能想象到的,尤其是莫名被拉到一個羣裏,被 @有個問題要查網關一次調用的一個參數對不對或有沒有,沒有個日誌服務平臺,不僅要親自操刀上陣,更悲催的是還只能去每臺服務器上去找日誌。
服務端在拆分了網關和服務中心之後,系統都開始往微服務架構的方向演進,一次 API 調用就需要有全局唯一的標識進行串聯,網關採用的是 UUID,在 API 每次調用時都會生成一個 UUID 傳遞給上游並返回給客戶端,這樣當有問題需要查詢時,就可以通過 UID 準確查找相關日誌了。
怎麼進行日誌的採集、查詢、統計,以及如何基於日誌實現監控告警?
通常來講,大多數系統打印日誌採用的是 Log4j,網關也是,再通過集團提供的日誌服務系統,比如 Scribe、Flume 等進行日誌採集,然後就可以在日誌系統或監控系統裏看到數據了。
不過,日誌採集看着簡單,做起來還是個技術活,網關的調用量本身是很大的,先不看記錄網關日誌會有多大的存儲量,關鍵點是看打印日誌會對網關性能有多大的影響。
首先談一下 Log4j,我們知道 Log4j 1.x 會引發線程 BLOCKED,所以 Log4j 1.x 不適合高併發的場景,解決方法一種是升級到 log4j2 或者更換爲 logback,另一種是通過設置 BufferedIO 或者使用 AsyncAppender 來緩解出現 BLOCKED 的概率。遺憾的是,網關採用的是後者,這主要是依賴衝突導致的,不過這只是做日誌採集裏的一個小點。
基於 MMap、Kafka、Storm、ElasticSearch 實現日誌服務平臺
除此之外,網關自己還實現了一套日誌服務系統,這主要是開放給平臺用戶的,當時集團的日誌系統還不對外開發,所以自己就又搞了一套。
當時技術選型沒有選擇 Scribe、Flume,而是自己基於 MMap 技術來實現,這也受限於服務器 agent 權限,所以,基本思路是通過 Kafka 進行日誌收集,然後 Storm 接收後寫到 ElasticSearch 提供服務查詢,這裏有個技術點,最開始寫日誌是直接發 Kafka,不過線上發現網絡的抖動會影響寫 Kafka 的 RT,後來,我們嘗試了 2 種方案,第一種是採用線程池異步寫,另一種是基於 MMap 技術將日誌先落盤,然後再異步的讀文件發 Kafka,相比之下,第二種方案更不會丟數據。
日誌打不好,找問題不僅抓瞎,弄不好系統還要撲街?
說到最後,也談談打日誌出的問題。
第一,throw Exception,這點尤其注意,微服務架構裏,如果服務提供方服務異常,一定不要將異常堆棧也傳給服務調用方,雖然通過異常信息可以快速定位問題,但異常信息會佔用大量的網絡資源,嚴重的就變成服務不可用了,這裏,我是有血的教訓的,所以,我推薦的方式是定義返回結果對象裏的返回值和錯誤碼。
基於多維度的限流熔斷策略,構建實時 API 成功率監控能力
上文說了全鏈路日誌和實時監控,本文就說下限流降級,這裏都是故事。網關係統,需要對調用 API 進行實時的性能監控和錯誤碼監控,由於是實時計算,所以採用了 NoSQL 來緩存數據,因爲是對 API 進行監控,所以將 API 接口名作爲緩存 Key,可當 API 調用異常猛增時,緩存熱定問題就出現了,很快就出現了 failover,然後服務不可用。所以,在處理數據時一定要考慮好數據熱點問題,無論是 NoSQL 還是 MySQL。
4。總結
言而總之,本篇文章重點講述了 API 網關的統一接入、分層架構、高可用架構。下篇文章,我將繼續介紹流量調度的配置中心、泛化調用。如果你覺得有收穫,歡迎你把今天的內容分享給更多的朋友。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/oCZDsHmAY0x22H7ZyURXBA