Zookeeper典型應用場景 高可用的服務註冊與消費(四)

1、項目結構

在這裏插入圖片描述
pom文件:

 <!--spring boot 版本依賴-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.101tec/zkclient-->
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.10</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
    </dependencies>

2、生產者

在這裏插入圖片描述

生產者把當前ip和端口註冊到zk上

2.1、pom文件

   <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

2.2、application.yml

server:
  port: 9000
zookeeper:
  ip: 192.168.92.39
  timeout: 10000

2.3、ZookeeperProviderConfig

@Configuration
public class ZookeeperProviderConfig implements InitializingBean {

    /***
     *功能描述  本地服務端口
     */
    @Value("${server.port}")
    private Integer port;

    /***
     *功能描述 zk ip
     */
    @Value("${zookeeper.ip}")
    private String zkAddress;

    /***
     *功能描述 超時時間
     */
    @Value("${zookeeper.timeout}")
    private Integer zkTimeout;

    /***
     *功能描述  zk註冊的服務節點
     */
    private static final String BASE_SERVICE = "/services";
    private static final String PRODUCER_SERVICE = "/producer";

    @Override
    public void afterPropertiesSet() throws Exception {
        //1、獲取本地地址
        String hostAddress = InetAddress.getLocalHost().getHostAddress();
        //2、創建Zookeeper
        ZkClient zkClient = new ZkClient(zkAddress, zkTimeout);
        //3、判斷父親節點是否存在,如果不存在創建
        if (!zkClient.exists(BASE_SERVICE)) {
            zkClient.createPersistent(BASE_SERVICE);
        }
        //4、把當前服務註冊到zk中
        System.out.println(serverUrl);
        zkClient.createEphemeralSequential(BASE_SERVICE + PRODUCER_SERVICE, serverUrl);

    }
}

2.4、controller

@RestController
@RequestMapping("/zk")
public class ProviderController {

    /***
     *功能描述  本地服務端口
     */
    @Value("${server.port}")
    private Integer port;

    @GetMapping("/hello")
    public String hello() {

        return "provider " + port + " say hello";
    }

}

2.5、啓動生產者,並且在idea複製一份,把端口改成9001啓動
在這裏插入圖片描述
1)訪問9000,9001端口
在這裏插入圖片描述
在這裏插入圖片描述
2)打開zk:
在這裏插入圖片描述

3、消費者

在這裏插入圖片描述

消費者用於監聽生產者提供服務的根節點,如果根節點發生了變化,及時更新服務列表

3.1、pom

  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

3.2、yml

server:
  port: 8000
zookeeper:
  ip: 192.168.92.39
  timeout: 10000

3.3、LoadBalance

public abstract class LoadBalance {

    /***
    *功能描述  服務列表
     */
    public volatile static List<String> SERVICE_LIST;
     
    /***
    *功能描述 獲取一個服務
    */
    public abstract String choseServiceHost();
}

3.4.、輪詢

@Configuration
public class LunXunBalance extends LoadBalance {

    private static Integer index = 0;

    /***
     *功能描述  如果服務列表不爲空,就從服務列表獲取一個url返回
     */
    @Override
    public String choseServiceHost() {
        if (!CollectionUtils.isEmpty(SERVICE_LIST)) {
            index++;
            if (index >= SERVICE_LIST.size()) {
                index = 0;
            }
            return SERVICE_LIST.get(index);
        }
        return null;
    }
}

3.5、ZookeeperCustomerConfig

@Configuration
public class ZookeeperCustomerConfig {

    /***
     *功能描述 zk地址
     */
    @Value("${zookeeper.ip}")
    private String zkAddress;

    /***
     *功能描述 超時時間
     */
    @Value("${zookeeper.timeout}")
    private Integer zkTimeout;

    /***
     *功能描述  zk註冊的服務節點
     */
    private static final String BASE_SERVICE = "/services";


    @Bean
    public ZkClient zkClient() {
        ZkClient zkClient = new ZkClient(zkAddress, zkTimeout);
        updateServerList(zkClient);
        zkClient.subscribeChildChanges(BASE_SERVICE, new ServerWatcher(zkClient));
        return zkClient;
    }


    /**
     * 功能描述 更新服務列表
     */
    private void updateServerList(ZkClient zkClient) {
        List<String> serverList = new ArrayList<>();
        try {
            //獲取節點
            List<String> childrens = zkClient.getChildren(BASE_SERVICE);
            //獲取節點的值
            for (String child : childrens) {
                Object host = zkClient.readData(BASE_SERVICE + "/" + child);
                serverList.add((String) host);
            }
            //把值賦給LoadBalance
            LoadBalance.SERVICE_LIST = serverList;
            System.out.println("服務列表已經更新:" + serverList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 功能描述  監聽子節點的變換
     *
     * @author Zrs
     * @date 2019/8/24
     * @return: ......
     */
    private class ServerWatcher implements IZkChildListener {

        private ZkClient zkClient;

        public ServerWatcher(ZkClient zkClient) {
            this.zkClient = zkClient;
        }

        @Override
        public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
            updateServerList(zkClient);
        }
    }


}

.3.6、RestConfig

@Configuration
public class RestConfig {

    @Bean
    public RestTemplate restTemplate() {

        return new RestTemplate();
    }
}

3.7、 CustomerController

@RestController
@RequestMapping("/customer")
public class CustomerController {

    @Resource
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalance loadBalance;

    @RequestMapping("/hello")
    public String customer() {
        String url = loadBalance.choseServiceHost();
        String hello = restTemplate.getForObject("http://" + url + "/zk/hello/", String.class);
        return hello;
    }
}

3.8、啓動消費者者
在這裏插入圖片描述

1)第一次訪問controller

在這裏插入圖片描述

2)第二次訪問controller
在這裏插入圖片描述
3)停掉9001端口的客戶端
在這裏插入圖片描述
在這裏插入圖片描述
4)再次訪問url
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章