近日,個推服務端技術專家李白受邀參與SegmentFault D-Day 線上技術直播活動,與來自頭部網際網路企業的後端技術專家們共探 “後端架構演進之路”。李白以“API閘道器演進之路”為主題,分享了個推基於golang進行API閘道器建設的實踐經驗和深度思考。
★以下為李白演講乾貨整理:
API閘道器之源起
API閘道器是隨“微服務”概念而興起的一種架構模式。在微服務拆分過程中,原本龐大的單體應用和業務系統被拆分成許多微服務系統進行獨立維護和部署,導致API規模成倍增長,API治理難度日益增加;同時,子系統通過API對外提供能力時,還會存在通用能力重複建設的問題。因此,使用API閘道器統一發布和管理API逐漸成為一種架構趨勢。
在個推,公司的訊息推送、金融風控等業務核心系統均是基於微服務架構,部分系統也存在自建的閘道器模組。隨著不同系統之間的依賴越來越多,高效進行介面治理的需求日益迫切。因此,個推很早就引入了統一的API閘道器,來解決許可權控制、流控、服務降級、灰度釋出、版本管理等一系列問題。
1、個推早期API閘道器
2015年,SpringCloud的誕生極大促進了微服務架構的發展和流行。個推也是在這一時期,依賴於SpringCloud gateway構建了自己真正意義上的API閘道器。
SpringCloud在生態上比較友好,有很多可以開箱即用的監控和容錯元件,但因為不支援流量和安全治理,所以無法很好地滿足後續公司進行API治理的需求;尤其是個推後來建設資料中臺,更亟需一個統一的API閘道器來承擔資料中臺的入口流量。此外,在開發語言上,SpringCloud只支援Java,適用性有限;且存在效能不理想、運維難度大等不足。
因此,為了實現更強大的API治理能力、簡化接入和運維方式,同時也為了更好地適應公司資料中臺建設需求,個推選擇自研API閘道器。
2、個推自研API閘道器
2.1 自研目標
個推建設API閘道器的幾個關鍵目標:
✦ 1) 要能夠對API完整生命週期進行統一治理
比如,在API設計上,要統一規範,規定API必須有歸屬服務和標籤,做到API設計上的隔離;設計完成後要能夠直接除錯,自動生成測試程式碼;釋出時,對API流量要做到精細化控制,支援服務的灰度釋出;在API執行過程中,要能夠對API呼叫情況進行全方位的監控和告警,對出現問題的服務能夠及時地熔斷隔離;下線後能夠及時回收資源。
✦ 2)需要有完善的功能元件,來處理再一次請求過程
在整個請求鏈路中,我們設計實現了鏈路追蹤、日誌、鑑權、限流、熔斷、外掛等一系列核心功能。
✦3)保證“三高”的同時,使用者遷移和接入要簡單
這一點其實是說API閘道器要便於運維和使用,同時要提供各種指標檢測功能,且支援自動容錯和彈性擴容。
2.2 技術選型
基於以上的目標設計和技術調研之後,我們選擇將golang作為自研API閘道器的主力開發語言。之所以選擇golang,有以下幾個原因:
✦ 1)個推在做多機房容災建設和資料拆分遷移過程中,設計了gproxy-codis和gproxy-es,並已經搭建了一套proxy叢集來路由不同的使用者。這些proxy到目前為止執行良好,一些大的叢集單機QPS超過6W。在這些專案的開發過程中,我們積累了不少的開發經驗和基礎元件,裡面的很多輪子都是可以直接複用的。因此,我們使用golang並基於現有的這些元件,開發一套gproxy-http就相對省力得多。
✦ 2)golang語言本身天然支援高併發,開發速度快,最重要是節省機器成本。
✦ 3 )golang作為雲原生框架使用最多的語言,golang上的技術沉澱也是為個推雲原生建設鋪路。
2.3 設計與實現
確認目標和技術選型之後,接下來就是一些具體的設計與實現。
✦ 1) 整體架構
個推API閘道器的整體架構設計,如圖所示:
首先是一個Web管理平臺,API的建立、釋出和後續管理都可在管理平臺上配置完成;配置完成後,會下發到配置中心通知到閘道器,同時閘道器也會定時拉取全量的API配置;然後是閘道器的一些核心元件,比如外掛引擎,主要是執行配置的一些外掛。轉發引擎也是API閘道器的核心模組,個推的轉發引擎支援http、grpc,同時還有個推自研的gcf協議,而在資料中臺的業務場景下,也支援了kafka的資料推送能力。
✦ 2) 外掛服務
從圖中可以看到,個推API閘道器整體架構裡有一個獨立的外掛服務。這個設計的核心原因是golang是類C語言,打包後是可執行檔案,而golang的原生外掛是直接編譯好的,不支援更新和解除安裝,所以也不能在介面上直接新增和更新外掛。基於此原因,我們使用Java開發了一個外掛服務,利用Java動態的語言特性,以靈活地支援外掛的新增、更新和解除安裝。
閘道器通過grpc與外掛服務通訊,效能上有一定損耗。為了儘可能減少效能的損耗,我們把加密、特定的序列化相關外掛都使用golang的一個原生外掛去實現,一些業務自定義比較強的元件則推薦使用Java外掛服務。
✦ 3) 資源隔離
資源隔離是實現系統高可用的常用手段,在隔離設計上主要有叢集和執行緒池的隔離。
API閘道器主要支援服務叢集隔離,通過這種叢集級別的隔離,在上層可以支援多租戶,如果再徹底一點,在LB層面可以把閘道器叢集也隔離出去。另外,服務的灰度釋出也是通過閘道器這種叢集隔離來實現的。具體過程是,在升級時,使用者可以在介面上配置流量轉發規則和叢集,通過流量回放,將部分測試流量匯入到灰度叢集,或把線上真實流量按比例轉發給灰度叢集,確保沒有問題後再全量釋出。
執行緒的隔離主要體現在資料服務,主要功能是把資料API化,也就是在介面通過簡單的配置就可以把MySQL、ES、Hbase的資料通過API提供出去,不用開發人員動手寫CRUD或者客戶端程式碼,非常方便。目前個推資料中臺業務場景的大部分流量都是請求資料服務,因此我們設計了普通執行緒池、慢執行緒池和自定義配置的執行緒池等三類執行緒池。當請求時長超過慢閾值後,介面會被分配到慢執行緒池處理,避免慢請求拖垮整個服務。
✦ 4) 服務編排
服務編排也是API閘道器需要滿足的一個常見需求,主要是將多個API做聚合呼叫,大幅降低呼叫延遲。這部分功能之前是在閘道器上的,在閘道器層面支援的服務編排相對來說較為基礎,能夠支撐API的併發聚合呼叫,但難以處理複雜的業務組合,特別是涉及到事務的編排場景。因此,我們決定將這部分功能,抽取出去做獨立服務,而後續的鏈路閘道器會直接訪問服務編排模組,這樣也保證了閘道器整體相對輕量。
✦ 5) 效能優化
針對API閘道器效能,我們也做了一系列壓測和優化,比如,使用開源函式代替或重寫內部大量使用的序列化、加解密等函式;大量使用Sync.Pool複用物件,對其內部邏輯進行純非同步處理;自研gnet,替換原生net框架,對網路模型進行優化等。從線上實際執行結果來看,目前個推資料中臺中的API平臺每天呼叫量超過10億次,單機QPS峰值在2W左右,整體效能損耗在10%+,效能表現超過預期。
✦ 6) 易用性設計
通過上述外掛機制、隔離手段和效能上的極致優化,我們確保建設的API閘道器平臺整體是高可用且易擴充套件的。而平臺做好以後,還要方便使用者接入使用和運維。
因此,為了提升易用性,我們採用純Web的介面設計,並內建了多個API模板。使用者通過簡單的配置,就可以建立一個API,例如介面授權有效期、QPS、限額等許可權配置,都能通過視覺化介面操作完成;建立好API之後,使用者還可以直接在介面上除錯。
同時,在對外提供API的場景下,使用者可以批量匯出某個服務下的API文件,非常方便。個推API平臺還實現了監控和統計的功能,比如提供API被呼叫的趨勢、整個服務下API呼叫量和錯誤統計等資料,對運營和研發人員比較友好。
總結
綜上,個推API閘道器基於golang自主研發,全Web化配置,實現了所有API介面的標準化、視覺化;除解決閘道器基礎需求外,也支援了外掛熱更新、多協議轉換、資料推送、叢集級別資源隔離等進階需求。除了整合到系統微服務架構中,個推API閘道器同時也作為公司資料中臺流量入口,日均承擔數十億級的訪問量。目前個推API閘道器新版叢集已經穩定執行一年以上,在保障系統穩定運轉的同時還在持續進化。未來,我們還將圍繞雲原生探索更多的可能性,為業務提供穩定高效的基礎平臺。