亚洲狼人综合,本道综合精品,在线看福利影,国产亚洲精品久久久玫瑰,日韩欧美精品在线观看,日韩在线国产,欧美乱码一区二区三区

京東京麥:微服務架構(gòu)下的高可用網(wǎng)關(guān)與容錯實踐

2017-12-28 20:02:23 DBAplus社群  點擊量: 評論 (0)
各自的系統(tǒng)在這一指導思想下收獲了優(yōu)雅的可維護性,但一方面也給接口調(diào)用提出了新的要求,比如眾多的 API 調(diào)用急需一個統(tǒng)一的入口來支持客戶端的調(diào)用。
    自微服務概念誕生以來,眾多的軟件架構(gòu)都在踐行著這一優(yōu)秀的設(shè)計理念。

各自的系統(tǒng)在這一指導思想下收獲了優(yōu)雅的可維護性,但一方面也給接口調(diào)用提出了新的要求,比如眾多的 API 調(diào)用急需一個統(tǒng)一的入口來支持客戶端的調(diào)用。

在這種情況下 API Gateway 誕生,我們將接入、路由、限流等功能統(tǒng)一由網(wǎng)關(guān)負責,各自的服務提供方專注于業(yè)務邏輯的實現(xiàn),從而給客戶端調(diào)用提供了一個穩(wěn)健的服務調(diào)用環(huán)境。

之后,我們在網(wǎng)關(guān)大調(diào)用量的情況下,還要保證網(wǎng)關(guān)的可降級、可限流、可隔離等等一系列容錯能力。

今天跟大家分享微服務下京麥開放平臺的網(wǎng)關(guān)實現(xiàn),以及我們?nèi)绾慰沽?、如何在大訪問量的情況下做容錯處理,重點介紹容錯的方法及每種容錯方法的使用場景與經(jīng)驗。

網(wǎng)關(guān)

這里說的網(wǎng)關(guān)是指 API 網(wǎng)關(guān),意思是將所有 API 調(diào)用統(tǒng)一接入到 API 網(wǎng)關(guān)層,由網(wǎng)關(guān)層統(tǒng)一接入和輸出。

一個網(wǎng)關(guān)的基本功能有如下幾種能力:

  • 統(tǒng)一接入
  • 安全防護
  • 協(xié)議適配
  • 流量管控
  • 長短鏈接支持
  • 容錯

有了網(wǎng)關(guān)之后,各個 API 服務提供團隊可以專注于自己的的業(yè)務邏輯處理,而 API 網(wǎng)關(guān)更專注于安全、流量、路由等問題。

單體應用

當業(yè)務簡單、團隊組織很小時,我們常常把功能都集中于一個應用中,統(tǒng)一部署、統(tǒng)一測試,玩得不亦樂乎。

但隨著業(yè)務迅速發(fā)展,組織成員日益增多,我們再將所有的功能集中到一個 Tomcat 中去,每當更新一個功能模塊,勢必要更新所有的程序,搞不好還會牽一發(fā)動全身,導致實在難以維護的情況。

微服務

單體應用滿足不了我們逐漸增長的擴展需求之后,微服務就出現(xiàn)了,它是將原來應用集中于一體的架構(gòu)。

比如商品功能、訂單功能、用戶功能拆分出去,各自有各自的自成體系的發(fā)布、運維等,這樣就解決了在單體應用下的弊端。

API 網(wǎng)關(guān)

進行微服務后,原先客戶端調(diào)用服務端的地方就要有 N 多個 URL 地址,包括商品的、訂單的、用戶等。

這時就必須要有個統(tǒng)一的入口和出口,這種情況下,我們的 API Gateway 就出現(xiàn)了,它很好地幫助我們解決了微服務下客戶端調(diào)用的問題。

泛化調(diào)用

對于普通的 RPC 調(diào)用,我要拿到服務端提供的 class 或者 jar 包,這樣過于繁重,更不好維護。

不過成熟的 RPC 框架都支持泛化調(diào)用,我們的網(wǎng)關(guān)就是基于這種泛化調(diào)用來實現(xiàn)的。

服務端開放出來他們的 API 文檔,我們拿到接口、參數(shù)、參數(shù)類型通過泛化調(diào)用到服務端程序。

public Object $invoke(String method, String[] parameterTypes, Object[] args);

容錯

