Spring cloud(2)-服務發現(Eureka,Consul)

ohcomeyes發表於2018-10-24

在分散式系統領域有個著名的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 節點的可用性來確保叢集資料的一致性。

    raft

  • paxos: 第一次由提交者Leader向所有其他伺服器發出prepare訊息請求準備,所有伺服器中大多數如果回覆諾言承諾就表示準備好了,可以接受寫入;第二次提交者向所有伺服器發出正式建議propose,所有伺服器中大多數如果回覆已經接收就表示成功了。

  • long polling:長輪詢,客戶端向伺服器傳送Ajax請求,伺服器接到請求後hold住連線,直到有新訊息才返回響應資訊並關閉連線,客戶端處理完響應資訊後再向伺服器傳送新的請求。

  • metrics:作為一款監控指標的度量類庫,它提供了很多模組可以為第三方庫或者應用提供輔助統計資訊, 它還可以將度量資料傳送給Ganglia和Graphite以提供圖形化的監控

  • Eureka的自我保護模式
    Eureka Server在執行期間,會統計心跳失敗的比例在15分鐘之內是否 低於85%,如果出現低於的情況(實際在 生產環境上通常是由於網 絡不穩定導致),Eureka Server會將當前的例項註冊資訊保護起來,同時提 示警告。保護模式主要用於一組客戶端和Eureka Server之間存在網路分 區場景下的保護。一旦進入保護模式,Eureka Server將會嘗試保護其服務注 冊表中的資訊,不再刪除服務登錄檔中的資料(也就是不會登出任何微服務)。
    所以Eureka的哲學是,同時保留”好資料“”壞資料“總比丟掉任何”好資料“要更好,所以這種模式在實踐中非常有效。,

為啥不使用zookeeper做發現服務呢?

  1. ZooKeeper是分散式協調服務,它的職責是保證資料(注:配置資料,狀態資料)在其管轄下的所有服務之間保持同步、一致;(強一致性)
  2. 發現服務的核心應該是需要強調服務的高可用
  3. ZooKeeper使用單一主程式Leader用於處理客戶端所有事務請求,採用ZAB協議將伺服器數狀態以事務形式廣播到所有Follower上;如果三臺服務掛了兩臺怎麼選出leader1 不大於 (3/2)=1的
  4. 正確的設定與維護ZooKeeper服務就非常的困難
  5. 叢集中出現了網路分割的故障(交換機故障導致交換機底下的子網間不能互訪)ZooKeeper會將它們都從自己管理範圍中剔除出去,外界就不能訪問到這些節點了,本身這些節點是“健康”的,能提供服務的
  6. 發現服務就算是返回了包含不實的資訊的結果也比什麼都不返回要好(因為暫時的網路故障而找不到可用的伺服器)

因此, 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是什麼?

RibbonNetflix釋出的開源專案,主要功能是提供客戶端的軟體負載均衡演算法,將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官方建議使用第二種方式。
  1. 一種是通過consul的服務註冊http API,由服務自己呼叫API實現註冊,
  2. 另一種方式是通過json個是的配置檔案實現註冊,將需要註冊的服務以json格式的配置檔案給出。
  • 服務發現:支援兩種方式實現服務發現,
  1. 一種是通過http API來查詢有哪些服務,
  2. 另外一種是通過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 吧~
個人部落格~
簡書~

相關文章