日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

zookeeper服务发现实战及原理--spring-cloud-zookeeper源码分析

發布時間:2025/4/5 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 zookeeper服务发现实战及原理--spring-cloud-zookeeper源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.為什么要服務發現?

服務實例的網絡位置都是動態分配的。由于擴展、失敗和升級,服務實例會經常動態改變,因此,客戶端代碼需要使用更加復雜的服務發現機制。

2.常見的服務發現開源組件

etcd—用于共享配置和服務發現的高可用性、分布式、一致的鍵值存儲。使用etcd的兩個著名項目是Kubernetes和Cloud Foundry。
consul-發現和配置服務的工具。它提供了一個API,允許客戶端注冊和發現服務。領事可以執行健康檢查,以確定服務的可用性。
Apache Zookeeper——一個廣泛使用的分布式應用高性能協調服務。Apache Zookeeper最初是Hadoop的子項目,但現在是頂級項目。

?

3.zookeeper服務發現原理

? 3.1 zookeeper是什么???

  ZooKeeper是一個分布式的,開放源碼的分布式應用程序協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要組件。它是一個為分布式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分布式同步、組服務等。

?3.2 為什么zookeeper?

  大部分分布式應用需要一個主控、協調器或控制器來管理物理分布的子進程(如資源、任務分配等)
  目前,大部分應用需要開發私有的協調程序,缺乏一個通用的機制
  協調程序的反復編寫浪費,且難以形成通用、伸縮性好的協調器
  ZooKeeper:提供通用的分布式鎖服務,用以協調分布式應用(如為HBase提供服務)

? 3.3 Zookeeper在微服務框架中可以實現服務發現,該服務發現機制可作為云服務的注冊中心。

  通過Spring Cloud Zookeeper為應用程序提供一種Spring Boot集成,將Zookeeper通過自動配置和綁定 的方式集成到Spring環境中.

4.準備工作

安裝zookeeper和zooinspector見

window7環境下ZooKeeper的安裝運行及監控查看

  此次安裝的zookeeper版本為最新版

  zookeeper-3.5.4-beta 安裝過程一樣

  下載ZooInspector,參照指南運行java -Dfile.encoding=UTF-8 -jar zookeeper-dev-ZooInspector.jar即可

5.實戰

? 5.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>

?

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

?5.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!";} }

5.4. 屬性文件配置

spring:application:name: HelloWorldcloud:zookeeper:connect-string: localhost:2181discovery:enabled: true server:port: 8081 logging:level:org.apache.zookeeper.ClientCnxn: WARN

6.源碼分析

?以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();}

6.1 創建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());}

6.2?ZookeeperAutoServiceRegistration.java

注冊方法

@Overrideprotected void register() {if (!this.properties.isRegister()) {log.debug("Registration disabled.");return;}if (this.registration.getPort() == 0) {this.registration.setPort(getPort().get());}super.register();}

調用父類AbstractAutoServiceRegistration的注冊方法

/*** Register the local service with the {@link ServiceRegistry}.*/protected void register() {this.serviceRegistry.register(getRegistration());}

調用ZookeeperServiceRegistry的注冊方法

/*** TODO: add when ZookeeperServiceDiscovery is removed One can override this method to* provide custom way of registering {@link ServiceDiscovery}*//** private void configureServiceDiscovery() {* this.zookeeperServiceDiscovery.configureServiceDiscovery(this.* zookeeperServiceDiscovery.getServiceDiscoveryRef(), this.curator, this.properties,* this.instanceSerializer, this.zookeeperServiceDiscovery.getServiceInstanceRef()); }*/@Overridepublic void register(ZookeeperRegistration registration) {try {getServiceDiscovery().registerService(registration.getServiceInstance());}catch (Exception e) {rethrowRuntimeException(e);}}

最終調用org.apache.curator.x.discovery.details.ServiceDiscoveryImpl

