原文: 服務(wù)發(fā)現(xiàn)——需求與模式
date: 2019-04-19 15:10:49
[TOC]
前言
從自成一體的單體應(yīng)用到分布式應(yīng)用, 演進出了面向服務(wù)架構(gòu)
服務(wù)發(fā)現(xiàn)的本質(zhì)在于讓服務(wù)之間發(fā)現(xiàn)彼此, 這是服務(wù)提供方與服務(wù)消費方完成消費的前提
在微服務(wù)架構(gòu)下, 無論是使用Dubbo, Thrift, gRPC這類標準的PRC實現(xiàn)進行通訊, 還是微服務(wù)所倡導(dǎo)的RESTful風(fēng)格API, 服務(wù)發(fā)現(xiàn)都是一個避不開的話題
需求
來舉例一個簡單的場景:

在固定數(shù)量, 固定地址的情況下, Consumer當然可以將服務(wù)提供者的地址寫死到自己的應(yīng)用內(nèi), 按照隨機或輪詢的策略去訪問服務(wù)提供者
但在云時代, 微服務(wù)的架構(gòu)下作為服務(wù)提供者的實例不一定運行在傳統(tǒng)的物理機/虛擬機上, 網(wǎng)絡(luò)地址動態(tài)變化, 實例數(shù)量還可能依據(jù)訪問流量進行動態(tài)伸縮
其中有兩個最核心的問題:
消費者怎么找到服務(wù)提供者? ——服務(wù)發(fā)現(xiàn)
在找到多個提供者實例后, 選擇哪個實例來消費服務(wù)? ——負載均衡
可見, 服務(wù)發(fā)現(xiàn)和負載均衡是分布式架構(gòu)最根本的問題, 同樣也應(yīng)該作為微服務(wù)的基礎(chǔ)框架/組件
方案
目前主要分為兩類模式: 客戶端發(fā)現(xiàn)和服務(wù)端發(fā)現(xiàn), 也就是client-side discovery pattern and server-side discovery pattern
下面來介紹幾種典型模式
- 集中式(傳統(tǒng))
- 客戶端嵌入式(進程內(nèi))
- 主機獨立進程
這幾種模式都有業(yè)界較好的實踐方案及開源組件
一: 集中式

常用的獨立LB可以使用硬件: F5 或軟件: Nginx 等
獨立LB中需要手工配置服務(wù)列表的地址, 例如在Nginx中配置服務(wù)列表:
upstream service_provider {
server 192.168.100.100:8080...;
server 192.168.100.101:8080...;
}
軟負載的特點是配置靈活且易于擴展, 還可以與硬件負載均衡器性能穩(wěn)定, 負載能力強的特點結(jié)合使用.
例如F5下配多個Nginx, 對其進行負載均衡, 多個Nginx再對后臺服務(wù)進行負載均衡
這種方式重點提供的是LB能力, 而"服務(wù)發(fā)現(xiàn)"通常是在F5或Nginx上配置來實現(xiàn)的, 其功能對客戶端來說是透明的
這種模式相對簡單, 在中小型公司中是很主流的方案
二: 客戶端嵌入式
也可以稱為進程內(nèi)代理

這種模式下, 多了一個注冊中心, 也是服務(wù)注冊表的概念, 并且在客戶端會集成一個類似SDK的東西:
- 對于服務(wù)提供者(Provider)來講: 它需要注冊到注冊中心, 定期進行heartbeat檢測
- 對于消費者(Consumer)來講: 首先它能夠從注冊中心獲取服務(wù)的實例, 也就是具備服務(wù)發(fā)現(xiàn)的能力
其次獲取到服務(wù)列表后選擇一個進行調(diào)用, 也就是具備負載均衡的能力
通常情況下, 整個過程可以做到自發(fā)現(xiàn)和自注冊, 無需其它代理的介入
三: 主機獨立進程式