容錯,這個詞的理解,書面意思就是可以容下錯誤,不讓錯誤再次擴張,讓這個錯誤產(chǎn)生的影響在一個固定的邊界之內(nèi)。

“千里之堤,毀于蟻穴”,我們采用容錯的方式就是不讓這種蟻穴繼續(xù)變大。在工作中,降級、限流、熔斷器、超時重試等都是常見的容錯方法。

抗量

所謂的抗量,就是增大我們系統(tǒng)的吞吐量,所以容錯的第一步就是系統(tǒng)要能抗量,沒有量的情況下幾乎用不到容錯。

我們的容器使用的是 Tomcat,在傳統(tǒng)的 BIO 模型下,一請求一線程,在機器線程資源有限的情況下是沒有辦法來實現(xiàn)我們的目標的。

NIO 給我們提供了這個機會,基于 NIO 的機制,利用較少的線程來處理更多的連接。

連接多不可怕,通過調(diào)整機器的參數(shù)一臺 8c8g 的機器,超過 10w 是不成問題的。

Tomcat 的 Conector 修改成 NIO 后,我們再從代碼層面引入了 Servlet3,它是從 Tomcat7 以后支持的,NIO 是 Tomcat6 以后就支持的。

利用 Servlet3 的特性,所有的 request 和 response 都由 Tomcat 的工作線程來處理,我們將業(yè)務邏輯異步到別的業(yè)務線程中去。

在異步環(huán)境下,可以提高單位時間內(nèi)的吞吐量,所有的 Servlet 請求都是由 Tomcat 的 Executor 線程池的線程處理的,也就是 Tomcat 的工作線程。

這些線程處理的時間越短越好,越短越能迅速地將線程歸還給 Executor 線程池,現(xiàn)在 Servlet 支持異步后就能將耗時的操作,比如有 RPC 請求的交給業(yè)務線程池來處理,使得 Tomcat 工作線程可立即歸還給 Tomcat 工作線程池。

另外,將業(yè)務異步處理之后,我們可以對業(yè)務線程池進行線程池隔離,這樣就避免了因一個業(yè)務性能問題而影響了其他的業(yè)務。

總結(jié)一下異步的優(yōu)勢:

  • 可以用來做消息推送,通過 Nginx 做代理,設(shè)置連接超時時間,客戶端通過心跳探測。
  • 提高吞吐量。
  • 請求線程和業(yè)務線程分開,從而可以通過業(yè)務線程池對業(yè)務線程做隔離。

脫離 DB

脫離 DB,這里不是說 DB 的性能不行,分庫分表、DB 集群化之后,在一定量的情況下是沒有問題的。

但是,如果從抗量的角度說的話,為何不使用 Redis 呢?如果軟件架構(gòu)里面有一種銀彈的話,那么 Redis 就是這種銀彈。

另外一個脫離 DB 的原因是:每當大促備戰(zhàn)前夕我們一項重點的工作就是優(yōu)化慢 SQL,但它就像小強一樣生命力是那樣的頑強,殺不絕。

如果有那么一個慢 SQL,平時是沒有問題的,比如一個查詢大字段的 SQL,平時量小不會暴露問題,但量一上來了,就是個災難。

再就是我們的網(wǎng)關(guān),包括接入、分發(fā)、限流等這些功能都應該是很輕的,所以我們就通過數(shù)據(jù)異構(gòu)的方式把數(shù)據(jù)重新轉(zhuǎn)載到 Redis 中,而且是將數(shù)據(jù)持久化到 Redis 里面去。

當然,使用 Redis 的過程中也需要注意大 key,大訪問量下也能讓集群趴下。

還有一個很重要的原因,我們使用的 DB 是 MySQL,鑒于 MySQL 的 failover 機制生效時間總是要長于 Redis 集群,最后就是因為 DB 切換的時候,常常伴隨 Web 應用服務器要重啟,將原來的連接釋放掉,才能方便使用新的數(shù)據(jù)庫連接。

多級緩存

最簡單的緩存就是查一次數(shù)據(jù)庫然后將數(shù)據(jù)寫入緩存。比如在 Redis 中設(shè)置過期時間,因為有過期失效,因此我們要關(guān)注下緩存的穿透率。

這個穿透率的計算公式,比如查詢方法 queryOrder(調(diào)用次數(shù) 1000/1s)里面嵌套查詢 DB 方法 query Product From DB(調(diào)用次數(shù) 300/s),那么 Redis 的穿透率就是 300/1000。

