敖胤

绳锯木断,水滴石穿;聚沙成塔,集腋成裘。

导航

Spring Cloud Netflix 学习笔记(一)—服务治理(Eureka)

服务治理通过抽象将服务消费者和服务提供者进行隔离。消费者不需要知道具体服务提供者的真实物理地址就可以进行调用,也无须知道具体有多少个服务者可用;而服务提供者只需要将自己注册到服务治理服务器中就可以对外提供服务,也不需要知道具体是哪些服务调用了自己。另一方面,服务治理能够为微服务架构提升应用弹性,当其中的一个服务提供者实例不可用或者出现问题时,服务治理服务器可以发现这个有问题的服务实例,在调度服务消费者时可以绕开有问题的服务实例,从而将对应用的影响降低到最低。

通常来说服务治理包括两部分,一个是服务器端(Server,注册中心),另一个是客户端(Client,应用服务)。Server是一个公共服务,为Client提供服务注册和发现的功能,维护注册到自身的Client的相关信息,同时提供接口给Client获取注册表中其他服务的信息,使得动态变化的Client能够进行服务间的相互调用。Client将自己的服务信息通过一定的方式登记到Server上,并在正常范围内维护自己信息一致性,方便其他服务发现自己,同时可以通过Server获取到自己依赖的其他服务信息,完成服务调用。

Eureka是一个RESTful风格的服务注册与发现的基础服务组件。它由两部分组成,一个是Eureka Server,提供服务注册和发现功能,即服务器端;另一个是Eureka Client,它简化了客户端与服务端之间的交互。Eureka Client会定时将自己的信息注册到Eureka Server中,并从Server中发现其他服务。Eureka Client中内置一个负载均衡器,用来进行基本的负载均衡。

1、搭建 Eureka Server

1.1、创建maven项目

在springcloud父工程下,创建一个名为eureka_server_0的maven子模块

1.2、导入依赖

在eureka_server_0的pom.xm中添加如下依赖:

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

1.3、添加配置

在application.yml配置文件中添加以下配置:

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    #是否向Eureka Server注册自己,因为自身是Server且目前是单机版,所以选择false
    registerWithEureka: false
    #是否从Eureka Server获取服务注册信息,因为自身是Server且目前是单机版,所以选择false
    fetchRegistry: false
    #Eureka Server地址,用于Client与Server通讯
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
  application:
    name: server0

1.4、编写启动类

为eureka_server_0编写一个Spring Boot启动类,并在类上添加@EnableEurekaServer注解

@SpringBootApplication
@EnableEurekaServer
public class ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }
}

1.5、启动服务

启动eureka_server_0,在浏览器直接访问http://localhost:8761/,看到如下页面表示Server创建成功:

2、搭建Eureka Client

在springcloud父工程下,创建emp和dept两个子模块

2.1、导入依赖

导入Eureka Client的依赖包

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

2.2、添加配置

分别各emp和dept添加如下配置

server:
  port: 8080

spring:
  application:
    name: emp

eureka:
  client:
    #服务注册地址
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
    #从server中拉取服务注册信息到本地
    fetch-registry: true
    #本服务注册到server中
    register-with-eureka: true

server:
  port: 8081

spring:
  application:
    name: dept

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
    fetch-registry: true
    register-with-eureka: true

2.3、编写启动类

@SpringBootApplication
@EnableEurekaClient //此注解为非必输
public class EmpApplication {
    public static void main(String[] args) {
        SpringApplication.run(EmpApplication.class, args);
    }
}

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

2.4、启动服务

启动eureka_server_0和emp、dept

访问http://localhost:8761/,看到如下页面,表示服务已经注册到Eureka Server。

3、服务注册说明

Eureka Server与Eureka Client之间的联系主要通过心跳的方式实现。心跳(Heartbeat)即Eureka Client定时向Eureka Server汇报本服务实例当前的状态,维护本服务实例在注册表中租约的有效性。

