服務化框架技術選型實踐
前言
首先本文不討論為什么要服務化,包括服務化的優點缺點。
其次本文也不討論什么是微服務,也不討論微服務和SOA的區別。
最后本文也不討論哪個技術最優。
服務框架構成
最基本的服務框架
基本的服務化框架包括如下模塊:統一的RPC框架,服務注冊中心,管理平臺。
有了這三個模塊,就能實現基本的服務化。下面對三個模塊進行具體分析。
RPC框架選型
為什么一定要是統一的RPC框架,而不是隨便啥框架,這里主要是為了技術對齊,減少開發人員的學習成本,減少團隊間溝通成本。
好,那么選擇一個RPC框架,我們都需要考量什么東西呢?這里我總結下:
- 代碼規范:例如是對已有代碼透明,還是代碼生成。
- 通訊協議:例如是TCP還是HTTP
- 序列化協議:例如是二進制還是文本,是否需要跨語言,性能
- IO模型:異步/同步,阻塞/非阻塞
- 負載均衡:客戶端軟負載,代理模式,服務端負載
另外如果是從開源里面選擇,那么我們還需要考量:
- 成熟度:包括學習成本,社區熱度,文檔數,是否有團隊維護,穩定性(盲目追求的不一定是最適合)
- 可擴展性:是否有SPI支持擴展,是否支持上下兼容
- 跨語言:是否支持跨語言
- 性能:要想作為RPC框架,性能一般都不會太差 [滑稽臉]
下面是常見的一些開源框架的比較,大家可以看一下。
Ps:SOAP,RMI,Hessian,ICE就不列舉了。
選型小結:
- 如果需要與前端交互的,適合短鏈接、跨語言的RPC框架,例如RESTful、gRPC等
- 如果純粹后臺交互的,適合長鏈接、序列化為二進制的RPC框架,例如thrift、dubbo等更高效
- 如果是小公司,新公司從頭開始推廣服務化框架的,可以選擇規范化的RPC框架,例如thrift、RESTful、gRPC
- 如果是已有大量業務代碼的再推廣服務框架的,那么最好選擇無代碼入侵的RPC框架,例如dubbo、RESTful
注冊中心選型
注冊中心相當于是服務提供者和服務調用者之間的引路人,在服務治理中的作用極為重要。
選擇注冊中心基本要考量:
- 服務注冊:接收注冊信息的方式
- 服務訂閱:返回訂閱信息的方式,推還是拉
- 狀態檢測:檢測服務端存活狀態
重點提一下這個狀態檢測,因為這個要是檢測不準確會誤判,導致嚴重后果,
例如Zookeeper根據服務端注冊的臨時節點進行狀態檢測,如果服務端和Zookeeper之間的網絡閃斷,導致Zookeeper認為服務端已經死了,從而摘掉這個節點。
但是其實客戶端和服務端直接的網絡是好的,這樣就有可能把節點全部摘掉,導致無可用節點。
如果是從開源里面選擇,那么還需要考量:
- 成熟度:包括學習成本,社區熱度,文檔數(盲目追求的不一定是最適合)
- 維護成本:注冊中心維護
- 數據解構:是否能快速定位結果,是否能遍歷
- 性能和穩定性:
- CAP原則:CP(關注一致性)還是AP(關注可用性)
下面是常見的一些使用開源項目做注冊中心的比較,大家可以看一下。
Ps:Redis和MySQL沒有列舉。
選型小結:
- 規模小選擇CP,RPC框架可以直接接入數據源
- 規模大選擇AP, RPC框架不可以直接接入數據源
- 存在跨機房,跨地域的盡量不要選有強一致性協議的注冊中心
- RPC框架必須要有注冊中心不可用的容災策略
- 服務狀態檢測十分重要
簡易管理端
管理端沒啥特殊要求,最起碼能看到服務提供者和調用者即可。
完善的服務化框架
如果需要一個完善的服務化框架,那么必須增加外部模塊,常見的模塊如下圖:
接口文檔管理
提供一個接口文檔管理以及接口查詢的入口,可以是一個公共的WIKI,也可以是獨立的系統,等等。
這里可以定義接口的文檔,包括接口描述,方法定義,字段定義
可以定義接口的SLA,包括支持的并發數,tp99多少,建議配置是什么
還有就是接口的負責人等一些查詢的入口。
配置中心
提供一個配置管理的地方,這里說的配置主要指的是服務相關的一些配置。
配置包括分組配置、路由策略、黑白名單、降級開關、限流信息、超時時間、重試次數等等,任何可以動態變更的所有數據。
這樣服務提供者和服務調用者可以不需要重啟自己的應用,直接進行配置的變更。
配置中心可以獨立于注冊中心,也可以和注冊中心合并。
監控中心
監控服務關注接口維度,實例(例如所在JVM實例)維度的數據。
RPC框架可以定時上報調用次數,耗時,異常等信息。
監控中心可以統計出服務質量信息,也可以進行監控報警。
分布式跟蹤
區別于監控中心,以調用鏈的模式對服務進行。
RPC框架作為分布式跟蹤系統的一個天然埋點,可以很好的進行一個數據輸出。
服務治理(重點)
我這邊列了常見的服務治理功能,例如:
-
服務路由:
- 權重:例如機器配置高的權重高,機器配置低的權重低
IP路由:例如某幾臺機器只能調某幾臺機器 - 分組路由:例如自動根據配置調某個分組
- 參數路由:例如根據方法名進行讀寫分類,或者根據參數走不同的節點
- 機房路由:例如只走同機房,或者同機房優先
- 權重:例如機器配置高的權重高,機器配置低的權重低
-
調用授權:
- 應用授權:只有授權后的應用才能調這組服務
- token:只有token對的調這組服務
- 黑白名單:只有名單允許的才能調這組服務
-
動態分組:
- 服務端切分組:可以根據分組的情況,對服務提供者進行一個動態的分組調度
- 客戶端切分組:可以對調用者進行一個分組調度
-
調用限流:
- 服務端限流:服務端基于令牌桶或者漏桶模型進行限流
- 客戶端限流:根據客戶端的標識,進行調用次數限流
-
灰度部署:
- 灰度上線:先啟動,驗證后在提供服務
- 預發標識:表示該服務為預發布服務
- 接口測試:方便的提供接口自動化功能測試功能
-
配置下發:
- 服務配置
- 全局配置
-
服務降級:
- Mock:出現異常或者測試情況下,返回Mock數據
- 熔斷:客戶端超時或者服務端超時
- 拒絕服務:服務端壓力大時,自動拒絕服務,保護自己
網關
RPC框架大部分場景都是自己調用的,什么時候會需要一個網關呢?
網關可以提供如下功能:
- 統一的鑒權服務
- 限流服務
- 協議轉換:外部協議轉統一內部協議
- Mock:服務測試,降級等
其它一些統一處理邏輯(例如請求解析,響應包裝)
服務注冊中心Plus
需要邏輯處理能力,例如對數據進行篩選過濾整合,計算服務路由等功能
同時還需要有與RPC框架交互的功能。
管理端Plus
管理端除了之前的簡單服務管理功能外,還需要提供配置信息展示,監控信息展示,各種維度的數據展示。
也就是下面提到的服務治理功能,都可以在管理端進行管理。
另外,常見的服務治理功能,我們都可以作為開放服務供開發人員進行一個調用。
京東實踐
第一代SAF背景
2012年初,京東從.NET轉Java。各個部門,各個業務線都沒有一個統一的服務化框架,有的是dubbo,有的是WebService,有的是Hessian等等。
同時各個業務系統自己有非常多的業務代碼。通過統計接口規模在1K左右,服務節點在50K左右,機器規模在8K左右,機房比較少拓撲簡單。
所以當時的愿景和目標比較明確:
- 京東系統服務化、API化的從無到有
- 統一京東的RPC調用框架
- 穩定可靠
- 提供簡單的服務治理功能
第一代SAF選擇
OK,結合我們的情況和上面的一些選型小結,我們當時的選擇如下:
- RPC框架:基于dubbo2.3.2做配置擴展,以及功能擴展包括rest(resteasy)、webservice(cxf)、kryo/thrift序列化、調用壓縮等
- 注冊中心:Zookeeper,RPC框架直接接入數據源
- 監控中心:監控服務+HBase
- 管理平臺:讀取Zookeeper做管理平臺,提供基本的上下線、黑白名單等功能
于2012年4月上線,最大規模時,接口數3K,接入最大IP數20K。
第二代JSF背景
隨著京東業務的不斷快速增長,接口、機器數也呈數量級增長。
同時京東成立子公司,在全國各地新建機房,部署結構也變得比較復雜。
加上SAF遺留的一些問題,大概面臨如下幾點:
- RPC框架較重,性能有提高的空間
- 注冊中心無業務邏輯,直接對外暴露
- 京東復雜的部署架構需要更強大靈活的服務治理功能
- 監控數據不完整,維度不夠
- 無應用依賴關系
- 跨語言調用需求
第二代JSF選擇
所以在2014年初,我們進行了第二代JSF的一個全部自研過程。
我們主要做了如下技術選型:(全部自研)
- RPC框架:輕量級,更佳的性能,兼容舊版本協議
- 注冊中心:基于DB作為數據源,前置Index服務;支持十倍接入量;部分邏輯放在注冊中心減少客戶端負擔
- 監控中心:監控Proxy服務+InfluxDB(2015后改為ElasticSearch)
- 管理端:基于DB,功能更強大,提供完善的服務治理管理功能;打通京東應用管理平臺,提供應用依賴關系梳理;
- HTTP網關:基于Netty,支持跨語言調用
開發周期:7人/年(2014.1-2015.1)。包括開發、測試、預發、上線、推廣。
JSF架構簡圖
JSF注冊中心
京東的注冊中心是自研的,基于DB做的數據最終一致,也就是上面說的AP系統。
注冊中心主要實現的就是服務列表的注冊訂閱推送,服務配置的獲取下發,服務狀態的實時查看等功能。
注冊中心節點是無狀態的,可水平擴展的。整個注冊中心集群下的所有注冊中心幾點都是等價的。
每個機房部署多個注冊中心節點。同機房的RPC框架會優先連本機房的注冊中心節點。
主要亮點如下:
-
引入Index服務概念
- 該服務就是一個最簡單HTTP的服務,用于找注冊中心節點(同機房或者壓力最小或者其它特定場景),可以認為是不會掛的服務,
- RPC框架會優先連該服務拿注冊中心地址,這樣子的好處是注冊中心地址變化后,RPC框架不用修改任何設置。
-
注冊中心內存有服務列表全量緩存,連不上數據庫也保證可讀
-
數據庫的數據結構更適合各種維度展示、過濾、分析等
- 例如根據分組,IP,應用,機房等不同維度 </ul> </li>
- 注冊中心就是個JSF服務,監控到壓力大即可進行動態水平擴展
- dogfooding,注冊中心其實是第一個JSF接口 </ul> </li>
- 服務列表推送邏輯改進
- 例如原來100個Provider,現在加1個節點,之前的SAF是需要下發101個節點,自己判斷加了哪個節點,進行長鏈接建立;
- 現在的改進是:修改為下發一個add事件,告知RPC框架加了1個節點,RPC框架進行長鏈接建立;
- 這樣做大大減少了推送的數據量。 </ul> </li>
- 注冊中心與RPC框架可各種交互
- 注冊中心和RPC框架是長鏈接,而且JSF是支持Callback的,注冊中心可以調用RPC框架進行服務列表變化之外的操作;
- 例如查看狀態,查看配置,配置下發等。 </ul> </li> </ul>
- Config:Spring/API/Annotation
- Proxy: Javassist/JDK
- Invoker/Filter:內置+自定義,Filter可擴展
- Client:Failover(默認)/FailFast/TransportPinpoint/MultiClientProxy
- 調用方式:同步(默認)/異步并行/異步回調/Callback/泛化
- Loadbalance:Random(默認)/Roundrobin/ConsistentHash/ LocalPreference/LeastActiveCall
- 路由:參數路由,分組路由,(IP級別路由邏輯在注冊中心做)
- 長連接維護:可用/死亡/亞健康
- 協議:JSF(默認)/SAF(dubbo)/HTTP/Telnet/HTTP2
- 第三方:REST/Webservice
- 序列化:MsgPack(默認)/Hessian/Json/Java/protobuf(c++)
- 壓縮:Snappy/LZMA
- 網絡:基于Netty4.0,長連接復用
- 線程模型:BOSS+WORKER+BIZ
- 容災:本地文件
- 請求上下文:IP,參數,隱式傳參
- 事件監聽:響應事件,連接事件,狀態事件
- 分布式跟蹤支持:進行數據埋點
-
基于Netty4.0實現HTTP網關,沒有使用Servlet容器,輕量高效。
-
支持服務自動發現
- 一般的HTTP服務,外面為了解決單點問題,都會用域名+VIP等實現高可用,故障轉移等;
- 現在網關同時原生接入了JSF的注冊中心,知道了服務的提供者信息(JSF協議支持HTTP調用)。
- 服務提供者也不用關系擴容縮容導致服務的IP端口發生變化,網關會自動維護服務列表。
- 服務限流
- 針對方法級+應用進行授權,固定時間只能調用指定次數。
- 同一個方法也只能占用網關內的部分線程 </ul> </li>
- 結果統一包裝
- 對異常等響應進行包裝 </ul> </li> </ul>
- 硬件指標:例如使用JDK獲取的Docker的指標有些是物理機的,我們需要特殊處理
- 網絡:結合京東的“胖”容器,每個容器其實有實際IP,對外提供服務
- 輕量:提高啟動速度
- 開放服務:在容器銷毀或者非優雅停機的情況下,提供API進行服務治理
- 接口數:萬級
- 服務節點數:百萬級
- 接入實例數:十萬級
- 框架調用量:每天千億級別
- 監控數據:每天120億條數據,1.2T數據量
- HTTP網關:每天百億級別
- 沒有最好,只有最適合!
- It’s just the beginning!
JSF遇到京東彈性云
京東的JSF服務開發在京東彈性云的研發推廣之前完成,自從京東彈性云落地以來,也遇到不少問題。
例如:
JSF規模
總結
意思就是不要人云亦云,盲目看大公司用什么,現在什么最新,或者什么性能最好。因為架構不是讓你一下子設計出來使用一輩子,好的架構都是慢慢演化而來的。不同的架構會做出不同的技術選型。所以無論什么時候都要結合自己的現狀以及未來幾年的規劃,來進行技術選型。
服務化框架的選擇只是開始,真正的變革是選擇后,公司整體業務和開發的變革。這個大家有空可以看看康威定律。
來自:http://geek.csdn.net/news/detail/136391
JSF RPC框架
RPC框架作為服務化里面的最基本的組件,其實都大同小異,因為RPC調用都繞不開代理、網絡、序列化這些操作。
JSF的RPC框架也類似,主要分為圖中的幾個模塊,
下面大概列下一些功能特性:
JSF管理平臺
提供強大管理功能,包括服務管理,監控管理,注冊中心管理等功能。
我們針對服務治理的功能,提供了很多API,可以授權給開發人員或者外部系統使用。
例如單元測試調用,限流配置/開關,動態分組,上下線等都提供了開放API。
JSF HTTP網關
網關是為了方便跨語言通過HTTP+JSON調用JSF服務,而不需要使用JSF的RPC框架。
特性如下: