spring cloud Greenwich 学习笔记(一)spring cloud eureka ribbon 服务注册与发现

springcloud系列学习笔记目录参见博主专栏 spring boot 2.X/spring cloud Greenwich
由于是一系列文章,所以后面的文章可能会使用到前面文章的项目。文章所有代码都已上传GitHub:https://github.com/liubenlong/springcloudGreenwichDemo
本系列环境:Java11;springboot 2.1.1.RELEASE;springcloud Greenwich.RELEASE;MySQL 8.0.5;

概述

Spring提供了一系列工具,可以帮助开发人员迅速搭建分布式系统中的公共组件(比如:配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,主节点选举, 分布式session, 集群状态)。协调分布式环境中各个系统,为各类服务提供模板性配置。使用Spring Cloud, 开发人员可以搭建实现了这些样板的应用,并且在任何分布式环境下都能工作得非常好,小到笔记本电脑, 大到数据中心和云平台。

本系列文章目的是快速学习 springcloud。详细原理后续介绍。
相关参考链接:

环境说明

Intellij IDEA
java: 11
springboot :** 2.1.1.RELEASE**
springcloud : Greenwich.RELEASE

关于spring cloud和spring boot的版本使用情况请参考 spring cloud Greenwich 学习笔记(0)spring cloud 与 spring boot的版本对应情况

eureka注册中心

eureka 简介

Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
Eureka包含两个组件:Eureka Server和Eureka Client。
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。
eureka现已闭源,停止更新,处于维护阶段。不过目前已经很稳定,依旧可以使用。也可以使用 Consul、zookeeper等替换

工程搭建

本文整体项目结构如下:
在这里插入图片描述
最外层pom文件引入springcloud和springboot的依赖

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

    <groupId>com.lbl</groupId>
    <artifactId>springclouddemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.boot.version>2.1.1.RELEASE</spring.boot.version>
        <spring.cloud.version>Greenwich.RELEASE</spring.cloud.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <modules>
        <module>springcloud-eureka-server</module>
        <module>springcloud-eureka-serviceprovider</module>
		<module>springcloud-eureka-serviceconsumer-ribbon</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <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>
</project>

eureka注册中心

首先编写eureka注册中心,也就是服务端。
该注册中心继承于上面方父module:springclouddemo

<parent>
    <groupId>com.lbl</groupId>
    <artifactId>springclouddemo</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


<dependencies>
    <!--引入eureka-server-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>

    <!-- jaxb模块引用 - start -->
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
    <!-- jaxb模块引用 - end -->

</dependencies>

说明:这里我们额外引入了jaxb。是因为 运行springboot项目出现:Type javax.xml.bind.JAXBContext not present

配置文件:

server:
  port: 8080

# 最佳实践:springcloud应用都要指定application.name
spring:
  application:
    name: springcloud-eureka-server

#  在默认情况下erureka server也是一个eureka client ,必须要指定一个 server
eureka:
  instance:
    hostname: localhost
  client:
#   registerWithEureka和fetchRegistry=false 表明自己是一个eureka server.
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

这里我们制定了端口、应用名称、eureka配置。各项配置含义参见注释。
编写启动类,这里需要引入@EnableEurekaServer注解来启用EurekaServer:

@SpringBootApplication
@EnableEurekaServer //启用EurekaServer
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

启动服务以后,浏览器访问http://127.0.0.1:8080/就是eureka的控制台了,这里可以看到注册的所有应用:
在这里插入图片描述

服务提供者

注册中心搭建好了,那么现在编写服务提供者项目springcloud-eureka-serviceprovider
这里需要引入依赖eureka-client不管是服务提供者还是消费者,在eureka眼里都是客户端】:

<artifactId>springcloud-eureka-serviceprovider</artifactId>
<packaging>jar</packaging>
<name>springcloud-eureka-serviceprovider</name>

<parent>
    <groupId>com.lbl</groupId>
    <artifactId>springclouddemo</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

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

    <!--引入eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <!-- jaxb模块引用 - start -->
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
    <!-- jaxb模块引用 - end -->
</dependencies>

配置文件中需要指定应用名称以及配置中心地址:

server:
  port: 8082

# 服务与服务之间相互调用一般都是根据这个name 。
spring:
  application:
    name: springcloud-eureka-serviceprovider

eureka:
  client:
    serviceUrl:
#      指定服务注册中心的地址
      defaultZone: http://localhost:8080/eureka/

编写启动类,顺便提供一个restAPI服务

@SpringBootApplication
@EnableEurekaClient //启用EurekaClient服务
@RestController
public class Application {

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

    @Value("${server.port}")
    String port;
    
    @RequestMapping("/")
    public String hi(String name) {
        return String.format("hello %s , from port=%s", name, port);
    }
}

这里我们启动两个springcloud-eureka-serviceprovider服务来模拟集群。将配置文件中的端口改为8083,然后将IDEA中单实例的配置去掉:
在这里插入图片描述
在这里插入图片描述
左上角的single instance only去掉,就可以启动多个项目了。启动端口8083的springcloud-eureka-serviceprovider
在eureka控制台查看服务信息,可以发现注册了两个服务8082和8083:
在这里插入图片描述
来看一下restcontroller还不好使:
在这里插入图片描述