在這種使用緩存的方式下,是要重視穿透率的,穿透率大了說明緩存的效果不好。

還有一種使用緩存的方式就是將緩存持久化,也就是不設(shè)置過期時間,這個會面臨一個數(shù)據(jù)更新的問題。

一般有兩種辦法:

  • 利用時間戳,查詢默認以 Redis 為主,每次設(shè)置數(shù)據(jù)的時候放入一個時間戳,每次讀取數(shù)據(jù)的時候用系統(tǒng)當前時間和上次設(shè)置的這個時間戳做對比。

比如超過 5 分鐘,那么就再查一次數(shù)據(jù)庫,這樣可以保證 Redis 里面永遠有數(shù)據(jù),一般是對 DB 的一種容錯方法。

  • 讓 Redis 真正作為 DB 來使用,就是如圖里畫的通過訂閱數(shù)據(jù)庫的 binlog,通過數(shù)據(jù)異構(gòu)系統(tǒng)將數(shù)據(jù)推送給緩存,同時將緩存設(shè)置為多級。

可以通過使用 jvm cache 作為應用內(nèi)的一級緩存,一般是體積小,訪問頻率大的更適合這種 jvm cache 方式,將一套 Redis 作為二級 remote 緩存,另外的最外層三級 Redis 作為持久化緩存。

超時與重試

超時與重試機制也是容錯的一種方法,凡是發(fā)生 RPC 調(diào)用的地方,比如讀取 Redis、DB、MQ 等。

因為網(wǎng)絡故障或者是所依賴的服務故障了,長時間不能返回結(jié)果,就會導致線程增加,加大 CPU 負載,甚至導致雪崩。所以對每一個 RPC 調(diào)用都要設(shè)置超時時間。

對于強依賴 RPC 調(diào)用資源的情況,還要有重試機制,但重試的次數(shù)建議 1-2 次。

另外如果有重試,超時時間還要相應都調(diào)小,比如重試 1 次,那么一共是發(fā)生 2 次調(diào)用。

如果超時時間配置的是 2s,那么客戶端就要等待 4s 才能返回,因此重試+超時的方式,超時時間要調(diào)小。

這里也再談一下 1 次 PRC 調(diào)用的時間都消耗在哪些環(huán)節(jié)。

1 次正常的調(diào)用統(tǒng)計的耗時主要包括:①調(diào)用端RPC框架執(zhí)行時間 + ②網(wǎng)絡發(fā)送時間 + ③服務端RPC框架執(zhí)行時間 + ④服務端業(yè)務代碼時間。

調(diào)用方和服務方都有各自的性能監(jiān)控,比如調(diào)用方 tp99 是 500ms,服務方 tp99 是 100ms,找了網(wǎng)絡組的同事確認網(wǎng)絡沒有問題的。

那么時間都花在什么地方了呢?兩種原因:客戶端調(diào)用方,還有一個原因是網(wǎng)絡發(fā)生 TCP 重傳,所以要注意這兩點。

熔斷

熔斷技術(shù)可以說是一種“智能化的容錯”,當調(diào)用滿足失敗次數(shù),失敗比例就會觸發(fā)熔斷器打開,有程序自動切斷當前的 RPC 調(diào)用,來防止錯誤進一步擴大。

實現(xiàn)一個熔斷器主要是考慮三種模式:

  • 關(guān)閉
  • 打開
  • 半開

各個狀態(tài)的轉(zhuǎn)換如下圖:

在了解了熔斷器的狀態(tài)機制后,我們可以自己來實現(xiàn)一個熔斷器。當然也可以使用開源的解決方案,比如 Hystrix 中的 breaker。

下圖是一個熔斷器打開關(guān)閉的示意圖:

這里要談的是熔斷器的使用注意項:

我們在處理異常時,要根據(jù)具體的業(yè)務情況來決定處理方式。比如我們調(diào)用商品接口,對方只是臨時做了降級處理,那么作為網(wǎng)關(guān)調(diào)用就要切到可替換的服務上來執(zhí)行或者獲取托底數(shù)據(jù),給用戶友好提示。

還有要區(qū)分異常的類型,比如依賴的服務崩潰了,這個可能需要花費比較久的時間來解決,也可能是由于服務器負載臨時過高導致超時。

