服務(wù)治理
服務(wù)治理是微服務(wù)架構(gòu)中最為核心和基礎(chǔ)的模塊,它主要用來(lái)實(shí)現(xiàn)各個(gè)微服務(wù)實(shí)例的自動(dòng)化注冊(cè)和發(fā)現(xiàn)。
在微服務(wù)架構(gòu)體系中,每個(gè)服務(wù)都是相對(duì)獨(dú)立的,包括其部署、擴(kuò)展和升級(jí),都不應(yīng)和其他服務(wù)產(chǎn)生耦合。但是微服務(wù)之間是無(wú)法避免業(yè)務(wù)關(guān)系的,也就是說(shuō)服務(wù)之間需要互相調(diào)用。對(duì)于Restful接口而言,服務(wù)A要調(diào)用服務(wù)B的接口,必須知道具體的url,這樣服務(wù)A就必須與服務(wù)B的部署位置產(chǎn)生依賴(lài)關(guān)系。另一方面,為了實(shí)現(xiàn)服務(wù)B的高可用,不論采用服務(wù)端負(fù)載均衡還是客戶(hù)端負(fù)載均衡,都需要手工維護(hù)服務(wù)B的實(shí)例列表。
為了解決微服務(wù)架構(gòu)中的服務(wù)實(shí)例維護(hù)問(wèn)題,產(chǎn)生了大量的服務(wù)治理框架和產(chǎn)品。服務(wù)治理的功能主要有一下幾點(diǎn):
- 對(duì)開(kāi)發(fā)新服務(wù)和升級(jí)現(xiàn)有服務(wù)的計(jì)劃管理服務(wù)的生命周期;
- 確保升級(jí)服務(wù)不會(huì)影響目前的服務(wù)消費(fèi)者制定方針來(lái)限制服務(wù)行為;
- 制定所有服務(wù)都要遵從的規(guī)則,確保服務(wù)的一致性監(jiān)控服務(wù)的性能;
- 由于服務(wù)組合,服務(wù)停機(jī)和性能低下的后果是嚴(yán)重的。通過(guò)監(jiān)控服務(wù)的性能和可用性,當(dāng)問(wèn)題出現(xiàn)的時(shí)候能馬上采取應(yīng)對(duì)措施;
- 管理由誰(shuí)來(lái)調(diào)用服務(wù)、怎樣調(diào)用服務(wù)
服務(wù)注冊(cè)
在服務(wù)治理框架中,通常需要一個(gè)注冊(cè)中心。每個(gè)服務(wù)想注冊(cè)中心登記自己提供的服務(wù),將服務(wù)的位置、調(diào)用方式等告知注冊(cè)中心。注冊(cè)中心會(huì)按服務(wù)名分類(lèi)組織分類(lèi)清單。另外服務(wù)注冊(cè)中心還需定時(shí)監(jiān)控清單中的服務(wù)的健康狀態(tài),及時(shí)剔除不可用的實(shí)例。
服務(wù)發(fā)現(xiàn)
在服務(wù)治理框架下,服務(wù)之間的調(diào)用不在依賴(lài)于服務(wù)的具體位置(如ip:port),而是通過(guò)服務(wù)名調(diào)用,從而將服務(wù)的部署從微服務(wù)的調(diào)用中解決關(guān)聯(lián)。通過(guò)服務(wù)名調(diào)用,還可以方便地實(shí)現(xiàn)負(fù)載均衡。由于服務(wù)注冊(cè),我們有一份清單可以找到某個(gè)服務(wù)的具體實(shí)例,若是服務(wù)不止一個(gè)實(shí)例,我們可以很方便地動(dòng)態(tài)選擇服務(wù)的實(shí)例進(jìn)行調(diào)用,從而實(shí)現(xiàn)負(fù)載均衡。這也有利于服務(wù)的橫向擴(kuò)展,實(shí)現(xiàn)高可用。
Spring Cloud Eureka
Netflix Eureka是Netflix開(kāi)發(fā)的一套基于jvm和restful的服務(wù)治理框架。其服務(wù)端是用java語(yǔ)言編寫(xiě),主要適用于java實(shí)現(xiàn)的分布式系統(tǒng)。但是其通信協(xié)議為基于http的restful,所以客戶(hù)端理論上用什么語(yǔ)言實(shí)現(xiàn)都可以。這也是微服務(wù)的一大特點(diǎn),服務(wù)可以根據(jù)自身特點(diǎn)選用相應(yīng)的語(yǔ)言或平臺(tái)實(shí)現(xiàn),不必局限于同一的平臺(tái)。
搭建服務(wù)注冊(cè)中心
Spring Cloud中的微服務(wù)就是一個(gè)個(gè)Spring Boot應(yīng)用程序,服務(wù)注冊(cè)中心也不例外。按上篇文章的步驟,搭建一個(gè)spring boot模塊。