至此注册中心搭建完成,服务提供者也对外提供服务了。接下来该搭建服务消费者了。

ribbon客户端负载均衡

服务消费者

springcloud提倡微服务采用rest http的方式。消费者在注册中心中发现服务后,需要通过负载均衡进行调度,springcloud全家桶提供了两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。其中feign底层使用了ribbon。本文介绍ribbon
首先引入相关依赖

<artifactId>springcloud-eureka-serviceconsumer-ribbon</artifactId>
<packaging>jar</packaging>
<name>springcloud-eureka-serviceconsumer-ribbon</name>

<parent>
    <groupId>com.lbl</groupId>
    <artifactId>springclouddemo</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

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

    <!--引入eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!--引入 netflix-ribbon -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>

    <!-- jaxb模块引用 - start -->
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
    <!-- jaxb模块引用 - end -->
</dependencies>

配置文件同样需要指定应用名称及注册中心地址

server:
  port: 8085

# 服务与服务之间相互调用一般都是根据这个name 。
spring:
  application:
    name: springcloud-eureka-serviceconsumer-ribbon

eureka:
  client:
    serviceUrl:
#      指定服务注册中心的地址
      defaultZone: http://localhost:8080/eureka/

编写启动类

@SpringBootApplication
@EnableEurekaClient //启用EurekaClient组件
//@EnableDiscoveryClient  //启用服务发现组件
public class Application {

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

    /**
     * springcloud中提倡rest风格的微服务
     * 想spring容器中注入RestTemplate
     *
     * 使用LoadBalanced表明这个restRemplate开启负载均衡的功能。
     * @return
     */
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

启动类中通过注解启用了Eureka和服务发现组件,并且向spring容器中注入了开启了负载均衡功能的RestTemplate。
编写controller

@RestController
public class HelloController {

    @Autowired
    RestTemplate restTemplate;

    @RequestMapping("/")
    public String hi(String name){
        //这里直接写的是服务名: springcloud-eureka-serviceprovider  。在ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名
        return restTemplate.getForObject("http://springcloud-eureka-serviceprovider?name=" + name, String.class);
    }
}

在controller中我们使用restTemplate来调用服务提供者,注意这里我们没有写IP和端口。而是通过服务名称进行调用的
启动服务,浏览器多次访问http://127.0.0.1:8085/?name=a,会发现下面两个result轮询出现
在这里插入图片描述
在这里插入图片描述
这是因为我们服务提供者启动了两个,端口分别是8082和8083,通过ribbon进行了客户端负载均衡
这时我们再看一下注册中心,里面展示了两个服务提供者,一个消费者:
在这里插入图片描述
整体的系统架构如下:

在这里插入图片描述

自我保护机制

官方对于自我保护机制的定义:

https://github.com/Netflix/eureka/wiki/Understanding-Eureka-Peer-to-Peer-Communication

自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。

自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:

  1. Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
  2. Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
  3. 当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。

因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。

关闭自我保护

这个只适用于测试环境,在生产环境不要关闭

** 服务端配置**

eureka:
  server:
    # 测试时关闭自我保护机制,保证不可用服务及时踢出
    enable-self-preservation: false

** 客户端配置**

# 心跳检测检测与续约时间
# 测试时将值设置设置小些,保证服务关闭后注册中心能及时踢出服务
eureka:
  instance:
    lease-renewal-interval-in-seconds: 1   # 每间隔1s,向服务端发送一次心跳,证明自己依然”存活“
    lease-expiration-duration-in-seconds: 2 # 告诉服务端,如果我2s之内没有给你发心跳,就代表我“死”了,将我踢出掉

@EnableDiscoveryClient与@EnableEurekaClient

可以看到,上面我将@EnableDiscoveryClient注释掉了。
其实这两个注解非常的类似,都是用于启用服务发现的。
stackoverflow https://stackoverflow.com/questions/31976236/whats-the-difference-between-enableeurekaclient-and-enablediscoveryclient 中介绍了:

There are multiple implementations of “Discovery Service” (eureka, consul, zookeeper). @EnableDiscoveryClient lives in spring-cloud-commons and picks the implementation on the classpath. @EnableEurekaClient lives in spring-cloud-netflix and only works for eureka. If eureka is on your classpath, they are effectively the same.

也就是说discovery service有许多种实现(eureka、consul、zookeeper等等),@EnableDiscoveryClientspring-cloud-commons包中, 而@EnableEurekaClient是在spring-cloud-netflix包中的。

如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他的注册中心,那么使用@EnableDiscoveryClient。

springcloud系列学习笔记目录参见博主专栏 spring boot 2.X/spring cloud Greenwich
由于是一系列文章,所以后面的文章可能会使用到前面文章的项目。文章所有代码都已上传GitHub:https://github.com/liubenlong/springcloudGreenwichDemo
本系列环境:Java11;springboot 2.1.1.RELEASE;springcloud Greenwich.RELEASE;MySQL 8.0.5;

发布了234 篇原创文章 · 获赞 212 · 访问量 91万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: Age of Ai 设计师: meimeiellie

分享到微信朋友圈

×

扫一扫,手机浏览