一个服务实例注册到Eureka服务器时大概需要30秒才能够在控制台中查看到该服务。这是因为,Eureka要求服务提供者必须发送3次心跳(默认每次心跳间隔为10秒)后才认为该服务实例已经准备好,可以对外提供服务了。

Eureka Server需要随时维持最新的服务实例信息,所以在注册表中的每个服务实例都需要定期发送心跳到Server中以使自己的注册保持最新的状态(数据一般直接保存在内存中)。为了避免Eureka Client在每次服务间调用都向注册中心请求依赖服务实例的信息,Eureka Client将定时从Eureka Server中拉取注册表中的信息,并将这些信息缓存到本地,用于服务发现。

4、安全认证

实际使用中,注册中心地址可能含有公网IP,如果不加权限认证而让人能直接访问,这是不安全的。

所以需要对Eureka Server进行改造,加上权限认证来保证安全性。通常是通过在Eureka Server集成Spring-Security的方式来处理。

4.1、导入依赖

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

4.2、添加Security配置类

在Server中编写WebSecurityConfig配置类,继承WebSecurityConfigurerAdapter并重写configure方法

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }
}

4.3、修改配置

  • 为Server配置安全认证用户名与密码
spring:
  application:
    name: server0
  #安全认证用户名与密码
  security:
    user:
      name: scott
      password: scott
  • Client中修改注册链接,在IP前添加“用户名:密码@”
eureka:
  client:
    serviceUrl:
      defaultZone: http://scott:scott@localhost:8761/eureka/
    fetch-registry: true
    register-with-eureka: true

重启后访问http://localhost:8761/,会跳转到登录页面,输入配置的用户名和密码即可正常访问Eureka管理页面。

5、搭建Eureka Server集群

Eureka的集群搭建方法很简单:每一台Eureka只需要在配置中指定另外多个Eureka的地址就可以实现一个集群的搭建了。

以2个节点为例:我们有server0和server1两台机器,需要做的就是:

  • 将server0注册到server1上面。

  • 将server1注册到server0上面。

5.1、新建eureka_server_1模块

这里使用复制eureka_server_0的方式,快速创建一个maven模块。

5.1.1、打开eureka_server_0路径

5.1.2、复制eureka_server_0

5.1.3、修改此副本
  • 重命名

  • 进入副本,删除target文件夹及.iml文件

  • 修改pom.xml中artifactId为eureka_server_1

      <artifactId>eureka_server_1</artifactId>
    
  • 在springcloud父工程的pom.xml中添加eureka_server_1模块

    <modules>
        <module>eureka_server_0</module>
        <!--添加eureka_server_1模块-->
        <module>eureka_server_1</module>
        <module>emp</module>
        <module>dept</module>
    </modules>
    
  • 修改配置

    server:
      port: 8762	#修改端口号
    spring:
      application:
        name: server1	#修改应用名
      security:
        user:
          name: scott
          password: scott
    

5.2、相互注册

要实现Eureka Server之间的相互注册,只需要稍加修改其配置,让两台Server开启注册与拉取服务即可。

  • eureka_server_0配置
eureka:
  instance:
    hostname: localhost
  client:
  	#开启
    registerWithEureka: true
    #开启
    fetchRegistry: true
    #注册到eureka_server_1,当有多台时,用英文逗号分隔
    serviceUrl: 
      defaultZone: http://scott:scott@localhost:8762/eureka/
  • eureka_server_1配置
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: true
    fetchRegistry: true
    #注册到eureka_server_0,当有多台时,用英文逗号分隔
    serviceUrl:
      defaultZone: http://scott:scott@localhost:8761/eureka/

5.3、服务注册

将emp注册到eureka_server_0,dept注册到eureka_server_1:

server:
  port: 8080

spring:
  application:
    name: emp

eureka:
  client:
    serviceUrl:
      defaultZone: http://scott:scott@localhost:8761/eureka/
    fetch-registry: true
    register-with-eureka: true

server:
  port: 8081

spring:
  application:
    name: dept

eureka:
  client:
    serviceUrl:
      defaultZone: http://scott:scott@localhost:8762/eureka/
    fetch-registry: true
    register-with-eureka: true

5.4、启动访问

启动eureka_server_0和eureka_server_1,等待同步后,可看到如下页面:


6、常用配置

6.1、Eureka Server保护模式

保护模式主要在一组客户端和Eureka Server之间存在网络分区场景时使用。一旦进入保护模式,Eureka Server将会尝试保护其服务的注册表中的信息,不再删除服务注册表中的数据。当网络故障恢复后,该Eureka Server节点会自动退出保护模式。如果在Eureka的Web控制台看到下图所示的内容,就证明Eureka Server进入保护模式了。

自我保护模式的配置如下,默认为true—开启

eureka:
  server:
    enable-self-preservation: true

6.2、心跳与宕机

  • Eureka Client服务启动时,会将自己的信息注册到Eureka Server上
  • 当Eureka Client调用其他服务时,先查询本地有没有目标服务的信息,没有则从Eureka Server上拉取
  • Eureka Client定时向Eureka Server发送一次消息(心跳请求),以通知注册中心自己处于“还活着”状态。默认是30s发送一次心跳请求,如果Eureka Server在给定时间内没有收到Eureka Client的消息,则会认为这个Client已经宕机,那么Eureka Server会移除掉此Eureka Client的注册信息。心跳间隔和宕机判定时间可通过如下参数设置:
eureka:
  instance:
  	#心跳间隔时间,单位s,默认30;表示Eureka Client向Eureka Server发送消息的时间间隔
    lease-renewal-interval-in-seconds: 45	
    #宕机判断时间,单位s,默认90;表示Eureka Server至上一次收到Client的心跳之后,等待下一次心跳的超时时间
    lease-expiration-duration-in-seconds: 120		
  • Eureka Client会定时从Eureka Server更新一次本地缓存中的注册信息。默认也是30s,可通过如下参数设置:
eureka:
  client:
    registry-fetch-interval-seconds: 45

6.3 自定义Eureka的InstanceID

客户端在注册时,服务的Instance ID的默认值的格式如下:

eureka:
  instance:
    instance-id: ${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id}:${server.port}

可自定义使其显示端口号:

eureka:
  instance:
    instance-id: ${spring.cloud.client.hostname}:${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}

6.4、使用IP注册

eureka:
  instance:
    prefer-ip-address: true

添加前后服务路径变化如下

  • 添加后

6.5、自定义实例跳转链接

自定义服务默认访问路径

eureka:
  instance:
    status-page-url: http://www.baidu.com

7、CAP原则

CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。而由于网络硬件肯定会出现延迟丢包等问题,所以分区容错性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡。

  • 满足CA舍弃P,也就是满足一致性和可用性,舍弃容错性。但是这也就意味着你的系统不是分布式的了,因为涉及分布式的想法就是把功能分开,部署到不同的机器上。

  • 满足CP舍弃A,也就是满足一致性和容错性,舍弃可用性。如果你的系统允许有段时间的访问失效等问题,这个是可以满足的。就好比多个人并发买票,后台网络出现故障,你买的时候系统就崩溃了。

  • 满足AP舍弃C,也就是满足可用性和容错性,舍弃一致性。这也就是意味着你的系统在并发访问的时候可能会出现数据不一致的情况。

实时证明,大多数都是牺牲了一致性。像12306还有淘宝网,就好比是你买火车票,本来你看到的是还有一张票,其实在这个时刻已经被买走了,你填好了信息准备买的时候发现系统提示你没票了。这就是牺牲了一致性。

但是不是说牺牲一致性一定是最好的。就好比mysql中的事务机制,张三给李四转了100块钱,这时候必须保证张三的账户上少了100,李四的账户多了100。因此需要数据的一致性,而且什么时候转钱都可以,也需要可用性。但是可以转钱失败是可以允许的。

Eureka使用的是AP模式。

posted on 2021-03-12 22:46  敖胤  阅读(208)  评论(0)    收藏  举报