放棄 Spring Cloud Gateway!Apache APISIX 在「還唄」業務中的技術實踐

語言: CN / TW / HK

不同行業之間,都會存在一些業務屬性上的差距。對於金融領域的應用軟件來説,因其涉及到錢等因素,所以在業務上會有以下獨特屬性:

  • 穩定性。金融領域跟錢強相關,這對於業務穩定性就有着非常嚴格的要求,穩定性一旦出現問題,它將影響整個交易系統的成敗。

  • 強監管。強監管一般是針對生物醫藥領域、醫療領域和金融領域,因為它們所呈現的內容都與人的生命相關。所以,更高層面的強監管要求勢必會影響一些業務層面的選型和架構呈現。

  • 準確性和有效性。由於跟錢強相關,所以在數字層面的呈現更是要求零偏差。就像股票價格一樣,它的數字呈現都是精確到了每分每秒和固定數位的。

基於以上這些特點,金融行業軟件系統在進行系統設計、機房拓撲以及中間件選型時,就會出現一些與其他通用行業不太一樣的地方。

對 Java 的那些愛與恨

金融系統為何獨愛 Java

Java 自誕生以來就深受開發者的喜愛。在中國有將近 50% 的開發者在使用 Java 作為開發語言。這不單單是因為其語言的優勢,也因為 Java 相關的生態非常龐大,尤其是國內的金融系統很多都是基於 Java 的,這導致有段時間大家都誤以為所有的系統都是用 Java 做的。

近 15~20 年以來,大部分金融系統基本都選擇了 Java 技術棧,深究其原因,我們認為主要是因為 Java 技術棧有以下幾點優勢。

正是如此,Java 逐漸得到了金融類軟件系統的青睞。

雲原生時代下的 Java 現狀

隨着技術行業的快速發展,單體架構逐漸被淘汰,微服務和雲原生時代正在風靡四海。然而在近幾年的技術大環境下,作為面向對象的高級語言,Java 也在一些業務場景中開始略顯疲憊:

首先,Java 性能較低,這點對比一下 C 語言相關技術棧就會明白。Java 是基於虛擬機,它的內存管理是交給虛擬機來解決的,所以當面對一些高性能或動態變化的業務場景時,Java 語言在處理上沒有那麼強勢。

其次,Java 語言需要更多的資源。一個架構的打造如果不考慮成本,很多問題都很好解決,但在雲原生時代下,所有的資源計算變得越來越細、越來越顆粒化。Java 在運作時需要消耗大量的資源,由於 Java 分量重和需要重啟的基礎特性,因此在高 QPS 或者業務連續性要求較高的場景下,該語言會更容易出現問題。

最後就是指針變量的問題。習慣於寫 C/C++ 語言的同學都知道,指針是一個非常好的資源。但 Java 是基於虛擬機,它把內存管理交給了 GC(Garbage Collection),而不是由手動程序進行管理,所以對於一些特定情況或者高併發、高訪問量和高性能的場景下,Java 的實際性能可能就略顯不足了。

還唄為何選擇 APISIX?

數禾科技是一家提供智能化金融的服務平台,旗下主要產品有還唄、還享花等。還唄 APP 是一款基於消費多場景的分期服務平台,通過與持牌金融機構合作,為大眾提供個人消費信貸服務,併為小微企業主提供貸款資金支持。在業務架構層面,還唄的產品實現一直是依賴 Java 技術棧的。

Spring Cloud Gateway 是 Spring Cloud 生態下為更好管理微服務而誕生的網關項目,對於公司業務以 Java 為主要開發語言的情況下,Spring Cloud Gateway 通常是個不錯的 API 網關選擇。但在近期的 API 網關迭代過程中,還唄放棄了使用已久的 Spring Cloud Gateway,而是選擇了 Apache APISIX。

架構的前後變化

在架構層面,還唄在使用 APISIX 前後呈現瞭如下圖所示的變化。

在左側的使用前架構中,還唄一共使用了三套網關係統,並把網關分為入口網關和出口網關兩大類。其中在運營系統網關和出口系統網關中,都使用了 Spring Cloud Gateway 作為網關,而在業務系統網關中則使用了 OpenRestry 作為業務系統網關。

對於一開始使用 Spring Cloud Gateway 作為運營和出口系統網關,主要是看中了 Spring Cloud 龐大的生態系統,以及簡單易部署和易維護的分佈式系統開發框架,所以在早期進行業務架構部署時,為了更快搭建起業務而選擇使用 Spring Cloud 全家桶。

但隨着業務慢慢發展,原先架構中的網關開始出現一些穩定性的問題,比如內存溢出、CPU 使用率過高等情況。為了升級網關性能及統一多個網關,還唄將架構中的網關全部統一替換為了 Apache APISIX。

