天天看點

Zookeeper使用詳解之配置管理和服務管理

對于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,并填寫如下配置資訊:

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,結果如下:

Zookeeper使用詳解之配置管理和服務管理

接着修改“hello,dev”的jdbc.password的值為root,修改後無需重新開機項目,直接重新整理頁面,結果如下:

Zookeeper使用詳解之配置管理和服務管理

當然,在最新版的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中進行注冊,如下:

Zookeeper使用詳解之配置管理和服務管理

接着啟動消費端,此時使用PrettyZoo進行檢視,發現消費者端也已經注冊,結果如下:

Zookeeper使用詳解之配置管理和服務管理

接着通路:http://localhost:8081/consume/hello,結果如下:

Zookeeper使用詳解之配置管理和服務管理

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);
    }
}           

接着重新開機消費端後測試,如下所示:

Zookeeper使用詳解之配置管理和服務管理

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”,如下:

Zookeeper使用詳解之配置管理和服務管理

接着依據三份配置 啟動服務,此時使用PrettyZoo進行檢視,結果如下:

Zookeeper使用詳解之配置管理和服務管理

也就是說,此時的三個服務已被當作叢集。

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);
    }
}           

接着重新啟動服務消費端後,再次進行測試,發現每次請求的的結果均不同,如下:

Zookeeper使用詳解之配置管理和服務管理
Zookeeper使用詳解之配置管理和服務管理
Zookeeper使用詳解之配置管理和服務管理

繼續閱讀