在分散式系統領域有個著名的CAP定理
(C-資料一致性
;A-服務可用性
;P-服務對網路分割槽故障的容錯性
,這三個特性在任何分散式系統中不能同時滿足,最多同時滿足兩個
);
eureka是AP
,zookeeper是CP
。對於服務發現
而言,可用性
比資料一致性
更加重要——AP勝過CP
Consul | zookeeper | euerka | etcd | |
---|---|---|---|---|
服務健康檢查 | 服務狀態,記憶體,硬碟等 | (弱)長連線,keepalive | 可配支援 | 連線心跳 |
多資料中心 | 支援 | — | — | — |
kv儲存服務 | 支援 | 支援 | — | 支援 |
一致性 | raft | paxos | — | raft |
CAP | ca | cp | ap | cp |
使用介面(多語言能力) | 支援http和dns | 客戶端 | http(sidecar) | http/grpc |
watch支援(客戶端觀察到服務提供者變化) | 全量/支援long polling | 支援 | 支援long polling/大部分增量 | 支援long polling |
自身監控 | metrics | — | metrics | metrics |
安全 | acl /https | acl | — | https支援(弱) |
spring cloud整合 | 已支援 | 已支援 | 已支援 | 已支援 |
-
raft
:Raft強依賴 Leader 節點的可用性來確保叢集資料的一致性。 -
paxos
: 第一次由提交者Leader向所有其他伺服器發出prepare訊息請求準備,所有伺服器中大多數如果回覆諾言承諾就表示準備好了,可以接受寫入;第二次提交者向所有伺服器發出正式建議propose,所有伺服器中大多數如果回覆已經接收就表示成功了。 -
long polling
:長輪詢,客戶端向伺服器傳送Ajax請求,伺服器接到請求後hold住連線,直到有新訊息才返回響應資訊並關閉連線,客戶端處理完響應資訊後再向伺服器傳送新的請求。 -
metrics
:作為一款監控指標的度量類庫,它提供了很多模組可以為第三方庫或者應用提供輔助統計資訊, 它還可以將度量資料傳送給Ganglia和Graphite以提供圖形化的監控 -
Eureka的自我保護模式
Eureka Server
在執行期間,會統計心跳失敗的比例在15分鐘之內是否 低於85%,如果出現低於的情況(實際在 生產環境上通常是由於網 絡不穩定導致),Eureka Server
會將當前的例項註冊資訊保護起來,同時提 示警告。保護模式主要用於一組客戶端和Eureka Server
之間存在網路分 區場景下的保護。一旦進入保護模式,Eureka Server
將會嘗試保護其服務注 冊表中的資訊,不再刪除服務登錄檔中的資料(也就是不會登出任何微服務)。
所以Eureka
的哲學是,同時保留”好資料“
與”壞資料“
總比丟掉任何”好資料“要更好,所以這種模式在實踐中非常有效。,
為啥不使用zookeeper做發現服務呢?
ZooKeeper
是分散式協調服務,它的職責是保證資料(注:配置資料,狀態資料)在其管轄下的所有服務之間保持同步、一致;(強一致性)- 發現服務的核心應該是需要強調服務的高可用
ZooKeeper
使用單一主程式Leader
用於處理客戶端所有事務請求,採用ZAB協議
將伺服器數狀態以事務形式廣播到所有Follower
上;如果三臺服務掛了兩臺怎麼選出leader
;1 不大於 (3/2)=1的
,- 正確的設定與維護
ZooKeeper服務
就非常的困難 - 叢集中出現了網路分割的故障(交換機故障導致交換機底下的子網間不能互訪)
ZooKeeper
會將它們都從自己管理範圍中剔除出去,外界就不能訪問到這些節點了,本身這些節點是“健康”
的,能提供服務的 - 發現服務就算是返回了
包含不實的資訊的結果也比什麼都不返回要好
(因為暫時的網路故障而找不到可用的伺服器)
因此, Eureka
可以很好的應對因網路故障導致部分節點失去聯絡的情況,而不會像zookeeper
那樣使整個註冊服務癱瘓。
Spring Cloud Eureka(服務註冊)
- 新增依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
複製程式碼
- 開啟服務註冊
通過 @EnableEurekaServer
註解啟動一個服務註冊中心提供給其他應用進行對話,這個註解需要在springboot工程
的啟動application類
上加
package io.ymq.example.eureka.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
複製程式碼
Spring Cloud Service Provider(服務提供者)
- 服務提供方
- 將自身服務註冊到 Eureka 註冊中心,從而使服務消費方能夠找到
- 新增依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
複製程式碼
- 開啟服務註冊
在應用主類中通過加上@EnableEurekaClient
,但只有Eureka
可用,你也可以使用@EnableDiscoveryClient
。需要配置才能找到Eureka註冊中心伺服器
discovery service
有許多種實現(eureka、consul、zookeeper
等)
@EnableDiscoveryClient
基於spring-cloud-commons
,
@EnableEurekaClient
基於spring-cloud-netflix
。
就是如果選用的註冊中心是eureka
,那麼就推薦@EnableEurekaClient
,
如果是其他的註冊中心,那麼推薦使用@EnableDiscoveryClient
。
@SpringBootApplication
@EnableEurekaClient
@RestController
public class EurekaProviderApplication {
@RequestMapping("/")
public String home() {
return "Hello world";
}
public static void main(String[] args) {
SpringApplication.run(EurekaProviderApplication.class, args);
}
}
複製程式碼
- 新增配置 application.yml
新增配置找到Eureka伺服器
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: eureka-provider
server:
port: 8081
複製程式碼
Spring Cloud Service Consumer(服務消費者)
向Eureka
註冊服務,消費者使用Ribbon
開啟負載均衡
Ribbon是什麼?
Ribbon
是Netflix
釋出的開源專案,主要功能是提供客戶端的軟體負載均衡演算法,將Netflix
的中間層服務連線在一起。Ribbon
客戶端元件提供一系列完善的配置項如連線超時,重試等。簡單的說,就是在配置檔案中列出Load Balancer(簡稱LB)
後面所有的機器,Ribbon
會自動的幫助你基於某種規則(如簡單輪詢,隨即連線等)
去連線這些機器。我們也很容易使用Ribbon
實現自定義的負載均衡演算法。
Ribbon的核心元件
Ribbon
在工作時首選會通過ServerList
來獲取所有可用的服務列表,然後通過ServerListFilter
過慮掉一部分地址,最後在剩下的地址中通過IRule
選擇出一臺伺服器作為最終結果。
ServerList
:用於獲取地址列表。它既可以是靜態的(提供一組固定的地址),也可以是動態的(從註冊中心中定期查詢地址列表)。ServerListFilter
:僅當使用動態ServerList
時使用,用於在原始的服務列表中使用一定策略過慮掉一部分地址。IRule
:選擇一個最終的服務地址作為LB結果
。選擇策略有輪詢、根據響應時間加權、斷路器(當Hystrix可用時)
等。
Ribbon提供的主要負載均衡策略
簡單輪詢負載均衡(RoundRobin)
: 以輪詢的方式依次將請求排程不同的伺服器,即每次排程執行i = (i + 1) mod n,並選出第i臺伺服器。隨機負載均衡 (Random)
: 隨機選擇狀態為UP的Server加權響應時間負載均衡 (WeightedResponseTime)
: 根據相應時間分配一個weight,相應時間越長,weight越小,被選中的可能性越低。區域感知輪詢負載均衡(ZoneAvoidanceRule)
:複合判斷server所在區域的效能和server的可用性選擇server
服務提供者(提供服務)
- 開啟服務註冊 註冊三臺
@SpringBootApplication
@EnableEurekaClient
@RestController
public class EurekaProviderApplication {
@Value("${server.port}")
String port;
@RequestMapping("/")
public String home() {
return "Hello world ,port:" + port;
}
public static void main(String[] args) {
SpringApplication.run(EurekaProviderApplication.class, args);
}
}
複製程式碼
- 新增配置 application.yml
埠依次為8081,8082,8083
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: eureka-provider
server:
port: 8081
複製程式碼
服務消費者(依賴於其它服務)
- pom.xml新增依賴
<!-- 客戶端負載均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<!-- eureka客戶端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
複製程式碼
- 開啟服務負載均衡
通過@EnableDiscoveryClient向服務註冊中心註冊;並且向程式的ioc注入一個bean: restTemplate並通過@LoadBalanced註解表明這個restRemplate開啟負載均衡的功能
@EnableDiscoveryClient
@SpringBootApplication
public class RibbonConsumerApplication {
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class, args);
}
}
複製程式碼
- 消費提供者方法
/**
* 描述:呼叫提供者的 `home` 方法
**/
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "/hello")
public String hello() {
return restTemplate.getForEntity("http://eureka-provider/", String.class).getBody();
}
}
複製程式碼
- 新增配置 application.yml
指定服務的註冊中心地址,配置自己的服務埠,服務名稱
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: ribbon-consumer
server:
port: 9000
複製程式碼
依次啟動服務(Eureka服務,三臺service provider和service Consumer)
,檢視ribbon
是否開啟負載均衡
Spring Cloud Consul(針對Consul的服務治理實現)
由於Consul
自身提供了服務端,所以我們不需要像之前實現Eureka
的時候建立服務註冊中心,直接通過下載consul的服務端程式就可以使用。
Consul
內建了服務註冊
與發現框架
(一站式)、具有以下性質(參考上面列表):
- 分佈一致性協議實現
- 健康檢查
- Key/Value儲存
- 多資料中心方案
Consul的優勢
- 使用 Raft 演算法來保證一致性, 比複雜的 Paxos 演算法更直接
- 支援多資料中心,內外網的服務採用不同的埠進行監聽
- 多資料中心叢集可以避免單資料中心的單點故障,而其部署則需要考慮網路延遲, 分片等情況等
- 支援健康檢查
- 支援 http 和 dns 協議介面
- 官方提供web管理介面
Consul的角色
client
:客戶端, 無狀態, 將 HTTP 和 DNS 介面請求轉發給區域網內的服務端叢集,所有註冊到當前節點的服務會被轉發到server,本身是不持久化這些資訊server
:服務端, 儲存配置資訊, 高可用叢集, 在區域網內與本地客戶端通訊,功能和client都一樣,唯一不同的是,它會把所有的資訊持久化的本地,這樣遇到故障,資訊是可以被保留的。 通過廣域網與其他資料中心通訊. 每個資料中心的 server 數量推薦為 3 個或是 5 個.server-leader
:表明這個server是它們的老大,它和其它server不一樣的一點是,它需要負責同步註冊的資訊給其它的server,同時也要負責各個節點的健康監測。raft
:server節點之間的資料一致性保證,一致性協議使用的是raft,而zookeeper用的paxos,etcd採用的也是taft。服務發現協議
:consul採用http和dns協議,etcd只支援http服務註冊
:支援兩種方式實現服務註冊,consul官方建議使用第二種方式。
- 一種是通過consul的服務註冊http API,由服務自己呼叫API實現註冊,
- 另一種方式是通過json個是的配置檔案實現註冊,將需要註冊的服務以json格式的配置檔案給出。
服務發現
:支援兩種方式實現服務發現,
- 一種是通過http API來查詢有哪些服務,
- 另外一種是通過consul agent 自帶的DNS(8600埠),域名是以NAME.service.consul的形式給出,NAME即在定義的服務配置檔案中,服務的名稱。DNS方式可以通過check的方式檢查服務。
- 服務間的通訊協議:Consul使用gossip協議管理成員關係、廣播訊息到整個叢集
結語
關於consul
的環境搭建以及應用後續再補充吧~
在github
上有關於Spring Cloud
完整的部署。
其它相關文章
Spring cloud(1)-簡介以及選擇
Spring cloud(2)-服務發現(Eureka,Consul)
Spring cloud(3)-負載均衡(Feign,Ribbon)
Spring cloud(4)-熔斷(Hystrix)
Spring cloud(5)-路由閘道器(Zuul)
Spring cloud(6)-配置管理及重新整理(Config,Bus)
最後,給個 star 吧~
個人部落格~
簡書~