在新網關架構中,業務系統網關會優先把請求流量通過服務發現的方式直接轉發到業務系統。如果後端應用在 Consul 中沒有健康 Pod 或者後端應用不支持服務發現等,就會把流量轉發到以前的內網 K8s Ingress,作為兜底的上游來使用。

新架構同時也統一了出口網關的兩個應用,新出口網關部署在 K8s 集羣外的外聯區。同時也在出口網關集羣前新增一個 SLB,可以統一出口網關的入口 ,方便沒有服務發現能力的應用或者其他 VPC 內的系統調用。

基於 APISIX 的應用實踐

實際業務情況下,由於內部已存在多種網關架構,沒辦法直接使用 Apache APISIX,於是還唄基於 APISIX 進行了一些改造和構建。

APISIX 構建部署

在內部進行開發時,將 APISIX 網關的代碼和定製代碼存放在不同路徑下,兩者協同工作,各自可獨立迭代。在部署時則採用 Docker 鏡像方式部署,構建一個 APISIX 指定版本的基礎鏡像,然後再把自定義代碼打包形成新鏡像。

自定義代碼打包時沒有使用 lua_package_path 來指定代碼目錄,而是直接覆蓋基礎鏡像 apisix 源碼目錄,如果有同名文件則覆蓋源碼文件。Dockerfile 如下所示:

