1. 簡介
本文將介紹如何使用Zookeeper
在微服務框架中實現服務發現,該服務發現機制可作為雲服務的注冊中心。通過Spring Cloud Zookeeper
為應用程序提供一種Spring Boot集成,將Zookeeper通過自動配置和綁定 的方式集成到Spring環境中。
在本例子中我們將創建兩個應用程序:
- 提供服務的應用程序(稱為
服務提供者
) - 使用此服務的應用程序(稱為
服務消費者
)
2. 安裝Zookeeper
2.1 下載
Apache官方最新版本為:3.4.8
下載地址:http://mirrors.cnnic.cn/apache/zookeeper/zookeeper-3.4.8/zookeeper-3.4.8.tar.gz
2.2 安裝
解壓到指定目錄下 D:\soft\zookeeper-3.4.8
修改zoo_sample.cfg 文件名(D:\soft\zookeeper-3.4.8\conf) 為 zoo.cfg
主要修改一下日志位置,具體配置文件如下:
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=D:\\zookeeper\\data
dataLogDir=D:\\zookeeper\\log
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
tickTime
:這個時間是作為 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發送一個心跳。dataDir
:顧名思義就是 Zookeeper 保存數據的目錄,默認情況下,Zookeeper 將寫數據的日志文件也保存在這個目錄里。dataLogDir
:顧名思義就是 Zookeeper 保存日志文件的目錄clientPort
:這個端口就是客戶端連接 Zookeeper 服務器的端口,Zookeeper 會監聽這個端口,接受客戶端的訪問請求。
2.3 啟動
進入到bin目錄,並且啟動zkServer.cmd,這個腳本中會啟動一個java進程,雙擊該文件即可啟動:
3. 搭建服務提供者
我們將創建一個服務提供者,通過增加pring-cloud-starter-zookeeper-discovery依賴和在主程序中引入@EnableDiscoveryClient注釋。服務的具體內容是通過GET請求返回“Hello World!”字符串。
整個項目結構如下:
3.1 導入依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yiidian</groupId>
<artifactId>spring-cloud-zookeeper-proivder</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- SpringBoot 對Web支持 SpringMVC相關功能,json轉換的功能等等 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
</dependencies>
<!-- 定義SpringCloud版本 -->
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.M9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3.2 啟動類
使用@EnableDiscoveryClient注釋我們的主類,這將使HelloWorld 應用程序自動發布。
package com.yiidian.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* 服務提供者啟動類
*/
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderStarter {
public static void main(String[] args) {
SpringApplication.run(ProviderStarter.class,args);
}
}
3.3 Controller
package com.yiidian.provider.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 一點教程網: http://www.yiidian.com
* 控制器
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "Hello World";
}
}
3.4 配置application.yml
在application.yml中定義服務名稱用來被客戶端調用,同時配置Zookeeper信息用來注冊服務。
server:
port: 9001
spring:
application:
name: Provider
cloud:
zookeeper:
discovery:
enabled: true
connect-string: localhost:2181
logging:
level:
org.apache.zookeeper.ClientCnxn: WARN
4. 搭建服務消費者
現在我們來創建一個REST服務消費者,它使用spring Netflix Feign Client來調用服務。先看看整個項目結構:
4.1 導入依賴
在pom文件里增加需要依賴的一些組件包。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yiidian</groupId>
<artifactId>spring-cloud-zookeeper-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- SpringBoot 對Web支持 SpringMVC相關功能,json轉換的功能等等 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<!-- 定義SpringCloud版本 -->
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.M9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
4.2 啟動類
同服務提供者一樣在主程序中增加@EnableDiscoveryClient 注解。
package com.yiidian.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
*服務消費者啟動類
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerStarter {
public static void main(String[] args) {
SpringApplication.run(ConsumerStarter.class,args);
}
}
4.3 定義Feign遠程接口
通過引入spring-cloud-starter-openfeign
組件包使用聲明式服務調用方式調用遠程服務,使用@FeignClient(“service-name”
)注解一個接口並將它自動連接到我們的應用程序中,以便我們以編程方式訪問此服務。
package com.yiidian.consumer.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* Feign遠程接口
*/
@FeignClient("Provider")
public interface HelloClient {
@GetMapping("/hello")
public String hello();
}
4.4 Controller
以下是一個簡單的服務控制器類,它通過注入接口helloWorldClient對象調用服務提供者的接口來消費該服務,並在響應中顯示它的返回值。
package com.yiidian.consumer.controller;
import com.yiidian.consumer.client.HelloClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 消費者控制器
*/
@RestController
public class GreetingController {
@Autowired
private HelloClient helloClient;
@GetMapping("/get-greeting")
public String greeting() {
return helloClient.hello();
}
}
4.5 配置application.yml
server:
port: 9002
spring:
application:
name: Consumer
cloud:
zookeeper:
discovery:
enabled: true
connect-string: localhost:2181
logging:
level:
org.apache.zookeeper.ClientCnxn: WARN
5. 測試
HelloWorld REST服務在Zookeeper中注冊了自己,Greeting服務通過聲明式客戶端發現和調用HelloWorld 服務。
現在我們可以運行這兩個服務,然后在瀏覽器中訪問 http://localhost:9002/get-greeting
,將返回以下信息:
6. 總結
在本文中我們看到了如何使用Spring Cloud Zookeeper
實現服務發現,並且在Zookeeper中注冊了一個名為Hello World的服務。然后通過聲明式服務調用方式實現了一個服務消費者Greeting來發現和使用該服務。
順便介紹下Zookeeper
與Eureka
這兩種服務治理框架的區別。Spring Cloud Eureka
實現的服務治理機制強調了CAP原理中的AP,即可用性
與可靠性
,而Zookeeper
強調CP(一致性
、可靠性
)。Eureka為了實現更高的服務可用性,犧牲了一定的一致性,在極端情況下它寧願接受故障實例也不要丟掉“健康”實例,比如,當服務注冊中心的網絡發生故障斷開時,由於所有的服務實例無法維持續約心跳,在強調CP的服務治理中將會把所有服務實例都剔除掉,而Eureka則會觸發保護機制,保留此時的所有節點,以實現服務間依然可以進行互相調用的場景。
歡迎關注我的公眾號::一點教程。獲得獨家整理的學習資源和日常干貨推送。
如果您對我的系列教程感興趣,也可以關注我的網站:yiidian.com