1.原理html
1.1 zookeeper是什麼? java
ZooKeeper是一個分佈式的,開放源碼的分佈式應用程序協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要組件。它是一個爲分佈式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分佈式同步、組服務等。git
1.2 爲何zookeeper?github
大部分分佈式應用須要一個主控、協調器或控制器來管理物理分佈的子進程(如資源、任務分配等)
目前,大部分應用須要開發私有的協調程序,缺少一個通用的機制
協調程序的反覆編寫浪費,且難以造成通用、伸縮性好的協調器
ZooKeeper:提供通用的分佈式鎖服務,用以協調分佈式應用(如爲HBase提供服務)web
1.3 Zookeeper在微服務框架中能夠實現服務發現,該服務發現機制可做爲雲服務的註冊中心。spring
經過Spring Cloud Zookeeper爲應用程序提供一種Spring Boot集成,將Zookeeper經過自動配置和綁定 的方式集成到Spring環境中apache
提早準備app
安裝zookeeper和zooinspector見框架
window7環境下ZooKeeper的安裝運行及監控查看dom
這次安裝的zookeeper版本爲最新版
zookeeper-3.5.4-beta 安裝過程同樣
下載ZooInspector,參照指南運行java -Dfile.encoding=UTF-8 -jar zookeeper-dev-ZooInspector.jar便可
1.實戰
1.1 使用sts建立一個spring starter project名稱爲zk-discovery,以下圖所示
此時自動生成的pom.xml的配置文件以下所示
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>zk-discovery</artifactId> <version>0.0.1-SNAPSHOT</version> <name>zk-discovery</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties> <dependencies> <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.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project>
1.2 ZkDiscoveryApplication增長服務發現註解
@EnableDiscoveryClient
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class ZkDiscoveryApplication { public static void main(String[] args) { SpringApplication.run(ZkDiscoveryApplication.class, args); } }
1.3 增長Rest服務HelloWorldController.java
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloWorldController { @GetMapping("/helloworld") public String HelloWorld() { return "Hello World!"; } }
1.4 配置屬性文件application.yml
spring: application: name: HelloWorld cloud: zookeeper: connect-string: localhost:2181 discovery: enabled: true server: port: 8081 logging: level: org.apache.zookeeper.ClientCnxn: WARN
2.源碼分析
以spring-boot app項目啓動時註冊服務ZookeeperAutoServiceRegistrationAutoConfiguration.java爲入口
@Bean @ConditionalOnMissingBean(ZookeeperRegistration.class) public ServiceInstanceRegistration serviceInstanceRegistration( ApplicationContext context, ZookeeperDiscoveryProperties properties) { String appName = context.getEnvironment().getProperty("spring.application.name", "application"); String host = properties.getInstanceHost(); if (!StringUtils.hasText(host)) { throw new IllegalStateException("instanceHost must not be empty"); } ZookeeperInstance zookeeperInstance = new ZookeeperInstance(context.getId(), appName, properties.getMetadata()); RegistrationBuilder builder = ServiceInstanceRegistration.builder() //1 .address(host) //2 .name(appName) //3 .payload(zookeeperInstance) //4 .uriSpec(properties.getUriSpec()); //5 if (properties.getInstanceSslPort() != null) { builder.sslPort(properties.getInstanceSslPort()); } if (properties.getInstanceId() != null) { builder.id(properties.getInstanceId()); } // TODO add customizer? return builder.build(); }
2.2 建立ServiceInstance的builder
/** * Return a new builder. The {@link #address} is set to the ip of the first * NIC in the system. The {@link #id} is set to a random UUID. * * @return builder * @throws Exception errors getting the local IP */ public static<T> ServiceInstanceBuilder<T>builder() throws Exception { String address = null; Collection<InetAddress> ips = ServiceInstanceBuilder.getAllLocalIPs(); if ( ips.size() > 0 ) { address = ips.iterator().next().getHostAddress(); // default to the first address } String id = UUID.randomUUID().toString(); return new ServiceInstanceBuilder<T>().address(address).id(id).registrationTimeUTC(System.currentTimeMillis()); }
觀察zookeeper的生成狀況
生成的helloWorld的服務信息以下:
{ "name": "HelloWorld", "id": "ef95204e-f5e8-4c69-96e4-3f7cec8dce33", "address": "DESKTOP-405G2C8", "port": 8081, "sslPort": null, "payload": { "@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance", "id": "application-1", "name": "HelloWorld", "metadata": { } }, "registrationTimeUTC": 1552453808924, "serviceType": "DYNAMIC", "uriSpec": { "parts": [ { "value": "scheme", "variable": true }, { "value": "://", "variable": false }, { "value": "address", "variable": true }, { "value": ":", "variable": false }, { "value": "port", "variable": true } ] } }
3.碰到的問題
Thrown "KeeperErrorCode = Unimplemented for /services" exception
緣由:Curator 和zookeeper的版本不一致
解決方式:zookeeper升級到最新的版本後異常消失
4.Spring Cloud中的Eureka和Zookeeper的區別
對於 zookeeper 來書,它是 CP 的。也就是說,zookeeper 是保證數據的一致性的。
Eureka 在設計時優先保證可用性,這就是 AP 原則。Eureka 各個節點都是平等的,幾個節點掛掉不會影響正常節點的工做,剩餘的節點依然能夠提供註冊和查詢服務。
參考文獻
【2】https://cloud.spring.io/spring-cloud-zookeeper/1.2.x/multi/multi_spring-cloud-zookeeper-config.html
【3】http://www.enriquerecarte.com/2017-07-21/spring-cloud-config-series-introduction
【4】https://dzone.com/articles/spring-cloud-config-series-part-2-git-backend
【5】https://dzone.com/articles/spring-cloud-config-part-3-zookeeper-backend
【6】https://github.com/santteegt/spring-cloud-zookeeper-service-discovery-demo
【7】https://blog.csdn.net/peterwanghao/article/details/79722247