FROM registry.xxx.net:5001/apisix-shuhe:v1.5ENV APP_NAME={{APP_NAME}}COPY {{PRODUCT_FILE}} /tmp/deploy2/artifact.tar.gz 
RUN mkdir /tmp/deploy/ && tar -xf /tmp/deploy2/artifact.tar.gz -C /tmp/deploy/ && \cp -R /tmp/deploy/apisix/ /usr/local/apisix/ && \cp /tmp/deploy/bin/apisix /usr/bin/apisix && \cp /tmp/deploy/conf/apisix-$APP_NAME.yaml /usr/local/apisix/conf/apisix.yaml && \cp /tmp/deploy/conf/config-$APP_NAME.yaml /usr/local/apisix/conf/config.yaml && \set -x && \bin='#! /usr/local/openresty/luajit/bin/luajit\npackage.path = "/usr/local/apisix/?.lua;" .. package.path' && \sed -i "1s@.*@$bin@" /usr/bin/apisix && \rm -rf /tmp/*

複製代碼

APISIX 的日誌默認存儲在本地(也可以通過 Syslog 等插件收集),通過調整 nginx 配置模板和判斷啟用的 Profile 來決定日誌存儲在本地還是通過 Syslog 存儲到 FLUENTD 中。同時在構建鏡像時替換模板中 FLUENTD_HOST 變量。如下所示:

{% if gw_profile and string.find( gw_profile,'local') then %}access_log logs/access.log main;error_log  logs/error.log warn;{%else%}access_log syslog:server=${FLUENTD_HOST}:5141 json_format;error_log  syslog:server=${FLUENTD_HOST}:5142 warn;{%end%}

複製代碼

在 nginx 配置模板中,還唄不光修改了日誌存儲,還調整了循環添加 ENV 環境變量、循環添加  lua_shared_dicts 配置及寫死一些 NGINX 其他調優參數。

因為公司是按照業務流量劃分為多種網關,這些網關的基本功能都差不多,因此還唄內部採取了「一套代碼部署多個網關應用」方案。通過 Profile 功能配置各個網關的 config-xxx.yaml 文件,然後通過公司 DEVOPS 平台構建鏡像時,根據應用名構建不同網關的 Docker 鏡像即可。

公司級定製插件

在內部訪問運營系統頁面時,會調用很多後端的 API 獲取數據,這些 API 都需要在 API 網關中配置對應的白名單。在頁面中根據登錄運營系統用户的角色不同,能夠訪問的 API 範圍也不一樣,因此權限系統也需要維護相關 API 列表。每當在頁面上新增後端 API 調用時 ,都需要開發人員在網關頁面及權限系統頁面配置兩次,工作宂餘且重複。

為此,還唄把網關配置與權限系統配置打通,只保留權限配置系統的配置入口,網關配置管理系統則定時拉取權限 API,之後轉換成網關 API 白名單配置。這樣做不僅能減少用户一次配置操作,同時也協助權限系統進行了權限管控。可以保證在運營頁面調用的後端 API,一定是在權限系統配置了相關權限。

在公司的實際業務中,經常會遇到原生插件不能滿足實際需求的情況,就需要定製開發。好在 APISIX 提供了很多工具類,參照原生插件就可以輕鬆實現,開發過程也非常簡單。以下列舉了還唄內部基於 APISIX 進行的其他定製插件:

網關流量灰度

之前還唄使用的 K8s 容器是 OpenShift(現已升級為 ACK 集羣),其中 Ingress 是 Haproxy 搭建。由於公網 K8s Ingress 的 Haproxy 不能把一個域名的流量轉發到兩個 Namespace 的路由中,因此考慮把新網關部署在和老網關相同的 Namespace 下。即域名的路由下掛載多個服務,之後便可以通過路由調整流量比例,控制流量走新網關還是老網關。

具體實施流程如下圖所示,在老網關的 Namespace 下新增 c、d 組用於部署新網關,通過路由控制新老網關的流量比例。

Java 層面網關的考慮因素

很多 Java 工程師在微服務架構中都會選擇 Spring Cloud,主要是語言綁定,並用類庫的方式放在代碼裏。但是在實踐過程中可能會出現升級困難的情況,如果團隊是多語言就需要維護多個類庫,假設有 10 個版本與 10 種語言,就需要維護 100 個類庫。

此時就可以通過代理的方式(即 API 網關)把多版本和多語言的問題輕鬆解決。那 Java 技術棧公司選擇 APISIX 作為 API 網關後都有哪些收益?我們根據還唄的實踐經歷,從以下兩個角度進行了總結。

公司角度

1. 功能與性能兼具

還唄在內部使用 4 核虛擬機無插件空跑壓測 APISIX 的 QPS 可以達到 80K,很好地解決了 Spring Cloud Gateway 在承接 C 端流量時出現的性能問題,而且在生產環境中發現 APISIX 相較於之前網關性能提升了 30% 以上。

其次,得益於雲原生屬性,APISIX 在實際的測試中完全可以滿足公司的需求,比如認證鑑權、可觀測性、服務發現、限流限速以及四層和七層流量轉發。而在功能擴展方面,APISIX 也支持了 70 餘款插件,大部分的業務可以使用其原生插件,很大程度上減少了開發工作。

2. 業務支出成本下降

在使用 APISIX 之前,如果性能出現了瓶頸,公司只能通過不斷的增加服務器來解決這個問題,因此相應的硬件成本也會非常的高。

還唄在進行成本計算時發現,使用 APISIX 後,服務器的數量大概減少了 60% 左右。統一技術棧後,業務上也可以很輕鬆地基於 APISIX 原生框架實現功能的擴展,節省了開發成本,加快了項目上線時間速度。

開發者角度

1. 滿足業務需求

業務中所使用的軟件或技術都應該是為需求而服務。從實際測試結果及調研數據來看,APISIX 的穩定性、可觀測性、可擴展性會更好。

軟件最終服務於業務。如果業務需要,可以為公司節約資源,那麼無論公司的技術棧是什麼,都會使用最符合公司業務的組件。

2. 降低維護成本

相比之前使用的 OpenResty,APISIX 的學習成本相對較低,維護起來也比較省心。同時,APISIX 豐富的插件簡化了一些通用功能的實現與部署,大大節約了項目上線的時間。

同時利用 APISIX 強大的日誌和動態調試功能,業務可以很輕鬆地排查出故障點,從而快速定位、節約時間。

總結:金融業務發展趨勢

在過去的十年裏,互聯網金融從「野蠻生長」開始逐漸向「精耕細作」模式轉變,這個轉變主要涉及到的就是系統的變革。

在野蠻生長階段,業務講究的是效率。為了業務更快速地建設,在基礎架構選擇的時候,負責人更多是選擇自己熟悉的語言架構進行搭建。不同的負責人便會選擇使用不同的技術棧,因此留下了很多技術債務。從 2017 年開始,依舊活躍的金融企業或服務公司大多都會面臨同樣的技術現狀,那就是存在多套技術組件。這時就需要進行基礎設施的統一。

來到精耕細作階段,企業就需要對系統進行垂直拆分,由以前的煙囱式拆分成前台、中台及後台等模式。系統到達一個穩定階段時,就需要把一些東西夯實下來。

而系統建設的根本目的其實就是為了共用。重複性使用越強,系統的運維成本就越低。所以很多公司到了精耕細作階段,要麼是進行系統的垂直拆分,要麼就是進行基礎組件的下沉,進而控制運維成本。

作為企業來説,成本優先依舊是需要考慮的原則。野蠻生長階段可能只需要儘快實現業務,而在目前大環境下,預算範圍之內肯定是成本優先。這樣的話,效率和成本永遠只能保住一項。因此在成本有限的情況下,企業就會少談技術的先進性。技術人員在選型的過程中,就不會考慮當下選擇的這個技術對團隊有多大沖擊、對現有的運維和架構帶來多少收益等等,更多是從成本角度考慮。