转载

Spring Cloud学习笔记(3)- Euraka基本概念

Euraka是Netflix开发的开源框架。Spring-Cloud Euraka是Euraka的Spring Cloud组件。当然Spring-Cloud还集成了诸如:Zookepper、Consul等组件。他们都可以实现服务发现的相关过程。

Euraka与Zookeeper

在目前Web开发中,主要使用Euraka,原因如下所示:

  • Zookepper主要强调一致性和分区容错性,对可用性的倾斜程度不够。在大多数网络应用中,实际上较为强调可用性。当然在一些需要强一致性要求的项目中也是可以使用Zookepper,诸如银行账户信息同步等等服务管理。
  • Euraka主要强调可用性和分区容错性,对日常Web开发较为适用。

Tips:

服务发现支持其他语言开发的服务注册和发现,微服务架构更好的提供了异构的工具集。 关于为什么使用Euraka作为服务发现工具可以参见这篇文章: dockone.io/article/78

本篇参考文章:

www.itmuch.com/spring-clou… 周立老师的Spring 教程系列

本人只是对这篇文章中的示例做了细节的描述,并且把一些基础的、容易迷惑的点做了细节的补充,大家可以先看周立老师的教程,然后来这里补充一些基础的概念。

1 新键一个分布式服务

  1. 打开IDEA 新键 控制台项目
  2. 添加框架支持 --> maven
  3. 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>

    <groupId>org.bruce.study</groupId>
    <artifactId>UserRegisterService</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.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-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- 引入H2数据库 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
    <!-- 引入spring cloud的依赖,管理Spring Cloud生态各组件的版本 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</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>
</project>
复制代码

关键点描述

由于Spring Cloud具有很多个版本,在Maven中需要配置Spring Boot的parent节点,该节点指定了当前Web项目使用的Spring Boot版本:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
复制代码

还需要使用dependencyManagement节点指定当前使用的Spring Cloud版本号:

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
复制代码

需要注意的是:

为什么Spring Boot不使用最新版本?(写此文章时,Spring Boot最新版本是2.3.1)

Spring Cloud不同版本要求使用的Spring Boot版本不一致,具体参见下表:

版本号 说明 是否推荐使用
纯数字版本号 开发版 开发团队内部使用,不是很稳定
GA 稳定版 相比于开发版,基本上可以使用了
PRE(M1、M2) 里程碑版 主要是修复了一些BUG的版本,一个GA后通常有多个里程碑版
RC 候选发布版 该阶段的软件类似于最终版的一个发行观察期,基本只修复比较严重的BUG
SR 正式发布版 可以投入生产的版本

++https://start.spring.io/actuator/info++ Spring Cloud与Spring Boot版本兼容性规则参见此网址相关版本说明(JSON格式)

通过Maven配置,我们构建分布式服务主要使用了:

  • H2数据库
  • JPA
  • Spring Boot
  • spring-cloud-starter-netflix-eureka-client

前三个的作用大家应该都懂了,>spring-cloud-starter-netflix-eureka-client用于当前分布式服务被识别为一个Eureka客户端。Eureka客户端将可以被注册至Eureka服务器。

2 编写一个分布式服务

package org.bruce.study.controller;

import org.bruce.study.Entities.User;
import org.bruce.study.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserDao userDao;

    @GetMapping("/{id}")
    public Optional<User> getUserById(
            @PathVariable
                    Integer id) {
        return this.userDao.findById(id);
    }
}

复制代码

Spring Boot 2.0.x相关知识请自行学习。

以上就是我们的服务提供了一个通过用户ID查询用户的服务,该服务提供Get请求方式。

3 配置服务运行参数

application.yml文件

server:
  # 指定Tomcat端口
  port: 8088
spring:
  application:
    name: userservice
  jpa:
    # 让hibernate打印执行的SQL
    show-sql: true

logging:
  level:
    root: INFO
    # 配置日志级别,让hibernate打印出执行的SQL参数
    org.hibernate: INFO
    org.hibernate.type.descriptor.sql.BasicBinder: TRACE
    org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
management:
  endpoint:
    health:
      # 是否展示健康检查详情
      show-details: always
eureka:
  client:
    service-url:
      # 指定eureka server通信地址,注意/eureka/小尾巴不能少
      defaultZone: http://localhost:8761/eureka/
  instance:
    # 是否注册IP到eureka server,如不指定或设为false,那就会注册主机名到eureka server
    prefer-ip-address: true

复制代码

Tips:

  • 指定当前服务运行端口 8088
  • 指定了服务的名称为:userservcie,注意这个名称就是当前服务注册至Eureka服务发现中的名称。
  • management:指定了当前Spring Boot运行监控。
  • eureka节点指定了当前服务发现的相关细节。client节点是指当前Eureka客户端的相关配置,一般在此节点中指定服务发现服务器的地址。
  • eureka-instance节点配置当前节点eureka client实例相关信息。

Eureka客户端重要配置项

Client节点:

配置项 说明
region 当前客户端所在默认服务分区(默认值:us-east-1)
availability.zones 配置region下可用的分区(zone),多个zone使用逗号分隔,这里顺序很重要,系统会按照配置的顺序优先从前面的URL开始加载
serviceUrl 配置获取应用注册的服务器地址,多个服务器地址使用逗号分隔
registry-fetch-interval-seconds 从服务端获取最新的注册信息的时间步长,单位:秒。如果获取超时,第二次获取时间会翻倍
register.with.eureka 是否将当前服务注册至Eureka服务器。设置为false,即说明当前服务仅仅获取其他服务访问地址,当其本身并不注册至Eureka服务器。这样可以保护一些私密的接口访问(诸如:员工身份令牌认证服务,仅仅调用外部服务发现,但其本身并不注册至Eureka服务器)。
fetch.registry 是否需要从服务端获取注册信息,服务端如果是集群需要配置为true。
instance-info-replication-interval-seconds 扫描本地实例的时间步长,单位:秒。如果有变化向Eureka服务器重新注册当前服务。