/*** Register/re-register/update a service instance** @param service service to add* @throws Exception errors*/@Overridepublic void registerService(ServiceInstance<T> service) throws Exception{Entry<T> newEntry = new Entry<T>(service);Entry<T> oldEntry = services.putIfAbsent(service.getId(), newEntry);Entry<T> useEntry = (oldEntry != null) ? oldEntry : newEntry;synchronized(useEntry){if ( useEntry == newEntry ) // i.e. is new {useEntry.cache = makeNodeCache(service);}internalRegisterService(service);}}@VisibleForTestingprotected void internalRegisterService(ServiceInstance<T> service) throws Exception{byte[] bytes = serializer.serialize(service);String path = pathForInstance(service.getName(), service.getId());final int MAX_TRIES = 2;boolean isDone = false;for ( int i = 0; !isDone && (i < MAX_TRIES); ++i ){try{CreateMode mode;switch (service.getServiceType()) {case DYNAMIC:mode = CreateMode.EPHEMERAL;break;case DYNAMIC_SEQUENTIAL:mode = CreateMode.EPHEMERAL_SEQUENTIAL;break;default:mode = CreateMode.PERSISTENT;break;}client.create().creatingParentContainersIfNeeded().withMode(mode).forPath(path, bytes);isDone = true;}catch ( KeeperException.NodeExistsException e ){client.delete().forPath(path); // must delete then re-create so that watchers fire }}}

?觀察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}]} }

7.碰到的問題

?Thrown "KeeperErrorCode = Unimplemented for /services" exception

  原因:Curator 和zookeeper的版本不一致

  解決方式:zookeeper升級到最新的版本后異常消失

8.Spring Cloud中的Eureka和Zookeeper的區別

? ? ?

對于 zookeeper 來書,它是 CP 的。也就是說,zookeeper 是保證數據的一致性的。

Eureka 在設計時優先保證可用性,這就是 AP 原則。Eureka 各個節點都是平等的,幾個節點掛掉不會影響正常節點的工作,剩余的節點依然可以提供注冊和查詢服務。

9.總結

? ?在微服務應用中,服務實例的運行環境會動態變化,實例網絡地址也是如此。因此,客戶端為了訪問服務必須使用服務發現機制。

服務注冊表是服務發現的關鍵部分。服務注冊表是可用服務實例的數據庫,提供管理 API 和查詢 API。服務實例使用管理 API 來實現注冊和注銷,系統組件使用查詢 API 來發現可用的服務實例。

服務發現有兩種主要模式:客戶端發現和服務端發現。在使用客戶端服務發現的系統中,客戶端查詢服務注冊表,選擇可用的服務實例,然后發出請求。在使用服務端發現的系統中,客戶端通過路由轉發請求,路由器查詢服務注冊表并轉發請求到可用的實例。

服務實例的注冊和注銷也有兩種方式。一種是服務實例自己注冊到服務注冊表中,即自注冊模式;另一種則是由其它系統組件處理注冊和注銷,也就是第三方注冊模式。

在一些部署環境中,需要使用 Netflix Eureka、etcd、Apache Zookeeper 等服務發現來設置自己的服務發現基礎設施。而另一些部署環境則內置了服務發現。例如,Kubernetes 和 Marathon 處理服務實例的注冊和注銷,它們也在每個集群主機上運行代理,這個代理具有服務端發現路由的功能。

HTTP 反向代理和 NGINX 這樣的負載均衡器能夠用做服務器端的服務發現均衡器。服務注冊表能夠將路由信息推送到 NGINX,激活配置更新,譬如使用 Cosul Template。NGINX Plus 支持額外的動態配置機制,能夠通過 DNS 從注冊表中獲取服務實例的信息,并為遠程配置提供 API。

參考文獻

【1】https://cloud.spring.io/spring-cloud-zookeeper/1.2.x/multi/multi_spring-cloud-zookeeper-discovery.html

【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

【8】https://www.cnblogs.com/EasonJim/p/7613734.html

【9】https://blog.csdn.net/eson_15/article/details/85561179

【10】https://www.nginx.com/blog/service-discovery-in-a-microservices-architecture/

轉載于:https://www.cnblogs.com/davidwang456/p/10436932.html

總結

以上是生活随笔為你收集整理的zookeeper服务发现实战及原理--spring-cloud-zookeeper源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。