原文地址:https://microservices.io/patterns/client-side-discovery.html
服務之間需要互相調用,在單體架構中,服務之間的互相調用直接通過編程語言層面的方法調用就搞定了。在傳統的分佈式應用的部署中,服務地址和端口是固定並且提前預知的,所以只需要簡單的 HTTP/REST 調用或者其他的 RPC 機制直接調用即可。但是在當下的雲原生微服務體系中,微服務大多在某個虛擬機或者某個容器下運行,服務實例數量以及提供服務的地址以及端口都是不固定的,可以理解爲,這些服務實例都是臨時的。所以,需要實現使服務客戶端能夠對一組動態變化的臨時服務實例發請求的機制。
提出問題
某個服務的客戶端,API網關或者一些其他需要發現服務實例的服務,如何知道服務實例的位置?
考慮因素
- 服務的每個實例都在特定的位置(主機和端口)暴露一個遠程 API,例如 HTTP/REST 或 Thrift 等
- 服務實例的數量及其位置都會動態變化
- 虛擬機和容器通常分配動態 IP 地址
- 服務實例的數量可能動態變化。例如,AWS 的 EC2 自動擴容組可以根據 LOAD(負載)動態調整實例數量。
解決方案
當想請求一個服務時,客戶端查詢一個公共的服務登記處(Service Registry,我們一般稱爲註冊中心),來查詢要調用的服務有哪些實例,並在地址是哪裏。如下圖所示:
舉例
這裏用 Scala 語言,Spring Boot 和 Spring Cloud 框架舉個例子,Spring Cloud 的服務發現主要就是基於客戶端服務發現的。
RegistrationServiceProxy 是該應用程序的一個組件,用於註冊用戶:
@Component
class RegistrationServiceProxy @Autowired()(restTemplate: RestTemplate) extends RegistrationService {
@Value("${user_registration_url}")
var userRegistrationUrl: String = _
override def registerUser(emailAddress: String, password: String): Either[RegistrationError, String] = {
val response = restTemplate.postForEntity(userRegistrationUrl,
RegistrationBackendRequest(emailAddress, password),
classOf[RegistrationBackendResponse])
...
}
這個類注入了 RestTemplate
以及 user_registration_url
,當這個應用被部署的時候,user_registration_url
實際爲http://REGISTRATION-SERVICE/user
,REGISTRATION-SERVICE
是客戶端用來做服務發現的服務名稱。服務發現通過 Netflix OSS 組件實現,包括 作爲註冊中心的 Eureka,以及查詢 Eureka 獲取實例來做 Http 請求調用的 Ribbon。
客戶端服務發現使用各種 Spring Cloud 註解進行配置:
@Configuration
@EnableEurekaClient
@Profile(Array("enableEureka"))
class EurekaClientConfiguration {
@Bean
@LoadBalanced
def restTemplate(scalaObjectMapper : ScalaObjectMapper) : RestTemplate = {
val restTemplate = new RestTemplate()
restTemplate.getMessageConverters foreach {
case mc: MappingJackson2HttpMessageConverter =>
mc.setObjectMapper(scalaObjectMapper)
case _ =>
}
restTemplate
}
@EnableEurekaClient
註解啓用了 Eureka 客戶端。@LoadBalanced
註解配置 RestTemplate
使用已配置爲使用 Eureka 客戶端進行服務發現的 Ribbon 進行遠程調用。因此,RestTemplate 將通過對 http://REGISTRATION-SERVICE/user
解析拿到服務名稱,之後通過查詢 Eureka 查找可用服務實例的網絡位置來進行請求。
分析
客戶端服務發現的優點:
- 與服務端服務發現相比,網絡中間組件和網絡跳轉更少一些
客戶端服務發現的缺點:
- 與註冊中心耦合,不同的註冊中心註冊邏輯不一樣。
- 需要實現不同語言的客戶端服務發現邏輯。
相關設計模式
- 服務登記處(Service Registry,或者稱爲註冊中心)
- 微服務基礎框架
- 服務端服務發現是這個設計模式的替代品