instance节点:

配置项 说明
lease-renewal-interval-in-seconds 向服务器心跳的时间步长,单位:秒。当Eureka客户端第一次向服务端心跳成功,服务端将返回404,客户端后续会接着注册本地实例,注册成功,后续心跳返回200。
prefer-ip-address 当Eureka客户端注册至Eureka服务器时,是以ip地址还是主机名的方式注册当前服务。(建议:IP)
ip.address 当前Eureka客户端指定该Eureka实例的IP地址,当不配置该项时默认取第一个网卡的非回环地址。
lease-expiration-duration-in-seconds 当前Eureka服务端驱逐客户端的时间步长,单位:秒。Eureka服务端在满足一定条件时,将会移除一些已经无法访问的Eureka客户端。如果Eureka服务端超过90秒未收到某个客户端心跳,且该客户端未开启自我保护,Eureka服务端就会驱逐该客户端。如果该客户端开启自我保护,但是上一分钟注册的客户端数 > 服务端上一分钟收到客户端的心跳数 * 每分钟续约因子(0.85),也会驱逐客户端。

通过配置我们需要知道的主要知识点

  • Eureka Client是当前服务注册至Eureka Server的装饰器。
  • Eureka Client本身是一个Eureka Instance。
  • Eureka Client使用心跳来告知Eureka Server当前服务的前状态。
  • 如果Eureka Server一段时间接收不到某个Eureka Client的心跳消息,Eureka Server将会注销该Eureka Client。
  • Eureka Client主要用于发现服务,可以不注册至Eureka Server。
  • Region:可以简单理解为Eureka 服务的物理分区。分布式服务可能构建在不同地域的不同机房中,为了减少服务之间调用的物理延时,我们总是希望服务间调用应该优先调用本地服务,从而减少网络传输带来的延时。Region即当前服务器的分区,可以认为是基于服务器地理位置的分区方式带来的服务分类标识。
  • Zone:Zone可以被认为是基于Region的子分类,比如我们有多个机房集群,一个位于北京,一个位于上海。北京的机房集群可能拥有多台服务器,诸如:服务器S1,服务器S2,那么我们可以标识服务器S1的Zone为S1、服务器S2的Zone为S2.这样就可以做到有效的物理分离请求去向,从而进一步减少跨服务器调用,减少时延。

编写Eureka Server

1.Idea 新建控制台项目

项目名称:EurekaDemoServer

2.添加Maven支持

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>
    <groupId>org.bruce.study</groupId>
    <artifactId>EurekaDemoServer</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <!-- 引入spring cloud的依赖,不能少,主要用来管理Spring Cloud生态各组件的版本 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</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>
</project>
复制代码

Spring Cloud版本、Spring Boot版本等相关部分参见本章前文部分

3.添加EurekaServer启动类

package org.bruce.study;

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

@SpringBootApplication
@EnableEurekaServer
public class EurecaDemoServer {

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

复制代码

使用@EnableEurekaServer进行注解,该类即被认为是EurekaServer的启动类。

4.添加application.yml配置

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:8761/eureka/
复制代码

容易导致的疑惑

为什么Eureka Server配置中出现了Client和Instance的配置?

答:任何一个Eureka Server首先是一个Eureka Client。任何一个Eureka Clent都是一个Eureka Instance。

tips:

回忆一下 IS A原则(李氏替换原则)

为什么要这么设计?

答:Eureka Instance即Eureka实例,他主要包含了诸如心跳、服务状态回报等等基础的网络通信机制。Eureka Client可以被认为是Eureka Instance的扩展,它提供了更多、更实用的配置,包括诸如获取IP地址等等一些易用性的配置。至于为什么这么设计?很简单,就是为了保障Eureka Server也可以作为一个Eureka Client在其他Eureka Server上注册。

tips:

多个Eureka Server实例,互相之间通过增量复制的方式,来实现服务注册表中数据的同步。

这是什么意思呢?

就是我做了一个商城订单付款服务,深圳服务器上部署了Eureka Server1,沈阳服务器步数了Eureka Server2,Eureka Server1可以注册在Eureka Server2 上,Eureka Server2也可以注册在Eureka Server1上。Eureka Server1和Eureka Server2的服务将被增量更新到他们的服务注册表中去,这样用户访问就不会因为某一台服务器宕机导致整个服务无法访问,这就是保障了高可用性。

Eureka配置之中的一些疑惑

Long long time ago,Netfix为了让全美都可以访问他们部署在亚马逊云上的相关服务,编写了Eureka。所以Eureka配置中保留了很多亚马逊云中的相关概念,诸如伸缩服务等等相关概念。但是一定要明白亚马逊云作为始祖级别的云服务,他的很多概念在其他云服务中都存在,因为已经成为了一种习惯,大家都在沿用这些概念,所以Eureka无论实在阿里云或者腾讯云中,都可以无缝的部署和运行。所以对于Eureka配置中遗留的一些诸如ASG等等亚马逊云独有的概念,完全无需担心,这些概念在其他云服务中都可以找到对应的特性。

原文  https://juejin.im/post/5efda328f265da22ec607c6b
正文到此结束
Loading...