Spring Cloud与Docker微服务架构实战(三)—— 服务注册与发现

谁践踏了优雅 2022-12-10 04:57 221阅读 0赞

四、微服务注册与发现

解决硬编码提供服务地址的问题,需要一个强大的服务发现机制。服务发现组件正是微服务架构中十分关键的一个组件。

服务提供者、消费者、服务发现组件三者的关系大致如下:

  • 各个微服务在启动时,将自己的网络地址等信息注册到服务发现组件中,服务发现组件会存储这些信息。
  • 服务消费者可从服务发现组件查询服务提供者的网络地址,并使用该地址调用服务提供者的接口
  • 各个微服务与服务发现组件使用一定机制(心跳)通信。服务发现组件如长时间无法与某微服务实例通信,就会注销该实例
  • 微服务网络地址发生变更(实例增减或IP端口变化),会重新注册到服务发现组件,不用人工修改

在这里插入图片描述

综上,服务发现组件应该具备如下功能:

  • 服务注册表:记录各个微服务信息。提供查询API和管理API,查询API用于查询可用微服务实例,管理API用于服务的注册和注销
  • 服务注册与服务发现:服务注册是指微服务在启动时,将自己的信息注册到服务发现组件上的过程。服务发现是指查询可用微服务列表及其网络地址的机制
  • 服务检查:服务发现组件使用一定机制定时检测已注册的服务,如果发现某实例长时间无法访问,就会从服务注册表中移除该实例

1.Eureka简介

Eureka是Netflix开源的服务发现组件,本身是一个基于REST的服务。包含server和client两部分。Spring Cloud将它集成在子项目Spring Cloud Netflix中,实现微服务的注册与发现。

2.Eureka原理

在这里插入图片描述

  • Application Service 服务提供者
  • Application Client 服务消费者
  • Make Remote Call 调用RESTful API行为

两个组件

  • Eureka Server 提供服务发现能力,各个微服务启动时,会向Eureka Server注册自己的信息,Eureka Server 进行存储
  • Eureka Client 是一个Java客户端,简化与 Eureka的交互
  • 微服务启动后,会周期性(默认30秒)地向Eureka Server发送心跳续约自己的“租期”
  • 如果Eureka Server 在一定时间内没有接收到某个微服务实例的心跳,Eureka Server会注销该实例(默认90秒)
  • 默认情况下,Eureka Server 同时也是 Eureka Client,多个Eureka Server实例,互相之间通过复制,来实现服务注册表中数据的同步
  • Eureka Client 会缓存服务注册表中的信息。优势:降低server的压力,加快查询服务的速度;及时server的所有节点都宕机,服务消费者依然可以使用缓存中信息找到服务提供者

3.编写 Eureka Server

创建Spring Boot项目,artifactId为 microservice-discovery-eureka,添加如下依赖:

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  4. <version>2.2.5.RELEASE</version>
  5. </dependency>

编写启动类,在启动类上加上@EnableEurekaServer注解,声明这是一个Eureka Server

  1. @EnableEurekaServer
  2. @SpringBootApplication
  3. public class EurekaServerApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(EurekaServerApplication.class, args);
  6. }
  7. }

配置文件如下:

  1. server:
  2. port: 8761
  3. eureka:
  4. client:
  5. # 默认交互地址
  6. service-url:
  7. defaultZone: http://localhost:8761/eureka/
  8. # 不要注册自己,因为自己就是server
  9. register-with-eureka: false
  10. # 不要同步注册服务列表,因为只有单节点
  11. fetch-registry: false

启动项目,访问 http://localhost:8761,得到如下结果

在这里插入图片描述

4.将微服务注册到Eureka Server上

在microservice-simple-provider-user 项目的pom.xml下添加如下依赖

  1. <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  5. <version>2.2.5.RELEASE</version>
  6. </dependency>

