天天看點

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

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

  • 穩定性。金融領域跟錢強相關,這對于業務穩定性就有着非常嚴格的要求,穩定性一旦出現問題,它将影響整個交易系統的成敗。
  • 強監管。強監管一般是針對生物醫藥領域、醫療領域和金融領域,因為它們所呈現的内容都與人的生命相關。是以,更高層面的強監管要求勢必會影響一些業務層面的選型和架構呈現。
  • 準确性和有效性。由于跟錢強相關,是以在數字層面的呈現更是要求零偏差。就像股票價格一樣,它的數字呈現都是精确到了每分每秒和固定數位的。

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

對 Java 的那些愛與恨

金融系統為何獨愛 Java

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

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

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

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

雲原生時代下的 Java 現狀

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

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

首先,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!Apache 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.5
ENV 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,一定是在權限系統配置了相關權限。

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

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

放棄 Spring Cloud Gateway!Apache APISIX 在「還呗」業務中的技術實踐
網關流量灰階

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

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

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

Java 層面網關的考慮因素

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

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

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

公司角度

1\. 功能與性能兼具

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

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

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

2\. 業務支出成本下降

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

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

開發者角度

1\. 滿足業務需求

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

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

2\. 降低維護成本

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

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

總結:金融業務發展趨勢

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

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