這種模式類似于上面一種, 區(qū)別在于提供服務(wù)發(fā)現(xiàn)和負載均衡能力的組件沒有嵌入每個客戶端內(nèi), 而是放在了同一主機下, 可以理解為同一主機下的不同進程
四: Other
實際中除了上述三種模式外, 還有很多變種和折中方案, 例如集中式的代理結(jié)合服務(wù)注冊中心實現(xiàn)服務(wù)的注冊于發(fā)現(xiàn)
以注冊中心Eureka Server為例, 可以提供UI/API對接發(fā)布系統(tǒng)或是手工注冊, 以及定期的健康檢查, 而無需在客戶端集成Eureka Client, 集中式的Proxy需要同步注冊中心中的服務(wù)地址
總結(jié)
可以看到, 以上三種最典型的方案中, 相同點都是把具備服務(wù)發(fā)現(xiàn)和負載均衡能力的組件交給一個類似Proxy的角色中
而區(qū)別在于該角色所處的位置, 放入客戶端內(nèi)還是客戶端外, 這也對應(yīng)了兩種分類: 客戶端發(fā)現(xiàn)與服務(wù)端發(fā)現(xiàn), 客戶端負載與服務(wù)端負載
通過以上幾種方案的說明, 我們可以理清它的分類:

優(yōu)劣性
每種方式都各有優(yōu)略, 沒有絕對, 主要從這幾方面來對比
可用性 & 性能
集中式方案中如果LB Proxy角色掛了, 那么影響的是所有客戶端, 由于這種單點問題, 為了保證HA軟負載通常需要部署多個, 好在Nginx無狀態(tài)可水平擴展
進程內(nèi)的方案如果客戶端/Proxy掛了只對自己產(chǎn)生影響, 而主機獨立進程的方案相對折中, 影響面僅為同一主機下的客戶端
從圖中能看出集中式的方案在服務(wù)的調(diào)用上會多一跳, 有一定的性能開銷
語言棧
相較其它兩種, 嵌入式的客戶端需要對針對客戶端做集成和改造才能實現(xiàn)自注冊和自發(fā)現(xiàn), 說的難聽點就是需要對服務(wù)有一定的侵入
并且這種改造需針對每種語言棧的服務(wù)定制
Netflix Eureka & Ribbon是該模式最典型的實現(xiàn), 對于Java語言棧, 這一切都變得輕松.
微服務(wù)的異構(gòu)旨在不同的數(shù)據(jù)庫和語言棧, Eureka服務(wù)端提供了完善的REST API, 對于其它非Java語言棧只需實現(xiàn)自己語言對應(yīng)的Eureka客戶端程序, 就可以將非Java實現(xiàn)的服務(wù)納入自己的服務(wù)治理體系
統(tǒng)一管控
從圖中也能看出, 集中式方案可以做到集中式的訪問控制, 而客戶端進程內(nèi)的模式則不易做到統(tǒng)一的管控, 主機獨立進程的方式在兩者之中
對比
相信通過以上三種典型模式的了解, 對于業(yè)界常見的一些服務(wù)發(fā)現(xiàn)組件對應(yīng)哪種模式應(yīng)該很清楚了, 例如:
客戶端發(fā)現(xiàn): Netflix Eureka, Apache Dubbo, Motan
服務(wù)端發(fā)現(xiàn): Nginx, Zookeeper, Kubernetes
而獨立于主機進程的代理更像是Service Mesh的風(fēng)格
| 模式 | 優(yōu)點 | 缺點 | 適用場景 |
|---|---|---|---|
| 集中式代理 | 運維簡單, 集中治理, 語言棧無關(guān) | 配置麻煩, 單點問題, 多一跳有性能開銷 | 具備一定運維能力 |
| 客戶端嵌入式代理 | 無單點問題, 性能較好 | 客戶端復(fù)雜, 不易集中治理, 語言棧相關(guān) | 語言棧統(tǒng)一 |
| 主機獨立進程代理 | 以上兩者折中 | 運維部署較復(fù)雜 | 具備一定運維能力 |