配置文件如下

  1. server:
  2. port: 8080
  3. spring:
  4. datasource:
  5. #通用数据源配置
  6. driver-class-name: com.mysql.cj.jdbc.Driver
  7. url: jdbc:mysql://localhost:3306/test?charset=utf8mb4&useSSL=false
  8. username: root
  9. password: 123456
  10. # Hikari 数据源专用配置 Hikari 是Springboot用的连接池
  11. hikari:
  12. maximum-pool-size: 20
  13. minimum-idle: 5
  14. #初始化数据
  15. # JPA 相关配置
  16. jpa:
  17. database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
  18. show-sql: true
  19. hibernate:
  20. # 慎用!
  21. # ddl-auto: create
  22. # 注册到服务发现中心的名称
  23. application:
  24. name: microservice-simple-provider-user
  25. eureka:
  26. client:
  27. service-url:
  28. defaultZone: http://localhost:8761/eureka/
  29. # 将自己的IP注册到服务发现中心,如果为false,则注册所在操作系统的hostname
  30. instance:
  31. prefer-ip-address: true
  32. logging:
  33. level:
  34. root: INFO
  35. org.hibernate: INFO
  36. org.hibernate.type.descriptor.sql.BasicBinder: TRACE
  37. org.hibernate.type.descriptor.sql.Extractor: TRACE
  38. management:
  39. endpoints:
  40. web:
  41. base-path: /actuator #如果修改,则监管点访问路径前缀也会改变
  42. exposure:
  43. include: "*" #星号代表暴露全部,可以选择暴露部分,填入想暴露的即可
  44. info:
  45. app:
  46. name:microservice-simple-provider-user

编写启动类,启动类上加上 @EnableDiscoveryClient 注解,声明这是一个Eureka Client

  1. @EnableDiscoveryClient
  2. @SpringBootApplication
  3. public class MicroserviceSimpleProviderUserApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(MicroserviceSimpleProviderUserApplication.class, args);
  6. }
  7. }

@EnableDiscoveryClient 为各种服务组件提供支持,该注解是 Spring-cloud-commons项目的注解,高度抽象;

@EnableEurekaClient表明是Eureka的Client,只能与Eureka一起工作

完成上述步骤后,就可以将用户微服务注册到Eureka Server上了,同样改造电影微服务,改造完毕后,启动所有微服务,访问注册中心,可以看到如下界面

在这里插入图片描述

可以看到,用户微服务、电影微服务都被注册到了Eureka Server上了

5. Eureka Server的高可用

微服务十分关注高可用,作为微服务之一的注册中心也不例外。之前设置的不让注册中心注册自己,现在需要让注册中心把自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,实现服务清单的互相同步,达到高可用的目的。

在前面项目基础上,进行修改,构建一个双节点的服务注册中心集群

1.复制项目,将项目的artifactId改为microservice-discovery-eureka-ha,里面的名称相应进行修改

2.配置系统的hosts,macOS 文件路径为 /etc/hosts,添加以下内容

  1. 127.0.0.1 peer1 peer2

3.修改application.yaml ,让两个节点的Eureka互相注册

  1. spring:
  2. application:
  3. name: microservice-discovery-eureka-ha
  4. ---
  5. spring:
  6. # 指定profiles 为 peer1
  7. profiles: peer1
  8. server:
  9. port: 8761
  10. eureka:
  11. instance:
  12. # 指定 profile 为 peer1 时,hostname 为peer1
  13. hostname: peer1
  14. client:
  15. # 注册到 peer2上去
  16. service-url:
  17. defaultZone: http://peer2:8762/eureka/
  18. ---
  19. spring:
  20. # 指定profiles 为 peer2
  21. profiles: peer2
  22. server:
  23. port: 8762
  24. eureka:
  25. instance:
  26. # 指定 profile 为 peer2 时,hostname 为peer2
  27. hostname: peer2
  28. client:
  29. # 注册到 peer1上去
  30. service-url:
  31. defaultZone: http://peer1:8761/eureka/

---将配置文件分为三段

二三段为spring.properties 指定了一个值,表示它所在的那段内容应用在哪个profile里

以不同的profile启动时,会有不同的配置

  • 打包项目,使用以下两个项目启动两个Eureka Server节点,使用 mvn package打包
  • java -jar microservice-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1

    java -jar microservice-discovery-eureka-ha-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2

  • 访问peer1:8761,发现registered-replicas 有peer2节点,同理访问peer2:8762,发现有peer1节点。如下图

在这里插入图片描述

将应用注册到Eureka集群上

只需要修改配置文件中的 Eureka Server地址(配置多个),就可以注册到集群上了。其实只配置Eureka Server集群中的某个节点,也能正常注册到集群上, 因为多个server之间会数据同步

示例如下:

  1. eureka:
  2. client:
  3. service-url:
  4. defaultZone: http://peer1:8761/eureka/, http://peer2:8762/eureka/

在这里插入图片描述

为Eureka Server添加用户认证

1.复制microservice-discovery-eureka,修改artifactId为microservice-discovery-eureka-authenticating,这里直接修改原项目

2.pom.xml中添加spring-boot-starter-security依赖,提供用户认证能力

  1. <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-security</artifactId>
  5. <version>2.3.4.RELEASE</version>
  6. </dependency>

3.添加配置文件内容如下

  1. security:
  2. basic:
  3. enable: true
  4. user:
  5. name: user
  6. password: user123456

登陆账号为user,密码为user123456,再次访问eureka主页,就会要求进行登录,初始密码会在控制台打印出来

将微服务注册到需认证的Eureka Server

修改一下 eureka客户端配置的注册中心交互地址即可,改为

  1. eureka:
  2. client:
  3. service-url:
  4. defaultZone: http://user:user123456@localhost:8761/eureka/

Eureka的元数据

Eureka元数据有两种,标准元数据和自定义元数据

标准元数据

  • 主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用

自定义元数据

  • 可以使用 eureka.instance.metadata-map配置,这些元数据可以在远程客户端中访问,一般不会改变客户端的行为,除非客户端知道该元数据的含义

关于元数据的示例

改造用户微服务,修改配置文件

  1. instance:
  2. prefer-ip-address: true
  3. metadata-map:
  4. my-metadata: 我自定义的元数据

改造电影微服务,修改controller,添加以下方法

  1. /* * 查询 microservice-simple-provider-user的实例信息 * @return */
  2. @GetMapping("/user-instance")
  3. public List<ServiceInstance> showInfo(){
  4. return this.discoveryClient.getInstances("microservice-simple-provider-user");
  5. }

启动eureka 注册中心,用户微服务和电影微服务,注意这里注册中心的地址不要弄混了

访问localhost:8010/user-instance,返回如下内容

  1. [
  2. {
  3. "metadata": {
  4. "management.port": "8080",
  5. "my-metadata": "我自定义的元数据"
  6. },
  7. "serviceId": "MICROSERVICE-SIMPLE-PROVIDER-USER",
  8. "uri": "http://172.19.173.181:8080",
  9. "secure": false,
  10. "scheme": "http",
  11. "host": "172.19.173.181",
  12. "port": 8080,
  13. "instanceId": "172.19.173.181:microservice-simple-provider-user:8080",
  14. "instanceInfo": {
  15. "instanceId": "172.19.173.181:microservice-simple-provider-user:8080",
  16. "app": "MICROSERVICE-SIMPLE-PROVIDER-USER",
  17. "appGroupName": null,
  18. "ipAddr": "172.19.173.181",
  19. "sid": "na",
  20. "homePageUrl": "http://172.19.173.181:8080/",
  21. "statusPageUrl": "http://172.19.173.181:8080/actuator/info",
  22. "healthCheckUrl": "http://172.19.173.181:8080/actuator/health",
  23. "secureHealthCheckUrl": null,
  24. "vipAddress": "microservice-simple-provider-user",
  25. "secureVipAddress": "microservice-simple-provider-user",
  26. "countryId": 1,
  27. "dataCenterInfo": {
  28. "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
  29. "name": "MyOwn"
  30. },
  31. "hostName": "172.19.173.181",
  32. "status": "UP",
  33. "overriddenStatus": "UNKNOWN",
  34. "leaseInfo": {
  35. "renewalIntervalInSecs": 30,
  36. "durationInSecs": 90,
  37. "registrationTimestamp": 1600829307368,
  38. "lastRenewalTimestamp": 1600829456688,
  39. "evictionTimestamp": 0,
  40. "serviceUpTimestamp": 1600829306779
  41. },
  42. "isCoordinatingDiscoveryServer": false,
  43. "metadata": {
  44. "management.port": "8080",
  45. "my-metadata": "我自定义的元数据"
  46. },
  47. "lastUpdatedTimestamp": 1600829307368,
  48. "lastDirtyTimestamp": 1600829306684,
  49. "actionType": "ADDED",
  50. "asgName": null
  51. }
  52. }
  53. ]