修改build.gradle,引入spring-cloud-starter-eureka-server
group 'com.zhuangqf.demo'
version '1.0-SNAPSHOT'
dependencies {
compile "org.springframework.cloud:spring-cloud-starter-eureka-server"
compile "org.springframework.boot:spring-boot-starter-web"
}
添加Application啟動(dòng)類(lèi),通過(guò)EnableEurekaServer注解啟動(dòng)一個(gè)注冊(cè)服務(wù)中心。
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
添加application.yml:
spring:
application:
name: eureka-server
server:
port: 9000
eureka:
instance:
instance-id: ${spring.cloud.client.ipAddress}:${server.port}
hostname: ${spring.cloud.client.ipAddress}
client:
fetch-registry: false
register-with-eureka: false
serviceUrl.defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
先重點(diǎn)關(guān)注eureka.client配置:
- eureka.client.fetch-registry 默認(rèn)為true,是否拉取注冊(cè)的實(shí)例信息,注冊(cè)中心不需要遠(yuǎn)程調(diào)用實(shí)例,所以不需要檢索服務(wù),設(shè)為false。
- eureka.client.register-with-eureka 對(duì)于單注冊(cè)中心,不需要向自己注冊(cè)
- eureka.client.serviceUrl.defaultZone 注冊(cè)中心地址

接入客戶(hù)端
注冊(cè)中心已經(jīng)跑起來(lái)了,那么怎么讓我們的服務(wù)注冊(cè)到注冊(cè)中心呢?讓我們對(duì)之前寫(xiě)過(guò)的example模塊做一些改造。
在example模塊的build.gradle中添加依賴(lài)
compile "org.springframework.cloud:spring-cloud-starter-eureka"
相應(yīng)的,在Application類(lèi)加一個(gè)注解:
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
public static void main(String[] arg) {
SpringApplication.run(Application.class,arg);
}
}
接著,在application.yml中指定注冊(cè)地址:
eureka:
instance:
instance-id: ${spring.cloud.client.ipAddress}:${server.port}
hostname: ${spring.cloud.client.ipAddress}
client:
serviceUrl.defaultZone: http://localhost:9000/eureka/

高可用注冊(cè)中心
高可用集群是指以減少服務(wù)中斷時(shí)間為目的的服務(wù)器集群技術(shù)。它通過(guò)保護(hù)用戶(hù)的業(yè)務(wù)程序?qū)ν獠婚g斷提供的服務(wù),把因軟件/硬件/人為造成的故障對(duì)業(yè)務(wù)的影響降低到最小程度。
在微服務(wù)架構(gòu)系統(tǒng)中,故障是不可能避免的。Eureka Server的設(shè)計(jì)一開(kāi)始就考慮了高可用的問(wèn)題,在Eureka的服務(wù)治理設(shè)計(jì)中,所有節(jié)點(diǎn)既是服務(wù)提供方,又是服務(wù)消費(fèi)方,服務(wù)注冊(cè)中心也不例外。
Eureka Server的高可用實(shí)際上是將自己作為服務(wù)向其他服務(wù)注冊(cè)中心注冊(cè)自己,這樣就可以形成一組互相注冊(cè)的服務(wù)注冊(cè)中心。注冊(cè)中心之間會(huì)共享彼此的服務(wù)清單,注冊(cè)中心可以在一個(gè)zone中,也可以按業(yè)務(wù)或服務(wù)的部署位置分為多個(gè)zone。
在這里,我們先簡(jiǎn)單實(shí)現(xiàn)同一個(gè)zone的兩個(gè)注冊(cè)中心,讓它們彼此注冊(cè),實(shí)現(xiàn)高可用。
首先,在eureka-server的application.yml中增加以下配置
-- peer1
server.port: 9001
eureka:
client:
fetch-registry: true
register-with-eureka: true
serviceUrl.defaultZone: http://${eureka.instance.hostname}:9002/eureka
-- peer2
server.port: 9002
eureka:
client:
fetch-registry: true
register-with-eureka: true
serviceUrl.defaultZone: http://${eureka.instance.hostname}:9001/eureka
peer1和peer2是可選的兩組配置,在配置中,我們從彼此注冊(cè)到對(duì)方。

分別啟動(dòng)peer1和peer2


啟動(dòng)example
修改example的注冊(cè)服務(wù)器地址:

此時(shí),peer1或者peer2有一個(gè)出現(xiàn)故障在短時(shí)間內(nèi)不會(huì)對(duì)系統(tǒng)的業(yè)務(wù)有太大的影響,因?yàn)榱硪粋€(gè)注冊(cè)中心可以臨時(shí)性承接所有的流量。