SpringCloud 微服务架构五大核心组件(一):Eureka 服务注册与发现

chan 作者
阅读 8643 喜欢 0

SpringCloud 简介

SpringCloud 是 Spring 旗下的项目之一,它是微服务架构的一种实现方式。

官网地址:http://projects.spring.io/spring-cloud/

SpringCloud 为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用 SpringCloud 开发人员可以快速地支持实现这些模式的服务和应用程序。

目前业界对 SpringCloud 使用最广的就是 SpringCloud Netflix 了。

Netflix 主要涉及的五大核心组件包括:

  • Eureka:注册中心
  • Zuul:服务网关
  • Ribbon:负载均衡
  • Config:分布式配置中心
  • Hystrix:熔断器

SpringCloud 与 SpringBoot 版本关系

SpringCloud 基于 SpringBoot 开发,因此 SpringBoot 与 SpringCloud 需要版本对应,否则可能会造成很多意料之外的错误,比如 eureka 注册了结果找不到服务类啊,比如某些 jar 导入不进来啊,等等这些错误。下面列出来springBoot和spring cloud的版本对应关系,需要配套使用,才不会出现各种奇怪的错误。

Release Train Boot Version
Hoxton 2.2.x
Greenwich 2.1.x
Finchley 2.0.x
Edgware 1.5.x
Dalston 1.5.x

微服务架构图

Eureka 服务注册与发现

使用 SpringBoot 创建三个服务,模拟一个服务调用的场景

一、创建父工程并引入 SpringCloud 的版本管理

1、引入 SpringCloud 版本管理:

<!-- SpringCloud的依赖 -->
<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>

2、项目结构如下: eureka-server(注册中心)、producer(服务提供者)、consumer(消费者)

  • eureka-server:服务注册中心(可以是一个集群),对外暴露自己的地址。
  • 提供者:启动后向 Eureka 注册自己信息(地址,服务名称等),并且定期进行服务续约
  • 消费者:服务调用方,会定期去 Eureka 拉取服务列表,然后使用负载均衡算法选出一个服务进行调用。
  • 心跳(续约):提供者定期通过 http 方式向 Eureka 刷新自己的状态

二、创建 eureka-server 模块

1、引入依赖:

<!-- Eureka 服务端 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

2、启动类使用注解使能配置:

@EnableEurekaServer

3、编写 application.yml 配置文件:

server:
  # 端口
  port: 9001
spring:
  application:
    # 应用名称,会在 Eureka 中显示
    name: eureka-server
eureka:
  client:
    # 是否注册自己的信息到 EurekaServer,默认是 true,这里作为服务端所以 false
    register-with-eureka: false
    # false 表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # EurekaServer的地址,现在是自己的地址,如果是集群,需要加上其它Server的地址。
      defaultZone: http://127.0.0.1:${server.port}/eureka

4、启动服务,并访问 http://127.0.0.1:9001

三、创建 producer 模块并注册到 eureka-server

1、引入依赖:

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

2、启动类添加注解:

@EnableEurekaClient

3、编写配置文件:

server:
  #端口号
  port: 8001
spring:
  application:
      #服务名
    name: producer
eureka:
  client:
    service-url:
      # eureka-server 地址
      defaultZone: http://127.0.0.1:9001/eureka
  instance:
    # 指定自己的 ip 信息,不指定的话会自己寻找
    ip-address: 127.0.0.1
    # 当调用 getHostname 获取实例的 hostname 时,返回 ip 而不是 host 名称
    prefer-ip-address: true

4、简单编写逻辑业务,暴露接口:

@RequestMapping(value = "user/list")
public RespResult getUsers() {
    List<User> users = userService.query();
    if (users != null) {
        return new RespResult<>(200, "成功", users);
    }
    return new RespResult(0, "失败");
}

5、启动项目,访问 Eureka 监控页面查看:

四、消费者 consumer 创建并注册

1、引入依赖:

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

2、启动类添加注解:

@EnableEurekaClient

3、修改配置文件:

server:
  port: 8002
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:9001/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

4、创建 controller 调用服务提供者接口:

@Resource
private DiscoveryClient client;

@RequestMapping(value = "test")
public RespResult getUsers() {
    // 获取服务列表
    List<String> services = client.getServices();
    services.forEach(service -> System.out.println(service));
    // 获取服务链接,因为只有一个服务,所有直接 get(0) 获取
    List<ServiceInstance> instances = client.getInstances("producer");
    ServiceInstance instance = instances.get(0);
    // 获取 ip 以及端口信息
    String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/user/list";
    return restTemplate.getForObject(url, RespResult.class);
}

5、启动服务查看注册中心:

6、访问 http://127.0.0.1:8002/test 测试:

使用 Dockerfile 以及 docker-compose 搭建 Eureka 集群

一、准备工作

1、pom引入插件:
docker-maven-plugin 插件就是了帮助我们在 Maven工程中,通过简单的配置,自动生成镜像并推送到仓库中。

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>1.2.0</version>
            <executions>
                <!--设置在执行maven 的install时构建镜像-->
                <execution>
                    <id>build-image</id>
                    <phase>install</phase>
                    <goals>
                        <goal>build</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

2、配置 application.yml

spring:
  application:
    name: eureka-server

---
spring:
  # 指定profile=eureka-server1
  profiles: eureka-server1
server:
  port: 8001
