對于zookeeper而言,其使用場景很多,如:資料釋出訂閱、分布式隊列,負載均衡,分布式命名服務、配置管理,服務的注冊發現和叢集管理等。本文先介紹如何基于Zookeeper實作配置管理和服務管理。
一、 配置管理
所謂配置管理是指對組成叢集的相關機器的配置進行管理。因為這些配置資訊需進行動态改變,是以可利用釋出/訂閱模式讓這些機器來訂閱配置資訊的變更,當配置資訊發生改變時,這些機器就會得到相應通知,進而更新自己的配置。
下面給出SpringCloud基于zookeeper實作的配置中心實作。
1.1 依賴
對應的依賴如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-config</artifactId>
</dependency>
1.2 實作
下面給出具體的實作類。
- 配置實體類
首先為配置實體類,用于承接從配置檔案中讀取的配置資訊,其聲明如下:
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@RefreshScope
@Data
@ConfigurationProperties(prefix = "jdbc")
@Component
public class JDBCProperties {
private String host;
private String port;
private String username;
private String password;
}
- 配置
接着便是對應的配置。需要說明的是,配置中心相關的類需放置在boostrap.yml或bootstrap.properties中,如下:
server:
port: 8080spring:
profiles:
active: dev
application:
name: hello
cloud:
zookeeper:
connect-string: 192.168.217.128:2181
enabled: true
- 測試接口類
接着給出對應的測試類:
import com.itheima.config.JDBCProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@Autowired
private JDBCProperties jdbcProperties;
@GetMapping("/jdbc")
public String hello() {
return jdbcProperties.toString();
}
}
- 啟動類
由于基于SpringBoot實作,是以需提供啟動類,下面為對應的代碼:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@EnableConfigurationProperties
@SpringBootApplication
public class ZkConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ZkConfigApplication.class, args);
}
}
1.3 測試
首先使用PrettyZoo連接配接zookeeper,并填寫如下配置資訊:
需要說明的是,config為固定的root路徑,"hello"為spring.application.name的值,而"hello,dev"則表示hello應用的dev環境,hello下的子節點名即為各配置字段的鍵,而值即為各配置資訊對應的值,下面為對應的配置資訊值:
# hello
jdbc.host=localhost
jdbc.port=3306
jdbc.username=root
jdbc.password=root
# hello,dev
jdbc.host=192.168.157.122
jdbc.port=3306
jdbc.username=root
jdbc.password=123456
接着啟動編寫的程式,通路:http://localhost:8080/hello/jdbc,結果如下:
接着修改“hello,dev”的jdbc.password的值為root,修改後無需重新開機項目,直接重新整理頁面,結果如下:
當然,在最新版的Spring Cloud Zookeeper Config中,增加了配置根路徑以及環境分割符的配置。下面為最新版中bootstrap.yml對應的配置:
server:
port: 8080spring:
profiles:
active: dev
application:
name: hello
cloud:
zookeeper:
connect-string: 192.168.217.128:2181
config:
enabled: true
root: config
profile-separator: ,
name: ${spring.application.name}
二、 服務管理
所謂的服務管理包括:服務注冊和發現等,其是指對服務端的上下線做統一管理。其會将各工作伺服器作為資料的釋出方,向叢集中注冊一些資訊,而監控伺服器則來訂閱這些工作伺服器的基本資訊。當工作伺服器都基本資訊發生變更時,如:服務上下線、伺服器角色或服務範圍改變等,各監控伺服器可得到通知并迅速地進行響應。
所謂負載均衡是指通過某種手段,将對某種資源的通路分攤到不同節點中,以減輕單點的壓力。最常見的為RPC中用戶端的負載均衡。
下面講一下基于Zookeeper實作的注冊中心,其包含了:服務注冊、服務發現和負載均衡等功能。
2.1 依賴
下面為基于zookeeper實作注冊中心的相關依賴:
<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>
2.2 實作
2.2.1 服務提供者
- 配置資訊
首先為服務提供端對應的配置資訊:
spring:
application:
name: zookeeper-provider
cloud:
zookeeper:
connect-string: 192.168.217.128:2181
discovery:
root: services
- 啟動類
接着給出服務提供端啟動類對應代碼:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class ZookeeperProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ZookeeperProviderApplication.class, args);
}
}
- 測試接口類
服務提供端的測試接口類對應代碼如下:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/provider")
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello, This is provider";
}
}
2.2.2 服務消費者
- 配置資訊
下面給出消費端項目的配置類:
server:
port: 8081spring:
application:
name: zookeeper-consumer
cloud:
zookeeper:
connect-string: 192.168.217.128:2181
discovery:
root: services
- 啟動類
下面為消費端的啟動類代碼:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ZookeeperConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ZookeeperConsumerApplication.class, args);
}
}
- 遠端通路配置類
下面為消費端對應的配置類代碼:
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplateBuilder().build();
}
}
- 測試接口類
下面為消費端對應的測試接口類代碼:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/consume")
public class HelloController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/hello")
public String hello() {
return restTemplate.getForObject("http://zookeeper-provider/provider/hello", String.class);
}
}
2.3 測試
首先啟動服務提供端,啟動後使用PrettyZoo檢視Zookeeper資訊,發現服務提供端已在zookeeper中進行注冊,如下:
接着啟動消費端,此時使用PrettyZoo進行檢視,發現消費者端也已經注冊,結果如下:
接着通路:http://localhost:8081/consume/hello,結果如下:
2.4 改進
上述消費端使用RestTemplate來直接調用服務提供端,該方式對開發者而言有些繁瑣,是以可使用OpenFeign來進行遠端調用。
首先是增加OpenFeign的依賴,如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
接着是新增對應的Feign接口類,對應代碼如下:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "zookeeper-provider", path = "/provider")
public interface HelloFeign {
@GetMapping("/hello")
public String hello();
}
接着是對接口測試類和啟動類進行修改,如下:
- 測試類
測試類修改後如下:
import com.itheima.feigns.HelloFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/consume")
public class HelloController {
@Autowired
private HelloFeign helloFeign;
@GetMapping("/hello")
public String hello() {
return helloFeign.hello();
}
}
- 啟動類
啟動類修改後如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@SpringBootApplication
public class ZookeeperConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ZookeeperConsumerApplication.class, args);
}
}
接着重新開機消費端後測試,如下所示:
2.5 負載均衡政策
實際上OpenFeign已内置了負載均衡元件,之前使用Ribbon實作,而自從Ribbon放棄維護後,官方推薦使用LoadBalancer。這裡示範如何修改負載均衡元件。
2.5.1 服務提供端修改
對于服務提供端而言,為了友善測試,需在傳回資訊中包含目前服務的端口,用以識别真正的調用者,修改後的代碼如下:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/provider")
public class HelloController {
@Value("${server.port}")
private Integer port;
@GetMapping("/hello")
public String hello() {
return "hello, This is provider, port:" + port;
}
}
接着便是複制兩份啟動配置,并傳入啟動參數“--server.port=808X”,如下:
接着依據三份配置 啟動服務,此時使用PrettyZoo進行檢視,結果如下:
也就是說,此時的三個服務已被當作叢集。
2.5.2 服務消費端修改
首先在消費端添加負載均衡政策類,對應代碼如下:
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CustomRuleConfig {
@Bean
public IRule loadRule() {
return new RandomRule();
}
}
接着修改啟動類,增加引用自定義負載均衡政策的配置。啟動類修改後如下:
import com.itheima.config.CustomRuleConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@SpringBootApplication
@LoadBalancerClient(configuration = CustomRuleConfig.class)
public class ZookeeperConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ZookeeperConsumerApplication.class, args);
}
}
接着重新啟動服務消費端後,再次進行測試,發現每次請求的的結果均不同,如下: