SpringCloud(二)服务注册与发现

目录

1.什么是服务治理

2.服务注册与发现

3.SpringCloud集成Eureka注册中心

4.SpringCloud集成Zookeeper注册中心

5.SpringCloud集成Consul注册中心

6.总结


 

1.什么是服务治理

在传统rpc远程调用中,服务与服务依赖关系,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

 

2.服务注册与发现

 在服务注册与发现中,有一个注册中心,当服务器启动的时候,会把当前自己服务器的信息 比如 服务地址通讯地址等以别名方式注册到注册中心上。 另一方(消费者|服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现rpc调用。

 

springcloud支持的注册中心:Eureka,Consual(go语言写的),zookeeper

dubbo常用的注册中心:zookeeper,Redis

 

 

3.SpringCloud集成Eureka注册中心

3.1.演示

3.1.1.案例需求

实现会员服务(提供者) springcloud-member  通过eureka注册中心 调用订单服务(消费者) springcloud-order

 

3.1.2.项目结构

springcloud-eureka-server   注册中心

springcloud-member   服务提供者

springcloud-order       服务消费者

 

3.1.3.所用注解

@EnableEurekaServer   表示开启EurekaServer注册中心
@EnableEurekaClient    启动eureka客户端
@LoadBalanced             让restTemplate在请求时拥有客户端负载均衡能力

 

3.2.搭建注册中心

1.创建springboot项目: springcloud-eureka-server 

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.itmayiedu</groupId>
    <artifactId>springcloud-eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!--SpringCloud eureka依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <!-- 注意: 这里必须要添加,否则各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

注意:springboot版本问题,我试了几个版本,启动eureka都报错,只有2.0.1才能正常启动。

 

3.application.yml

###服务端口号
server:
  port: 8100

eureka:
  instance:
    ###注册中心IP地址
    hostname: 127.0.0.1
  client:
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    ###因为自己是为注册中心,不需要自己注册自己
    register-with-eureka: false
    ###因为自己是为注册中心,不需要检索服务
    fetch-registry: false

 

4.启动类

package com.itmayiedu.springcloudeurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class AppEureka {

   public static void main(String[] args) {
      SpringApplication.run(AppEureka.class, args);
   }
}

@EnableEurekaServer 表示开启EurekaServer服务,开启注册中心

 

5.启动eureka,浏览器访问http://localhost:8100/

 

 

3.3.搭建服务提供者 springcloud-member 

1.创建springboot项目: springcloud-member

 

2.pom文件

<?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 https://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.0.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itmayiedu</groupId>
    <artifactId>springcloud-member</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud-member</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- SpringBoot整合eureka客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

    <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

 

3.application.yml

###服务启动端口号
server:
  port: 8000

###服务名称(服务注册到eureka名称)
spring:
  application:
    name: app-itmayiedu-member

###服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8100/eureka

    ###是否将服务注册到注册中心(是)
    register-with-eureka: true
    ###是否需要从eureka上获取注册信息(是)
    fetch-registry: true

 

4.MemberController

package com.itmayiedu.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MemberController {

   @RequestMapping("/getMember")
   public String getMember() {
      return "会员系统";
   }
}

 

5.启动类

package com.itmayiedu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient
@SpringBootApplication
public class SpringcloudMemberApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringcloudMemberApplication.class, args);
    }

}

@EnableEurekaClient:启动eureka客户端

 

6.启动member项目,浏览器访问注册中心地址http://localhost:8100/


注:注册中心里已经发现了member项目,项目名称是在member项目里的application.yml中定义的


右边的是服务接口的地址,我们可以访问member接口:


 

3.4..搭建服务消费者 springcloud-order

1.创建springboot项目: springcloud-order

 

2.pom文件

<?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 https://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.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itmayiedu</groupId>
    <artifactId>springcloud-order</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud-order</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringBoot整合eureka客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

    </dependencies>
    <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

 

3.application.yml

###服务启动端口号
server:
  port: 8001

###服务名称(服务注册到eureka名称)
spring:
  application:
    name: app-itmayiedu-order
###服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8100/eureka

    ###是否将服务注册到注册中心(是)
    register-with-eureka: true
    ###是否需要从eureka上获取注册信息(是)
    fetch-registry: true

 

4.rest的接口调用方式

在springcloud中,有两种远程调用接口方式:

1)rest(springboot的web组件提供的),rest底层使用的是httpclient方式

2)fegin(springcloud提供的)

 

在rest中,有两种调用方式:

1)服务接口地址:这一种相当于直接调用接口,并没有通过euraka

2)服务别名(注册到eureka),这一种相当通过别名于从eureka中获取到对应的接口地址,再通过地址调用。使用rest通过别名方式调用接口,需要依赖ribbon负载均衡器,eureka已经集成了负载均衡器,需要通过@LoadBalanced开启负载均衡器

 

5.第一种,通过服务接口地址调用

OrderController

package com.itmayiedu.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class OrderController {

   @Autowired
   private RestTemplate restTemplate;

   @RequestMapping("/getOrder")
   public String getOrder() {
      // 有两种调用方式:一种是服务别名,一种是服务接口地址
      String memberUrl = "http://127.0.0.1:8000/getMember";
      String result = restTemplate.getForObject(memberUrl, String.class);
      System.out.println("会员服务调用订单服务,result:" + result);
      return result;
   }

}

启动类:

package com.itmayiedu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableEurekaClient
@SpringBootApplication
public class SpringcloudOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringcloudOrderApplication.class, args);
    }

    // 解决restTemplate找不到问题:将restTemplate注入到springboot容器中
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

启动order项目,浏览器访问eureka:两个服务都已经注册到注册中心



访问order项目:

 

6.第二种,通过注册别名调用

OrderController

package com.itmayiedu.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class OrderController {

   @Autowired
   private RestTemplate restTemplate;

   @RequestMapping("/getOrder")
   public String getOrder() {
      // 有两种调用方式:一种是服务别名,一种是服务接口地址
      //String memberUrl = "http://127.0.0.1:8000/getMember";
      String memberUrl = "http://app-itmayiedu-member/getMember";
      String result = restTemplate.getForObject(memberUrl, String.class);
      System.out.println("会员服务调用订单服务,result:" + result);
      return result;
   }

}

启动类

package com.itmayiedu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableEurekaClient
@SpringBootApplication
public class SpringcloudOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringcloudOrderApplication.class, args);
    }

    // 解决restTemplate找不到问题:将restTemplate注入到springboot容器中
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

@LoadBalanced让restTemplate在请求时拥有客户端负载均衡能力,如果不加次注解,访问时会报错

 

启动order项目,访问order项目:

 

3.5.搭建 服务提供者 集群

刚才已经启动了一台member项目,端口是8000,现在再启动一台member项目,端口号是8010,演示ribbon的负载均衡效果

1.修改member项目的MemberController类,显示端口号

package com.itmayiedu.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MemberController {

    @Value("${server.port}")
    private String port;

   @RequestMapping("/getMember")
   public String getMember() {
      return "会员系统:" + port;
   }
}

 

2.修改application.yml文件,再启动一台8010端口会员项目。

访问eureka发现member项目有两台了:



 

3.浏览器依次访问,发现轮流访问两台会员项目。此处采用的负载均衡策略是最基本的轮训策略。

 

3.6.eureka的自我保护机制

3.6.1.概念

1)eureka自我保护机制的两种角色:EurekaClient(注册客户端),EurekaServer (注册中心服务端)

2)为什么会产生Eureka自我保护机制:为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通的情况下,EurekaServer不会对EurekaClient服务进行剔除

3)自我保护机制:默认情况下EurekaClient会定时向EurekaServer发送心跳包,如果EurekaServer在一定时间内没有收到EurekaClient发送的心跳包,便会直接从服务注册列表中剔除该服务(默认90s),但是在短时间内丢失了大量的服务实例心跳,这时候EurekaServer会开启自我保护机制,不会剔除该服务。

4)eureka的自我保护机制,为什么不会剔除服务呢?
为了防止EurekaClient是可以正常访问的,但是只是与EurekaServer网络访问不同,防止误剔除服务。

5)在什么环境下需要开启自我保护机制:生产环境下建议开启自我保护机制,本地环境下禁止自我保护机制。

6)如果服务真的宕机呢?本地调用应该重试机制,保护接口网络延迟幂等性,服务降级功能。

 

3.6.2.开启自我保护机制

基于上面的代码,开启一台eureka注册中心,一台服务消费者order,两台服务提供者member。

多次访问order项目,发现order项目调用member项目时,会依次访问两台不同端口号的member项目。

但是,我此时停掉一台服务提供者member项目,会发现多次访问order项目时,会轮流显示调通依然启动的member项目和因为另一台宕机导致的报错页面,这就是eureka的自我保护机制。当然,短时间内是可以这样的,如果超出了自我保护机制的时间,eureka会自动剔除掉宕机的那台提供者。

 

3.6.3.禁止自我保护机制

在注册中心 springcloud-eureka-server 项目中,修改application.yml文件

###服务端口号
server:
  port: 8100
##定义服务名称
spring:
  application:
    name: app-itmayiedu-eureka
eureka:
  instance:
    ###注册中心ip地址
    hostname: 127.0.0.1
  client:
    serviceUrl:
      ##注册地址
      defaultZone: http://${eureka.instance.hostname}:8100/eureka/
    ####因为自己是注册中心,是否需要将自己注册给自己的注册中心(集群的时候是需要是为true)
    register-with-eureka: false
    ###因为自己是注册中心, 不需要去检索服务信息
    fetch-registry: false
  server:
    # 测试时关闭自我保护机制,保证不可用服务及时踢出
    enable-self-preservation: false
    ##剔除失效服务间隔
    eviction-interval-timer-in-ms: 2000

 

在服务提供者 springcloud-member 项目中,修改application.yml文件

###会员项目的端口号
server:
  port: 8000
###服务别名----服务注册到注册中心名称 
spring:
  application:
    name: app-itmayiedu-member
eureka:
  client:
    service-url:
      ##### 当前会员服务注册到eureka服务地址    
      defaultZone: http://localhost:8100/eureka
    ### 需要将我的服务注册到eureka上
    register-with-eureka: true
    ####需要检索服务
    fetch-registry: true
  # 心跳检测检测与续约时间
  # 测试时将值设置设置小些,保证服务关闭后注册中心能及时踢出服务
  instance:
    lease-renewal-interval-in-seconds: 1
    lease-expiration-duration-in-seconds: 2

配置表示:1秒钟发送一次心跳包,如果2秒钟没有发送,则eureka剔除该服务。

 

再次访问:依然发现轮流出现访问通和报错信息,这是因为 客户端的本地缓存机制,访问请求时,会先从客户端本地缓存中获取接口列表,当本地缓存时间过了之后,才会从注册中心获取新的接口列表,所以访问时需要考虑两个因素,一个是客户端本地缓存,另一个是注册中心的自我保护机制,当两个时间都到期之后,就不会访问已经宕机的服务器了。

 

 

3.7.Eureka集群

3.7.1.高可用注册中心

在微服务中,注册中心非常核心,可以实现服务治理,如果一旦注册出现故障的时候,可能会导致整个微服务无法访问,在这时候就需要对注册中心实现高可用集群模式。

 

3.7.2.Eureka高可用原理

默认情况下Eureka是让服务注册中心,不注册自己

###因为该应用为注册中心,不会注册自己

    register-with-eureka: true

###不需要去注册中心上检索服务

    fetch-registry: true

Eureka高可用实际上将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组相互注册的服务注册中心,从而实现服务清单的互相同步,达到高可用效果。

 

 

3.7.3.搭建Eureka集群

1.我们需要搭建两台eureka注册中心,一个是8100(刚才的),一个是9100(新建的)

2.注册中心端口号为8100的application.yml文件

###服务端口号
server:
  port: 8100
###eureka 基本信息配置
spring:
  application:
    name: eureka-server
eureka:
  instance:
    ###注册到eurekaip地址
    hostname: 127.0.0.1
  client:
    serviceUrl:
      defaultZone: http://127.0.0.1:9100/eureka/, http://127.0.0.1:9100/eureka/
    ###因为自己是为注册中心,做集群时需要将自己注册到注册中心
    register-with-eureka: true
    ###因为自己是为注册中心,做集群时需要检索服务
    fetch-registry: true

注意:

1)多台eureka的名称必须相同

2)此eureka必须注册到别的集群上去

如果是三台,则需要将此台注册到另两台上去

3)必须开启自我注册和自我搜索

 

3.注册中心端口号为9100的application.yml文件

###服务端口号
server:
  port: 9100
###eureka 基本信息配置
spring:
  application:
    name: eureka-server
eureka:
  instance:
    ###注册到eurekaip地址
    hostname: 127.0.0.1
  client:
    serviceUrl:
      defaultZone: http://127.0.0.1:8100/eureka/
    ###因为自己是为注册中心,不需要自己注册自己
    register-with-eureka: true
    ###因为自己是为注册中心,不需要检索服务
    fetch-registry: true

 

4.分别访问两台eureka,发现彼此都已经注册到对方注册中心的列表中了。

 

5.客户端注册eureka集群

member项目和order项目,只需要在application.yml文件中添加多个集群地址就可以了

 

6.我们分别访问两台eureka集群,发现一台有接口列表,另一台没有。

因为在注册过程中,只会保证有一台注册中心服务有对应的服务信息列表,当一台注册中心宕机后,会自动地转移到别的注册中心上去,当然,这种转移是需要一定时间的

 

 

4.SpringCloud集成Zookeeper注册中心

4.1.项目结构

springcloud-member

springcloud-order

直接使用zookeeper软件,不搭建注册中心项目

 

4.2.搭建服务提供者 springcloud-member

1.创建springboot项目:springcloud-member

2.pom文件

<?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 https://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.0.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itmayiedu</groupId>
    <artifactId>springcloud-member</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud-member</name>
    <description>Demo project for Spring Boot</description>

    <!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

        <!-- SpringBoot整合zookeeper客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>
    </dependencies>

    <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

3.application.yml

###订单服务的端口号
server:
  port: 8080

###服务注册到注册中心的名称
spring:
  application:
    name: zk-member
  ###注册中心的地址
  cloud:
    zookeeper:
      connect-string: 127.0.0.1:2181

4.MemberController

package com.itmayiedu.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@EnableDiscoveryClient
@SpringBootApplication
@RestController
public class MemberController {

    @Value("${server.port}")
    private String port;

    @RequestMapping("/getMember")
    public String getMember(){
        return "会员服务!"+ port;
    }

    public static void main(String[] args) {
        SpringApplication.run(MemberController.class, args);
    }

}

 @EnableDiscoveryClient 当启动zookeeper,consul注册中心客户端时,使用此注解

 

5.先启动zookeeper,再启动member项目,打开zookeeper可视化工具,发现member项目已经注册到注册中心上了

注:服务注册名称是持久节点,服务注册地址是临时节点

 

6.访问member接口

 

7.再启动一台8081端口号的member项目,发现有两台member项目注册到zookeeper中了

zookeeper与eureka不同的地方时:zookeeper没有自我保护机制,eureka有自我保护机制

 

4.3.搭建服务消费者 springcloud-order

1.创建springboot项目:springcloud-order

2.pom文件

<?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 https://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.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itmayiedu</groupId>
    <artifactId>springcloud-order</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud-order</name>
    <description>Demo project for Spring Boot</description>

    <!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringBoot整合zookeeper客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>

    </dependencies>
    <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

3.application.yml

###服务端口号
server:
  port: 8090
###服务名称
spring:
  application:
    name: zk-order
  cloud:
    zookeeper:
    ###注册到zookeeper地址
      connect-string: 127.0.0.1:2181

4.OrderController

package com.itmayiedu.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@RestController
@EnableDiscoveryClient
public class OrderController {

   @Autowired
   private RestTemplate restTemplate;

   @RequestMapping("/orderToMember")
   public String orderToMember() {
      String memberUrl = "http://zk-member/getMember";
      return restTemplate.getForObject(memberUrl, String.class);
   }

   public static void main(String[] args) {
      SpringApplication.run(OrderController.class, args);
   }

   // 默认rest方式开启 负载均衡功能 如果以app-itmayiedu-member名称进行调用服务接口的时候 必须
   @Bean
   @LoadBalanced
   RestTemplate restTemplate() {
      return new RestTemplate();
   }
}

5.启动order项目,访问order接口:依次访问member集群

 

6.介绍一个关于注册中心的api,可以获取到注册中心上服务列表信息:DiscoveryClient

package com.itmayiedu.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@SpringBootApplication
@RestController
@EnableDiscoveryClient
public class OrderController {

   @Autowired
   private RestTemplate restTemplate;

   @Autowired
   private DiscoveryClient discoveryClient;

   @RequestMapping("/discoveryClientMember")
   public List<ServiceInstance> discoveryClientMember() {
      List<ServiceInstance> instances = discoveryClient.getInstances("zk-member");
      for (ServiceInstance serviceInstance : instances) {
         System.out.println("url:" + serviceInstance.getUri());
      }
      return instances;
   }
   
   @RequestMapping("/orderToMember")
   public String orderToMember() {
      String memberUrl = "http://zk-member/getMember";
      return restTemplate.getForObject(memberUrl, String.class);
   }
   
   public static void main(String[] args) {
      SpringApplication.run(OrderController.class, args);
   }

   @Bean
   @LoadBalanced
   RestTemplate restTemplate() {
      return new RestTemplate();
   }

}

 

 

 

5.SpringCloud集成Consul注册中心

5.1.Consul简介

Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。