eureka:
  instance:
    # 指定当profile=eureka-server1时,主机名是eureka-server1
    hostname: eureka-server1
  client:
    register-with-eureka: true
    fetch-registry: true
    serviceUrl:
      # 将自己注册到eureka-server2这个Eureka上面去
      defaultZone: http://eureka-server2:8002/eureka/,http://eureka-server3:8003/eureka/

---
spring:
  profiles: eureka-server2
server:
  port: 8002
eureka:
  instance:
    hostname: eureka-server2
  client:
    register-with-eureka: true
    fetch-registry: true
    serviceUrl:
      defaultZone: http://eureka-server1:8001/eureka/,http://eureka-server3:8003/eureka/

---
spring:
  profiles: eureka-server3
server:
  port: 8003
eureka:
  instance:
    hostname: eureka-server3
  client:
    register-with-eureka: true
    fetch-registry: true
    serviceUrl:
      defaultZone: http://eureka-server1:8001/eureka/,http://eureka-server2:8002/eureka/

3、编写 Dockerfile 文件构建 eureka-server 镜像:

# 基于 java8 镜像
FROM java:8
# 映射卷,视情况设置
VOLUME /root/eureka/share
# 复制 eureka-server.jar 应用并执行
ADD app.jar app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT  ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

4、编写 docker-compose.yml

version: '2'
services:
  eureka-server1:
    image: eurekaserver
    container_name: eureka-server1
    hostname: eureka-server1
    networks:
      - eureka-net
    ports:
      - 8001:8001
    environment:
      - spring.profiles.active=eureka-server1

  eureka-server2:
    image: eurekaserver
    container_name: eureka-server2
    hostname: eureka-server2
    networks:
      - eureka-net
    ports:
      - 8002:8002
    environment:
      - spring.profiles.active=eureka-server2

  eureka-server3:
    image: eurekaserver
    container_name: eureka-server3
    hostname: eureka-server3
    networks:
      - eureka-net
    ports:
      - 8003:8003
    environment:
      - spring.profiles.active=eureka-server3
networks:
  eureka-net:
    driver: bridge

注:使用docker部署eureka集群会报循环依赖,在这里使用多个容器共享一个网络的方式解决的。
摘自:http://www.itmuch.com/docker-compose-eureka-ha/

5、maven 打包 eureka 并改名为 app.jar:

二、部署

1、创建一个文件夹存放 Dockerfiledocker-compose.ymlapp.jar

2、构造镜像:

docker build -t eurekaserver .

3、创建容器:

docker-compose up -d

简单的集群搭建完毕

三、生产者、消费者注册到注册中心

只需要修改 yml eureka-server 地址即可:

eureka:
  client:
    service-url:
      # eureka-server地址
      defaultZone: http://[服务器地址]:8001/eureka,http://[服务器地址]:8002/eureka,http://[服务器地址]:8003/eureka

消费者调用生产者接口:

Eureka 的自我保护机制

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

默认情况下,Eureka Client会定时的向 Eureka Server端发送心跳包,默认是30s发送一次,目的是告诉 Eureka Server当前客户端实例还处于存活状态,如果Eureka server在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒),但是,如果短时间内丢失大量的实例心跳,便会触发Eureka server的自我保护机制的 ,默认自我保护机制处于开启状态,比如在开发测试时,需要频繁地重启微服务实例客户端,但是我们很少会把eureka server一起重启(因为在开发过程中不会修改eureka注册中心),当一分钟内收到的心跳数大量减少时,会触发该保护机制。可以在eureka管理界面看到Renews thresholdRenews(last min),当Renews(last min)(最后一分钟收到的心跳数)小于Renews threshold(心跳阈值)的时候,如果某个服务实例宕机掉,触发保护机制,会出现红色的警告:

配置关闭 Eureka 的自我保护机制

Eureka自我保护机制默认是开启的,如果如果需要关闭自我保护机制,按照下述方式: enable-self-preservation: false 开关关闭掉,然后修改客户端和服务端相关参数,保证异常服务能及时剔除。

# Eureka 自我保护机制
server:
  # 是否开启 Eureka 的自我保护机制(默认为true)
  enable-self-preservation: false
  # 配置 Eureka Server 清理无效节点的时间间隔(单位毫秒,默认60*1000毫秒,即60秒)
  eviction-interval-timer-in-ms: 60000

不关闭保护机制的情况下手动剔除服务(优雅停服)

1、Eureka Client 引入依赖:

<!--监控依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、配置文件:

management:
  endpoints:
    web:
      exposure:
        include: shutdown #暴漏shutdown端点服务
  endpoint:
    shutdown:
      enabled: true

3、发送 post 请求手动剔除服务:

http://ip:port/actuator/shutdown

Eureka 的默认参数

Eureka Client 配置

eureka:
  instance:
    #eureka服务端在接受到实例的最后一次发出的心跳后,需要等待多久才可以将此删除,单位为秒(默认为90s),超过时间则剔除(客户端会按照此规则向Eureka服务端发送心跳检测包)
    lease-expiration-duration-in-seconds: 90
    #eureka客户端需要多长时间发送心跳给eureka服务端,单位为秒(默认为30s),(客户端会按照此规则向Eureka服务端发送心跳检测包)
    lease-renewal-interval-in-seconds: 30

Eureka Client 消费者配置

eureka:
  client:
    #表示eureka client间隔多久去拉取服务器注册信息,默认为30秒
    registry-fetch-interval-seconds: 5

全部评论0