作為熔斷器應該能夠甄別這種異常類型,從而根據(jù)具體的錯誤類型調(diào)整熔斷策略。

增加手動設(shè)置,在失敗的服務恢復時間不確定的情況下,管理員可以手動強制切換熔斷狀態(tài)。最后,熔斷器的使用場景是調(diào)用可能失敗的遠程服務程序或者共享資源。

如果是本地緩存本地私有資源,使用熔斷器則會增加系統(tǒng)的額外開銷。還要注意,熔斷器不能作為應用程序中業(yè)務邏輯的異常處理替代品。

線程池隔離

在抗量這個環(huán)節(jié),Servlet3 異步時,有提到過線程隔離。線程隔離的直接優(yōu)勢就是防止級聯(lián)故障,甚至是雪崩。

當網(wǎng)關(guān)調(diào)用 N 多個接口服務的時候,我們要對每個接口進行線程隔離,比如我們有調(diào)用訂單、商品、用戶。

那么訂單的業(yè)務不能夠影響到商品和用戶的請求處理。如果不做線程隔離,當訪問訂單服務出現(xiàn)網(wǎng)絡故障導致延時,線程積壓最終導致整個服務 CPU 負載滿。

就是我們說的服務全部不可用了,有多少機器都會被此刻的請求塞滿。那么,有了線程隔離就會使得我們的網(wǎng)關(guān)能保證局部問題不會影響全局。

降級、限流

關(guān)于降級限流的方法業(yè)界都已經(jīng)有很成熟的方法了,比如 Failback 機制,限流方法令牌桶、漏桶、信號量等,這里談一下我們的一些經(jīng)驗。

降級一般都是由統(tǒng)一配置中心的降級開關(guān)來實現(xiàn)的,那么當有很多個接口來自同一個提供方,這個提供方的系統(tǒng)或這機器所在機房網(wǎng)絡出現(xiàn)了問題,我們就要有一個統(tǒng)一的降級開關(guān)。

不然就要一個接口一個接口地來降級,也就是要對業(yè)務類型有一個大閘刀。

還有就是降級切記暴力降級,什么是暴力降級?比如把論壇功能降調(diào),結(jié)果用戶顯示一個大白板,我們要實現(xiàn)緩存住一些數(shù)據(jù),也就是有托底數(shù)據(jù)。

限流一般分為分布式限流和單機限流,如果實現(xiàn)分布式限流的話就要一個公共的后端存儲服務,比如 Redis,在大 Nginx 節(jié)點上利用 Lua 讀取 Redis 配置信息。

我們現(xiàn)在的限流都是單機限流,并沒有實施分布式限流。

網(wǎng)關(guān)監(jiān)控與統(tǒng)計

API 網(wǎng)關(guān)是一個串行的調(diào)用,每一步發(fā)生的異常都要記錄下來,統(tǒng)一存儲到一個地方,比如 Elasticsearch 中,便于后續(xù)對調(diào)用異常的分析。

鑒于公司 Docker 申請都是統(tǒng)一分配,而且分配之前 Docker 上已經(jīng)存在 3 個 Agent 了,不再允許增加。

我們自己實現(xiàn)了一個 Agent 程序,來負責采集服務器上面的日志輸出,然后發(fā)送到 Kafka 集群,再通過 Web 查詢消費到 Elasticsearch 中?,F(xiàn)在做的追蹤功能還比較簡單,這塊還需要繼續(xù)豐富。

總結(jié)

網(wǎng)關(guān)基本功能有統(tǒng)一接入、安全防護、協(xié)議適配等。這篇文章里我們并沒有講如何來實現(xiàn)這些基本的功能,因為現(xiàn)在有很多成熟的解決方案可以直接拿過來使用。

比如 Spring Cloud 這種全家桶里面的很多組件,Mashape 的 API 層 Kong 等。

大云網(wǎng)官方微信售電那點事兒

責任編輯:售電衡衡

免責聲明:本文僅代表作者個人觀點,與本站無關(guān)。其原創(chuàng)性以及文中陳述文字和內(nèi)容未經(jīng)本站證實,對本文以及其中全部或者部分內(nèi)容、文字的真實性、完整性、及時性本站不作任何保證或承諾,請讀者僅作參考,并請自行核實相關(guān)內(nèi)容。
我要收藏
個贊
?