它具有很多优点。包括: 基于 raft 协议,比较简洁; 支持健康检查, 同时支持 HTTP 和 DNS 协议 支持跨数据中心的 WAN 集群 提供图形界面 跨平台,支持 Linux、Mac、Windows

Consul下载地址https://www.consul.io/downloads.html

 

5.2.Consul环境搭建

1.下载压缩包,解压之后,得到一个consul.exe文件

 

2.在当前目录下,执行cmd命令

启动consul命令:    consul agent -dev -ui -node=cy

-dev开发服务器模式启动,-node结点名为cy,-ui可以用界面访问,默认能访问。

 

3.启动成功后,访问consul界面: http://localhost:8500


4.consul就这样简单的搭建成功了。我们可以制作一个bat文件启动consul。

在consul.exe同级目录下,创建一个bat文件,内容是启动consul命令:  consul agent -dev -ui -node=cy

 

 

5.3.搭建服务提供者 springcloud-consul-member

1.创建springboot项目:springcloud-consul-member

2.pom文件

<?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 https://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.0.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itmayiedu</groupId>
    <artifactId>springcloud-consul-member</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud-consul-member</name>
    <description>Demo project for Spring Boot</description>

    <!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--SpringCloud 集成consul注册中心 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
    </dependencies>

    <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

3.application.yml

###服务端口号
server:
  port: 8502
spring:
### 服务名称
  application:
    name: consul-member
####consul注册中心地址
  cloud:
    consul:
    ### consul地址
      host: localhost
          ###     ### consul端口号
      port: 8500
      discovery:
      ##服务地址自定义为为ip地址
        hostname: 192.168.18.220
###默认情况下 服务注册到注册中心 地址随机生成英文 pc-yushengjun:

4.ConsulMemberController

package com.itmayiedu.controller;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulMemberController {

   @RequestMapping("/getMember")
   public String getMember() {
      return "会员服务";
   }

   public static void main(String[] args) {
      SpringApplication.run(ConsulMemberController.class, args);
   }

}

5.启动consul,启动member项目,访问consul界面

 

6.总结:

其实我们可以发现,换不同注册中心的时候,无论是eureka,zookeeper,还是consul,接口调用方式都不变,不同的是启动注解,配置文件和maven依赖信息

 

@EnableDiscoveryClient 与@EnableEurekaClient区别

1)@EnableDiscoveryClient注解是基于spring-cloud-commons依赖,并且在classpath中实现; 适合于consul、zookeeper注册中心

2)@EnableEurekaClient注解是基于spring-cloud-netflix依赖,只能为eureka作用;

 

Zookeeper与Eureka区别

CPA理论:一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡。在此Zookeeper保证的是CP, 而Eureka则是AP。

Consistency(一致性), 数据一致更新,所有数据变动都是同步的
Availability(可用性), 好的响应性能
Partition tolerance(分区容忍性) 可靠性

1、“C”是指一致性,即当一个Process(过程)修改了某个数据后,其他Process读取这是数据是,得到的是更新后的数据,但并不是所有系统都 可以做到这一点。例如,在一些并非严格要求一致性的系统中,后来的Process得到的数据可能还是修改之前的数据,或者需要等待一定时间后才能得到修改 之后的数据,这被成为“弱一致性”,最经典的应用就是DNS系统。当用户修改了DNS配置后,往往不会马上在全网更新,必定会有一个延迟,这个延迟被称为 “不一致窗口”,它的长度取决于系统的负载、冗余的个数等因素。但对于某些系统而言,一旦写入,后面读取的一定是修改后的数据,如银行账户信息,这被称为 “强一致性”。

2、“A”是指可用性。即系统总是能够为用户提供连续的服务能力。当用户发出请求是,系统能给出响应(成功或者失败),而且是立即给出响应,而不是等待其他事情完成才响应。如果需要等待某件事情完成才响应,那么“可用性”就不存在了。

3、“P”是指容错性。任何一个分布式计算系统都是由多个节点组成的。在正常情况下,节点与节点之间的通信是正常的。但是在某些情况下,节点之间的通信会 断开,这种断开成为“Partition”。在分布式计算的实现中,Partition是很常见的,因为节点不可能永远不出故障,尤其是对于跨物理地区的 海量存储系统而言,而容错性则可以保证如果只是系统中的部分节点不可用,那么相关的操作仍旧能够正常完成。

 

Zookeeper是保证CP

当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。

 

Eureka是保证AP

Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况: 
1. Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务 
2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用) 
3. 当网络稳定时,当前实例新的注册信息会被同步到其它节点中

因此, Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值