Eureka Server的REST端点

提供一些REST端点,供非JVM微服务操作Eureka。一般来说很少用原始的http请求来操作,很多语言提供一些工具包来封装了这些API。此节不展开介绍

Eureka 的自我保护模式

默认情况,Eureka Server一定时间内没有收到某个微服务实例心跳,会注销该实例,但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,微服务是健康的,却被注销掉了

通过自我保护模式来解决这个问题,当Eureka Server节点短时间内丢失过多客户端时,这个节点会进入自我保护模式。之后Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据。故障恢复后,Eureka Server节点会自动退出自我保护模式。

可以使用 eureka.server.enable-self-preservation = false 禁用自我保护

多网卡环境下的IP选择

如果某个服务器有 eth0、eth1和eth2三块网卡,但只有eth1可以被其他服务器访问,如果将eth0和eth2注册到Eureka Server上,其他微服务无法通过此IP调用该微服务接口

Spring Cloud 提供了按需选择IP的能力,避免以上问题

1.忽略指定名称网卡

  1. spring:
  2. cloud:
  3. inetutils:
  4. ignored-interfaces:
  5. - docker0
  6. - veth.*
  7. eureka:
  8. instance:
  9. prefer-ip-address: true

这样就可以忽略docker0网卡以及所有以veth开头的网卡

2.正则表达式,指定使用的网络地址

  1. spring:
  2. cloud:
  3. inetutils:
  4. preferredNetworks:
  5. - 192.168
  6. - 10.0
  7. eureka:
  8. instance:
  9. prefer-ip-address: true

3.只使用站点本地地址

  1. spring:
  2. cloud:
  3. inetutils:
  4. useOnlySiteLocalInterfaces: true
  5. eureka:
  6. instance:
  7. prefer-ip-address: true

4.手动指定IP地址

  1. eureka:
  2. instance:
  3. prefer-ip-address: true
  4. ip-address: 127.0.0.1

Eureka 健康检查

一般在Eureka首页,Status栏中显示UP,则该应用程序状态正常。还有其他取值,如DOWN、OUT_OF_SERVICE、UNKNOWN等。只有UP的微服务才会被请求,默认情况下,服务端与客户端心跳保持正常,应用程序就会始终保持“UP”状态。

但以上机制不能完全反映应用程序状态。微服务与Eureka Server之间心跳正常,Eureka Server认为该微服务“UP”,实际上该微服务的数据源有问题(网络抖动连不上),根本无法正常工作

前面提到过,使用 Spring Boot Actuator可以展示应用程序健康信息,如何才能将该端点的健康状态传播到 Eureka Server呢?

为Eureka开启健康检查,配置如下,在微服务配置文件中设置

  1. eureka:
  2. client:
  3. healthcheck:
  4. enabled: true

副作用:

  • 如果在 bootstrap.yml配置,可能会使注册状态为UNKNOWN
  • /pause 端点无法正常工作(BUG)

发表评论

表情:
评论列表 (有 0 条评论,221人围观)

还没有评论,来说两句吧...

相关阅读