Spring Cloud Eureka 高可用
一、配置解析
1.1 通用配置
# 应用名称,将会显示在Eureka界面的应用名称列
spring.application.name=config-service
# 应用端口,Eureka服务端默认为:8761
server.port=3333
1.2 eureka.server前缀的配置项
# 是否允许开启自我保护模式,缺省:true
# 当Eureka服务器在短时间内丢失过多客户端时,自我保护模式可使服务端不再删除失去连接的客户端
eureka.server.enable-self-preservation = false
# Peer节点更新间隔,单位:毫秒
eureka.server.peer-eureka-nodes-update-interval-ms =
# Eureka服务器清理无效节点的时间间隔,单位:毫秒,缺省:60000,即60秒
eureka.server.eviction-interval-timer-in-ms = 60000
1.3 eureka.instance前缀的配置项
# 服务名,默认取 spring.application.name 配置值,如果没有则为 unknown
eureka.instance.appname = eureka-client
# 实例ID
eureka.instance.instance-id = eureka-client-instance1
# 应用实例主机名
eureka.instance.hostname = localhost
# 客户端在注册时使用自己的IP而不是主机名,缺省:false
eureka.instance.prefer-ip-address = false
# 应用实例IP
eureka.instance.ip-address = 127.0.0.1
# 服务失效时间,失效的服务将被剔除。单位:秒,默认:90
eureka.instance.lease-expiration-duration-in-seconds = 90
# 服务续约(心跳)频率,单位:秒,缺省30
eureka.instance.lease-renewal-interval-in-seconds = 30
# 状态页面的URL,相对路径,默认使用 HTTP 访问,如需使用 HTTPS则要使用绝对路径配置,缺省:/info
eureka.instance.status-page-url-path = /info
# 健康检查页面的URL,相对路径,默认使用 HTTP 访问,如需使用 HTTPS则要使用绝对路径配置,缺省:/health
eureka.instance.health-check-url-path = /health
1.4 eureka.client前缀
# Eureka服务器的地址,类型为HashMap,缺省的Key为 defaultZone;缺省的Value为 http://localhost:8761/eureka
# 如果服务注册中心为高可用集群时,多个注册中心地址以逗号分隔。
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
# 是否向注册中心注册自己,缺省:true
# 一般情况下,Eureka服务端是不需要再注册自己的
eureka.client.register-with-eureka = true
# 是否从Eureka获取注册信息,缺省:true
# 一般情况下,Eureka服务端是不需要的
eureka.client.fetch-registry = true
# 客户端拉取服务注册信息间隔,单位:秒,缺省:30
eureka.client.registry-fetch-interval-seconds = 30
# 是否启用客户端健康检查
eureka.client.health-check.enabled = true
#
eureka.client.eureka-service-url-poll-interval-seconds = 60
# 连接Eureka服务器的超时时间,单位:秒,缺省:5
eureka.client.eureka-server-connect-timeout-seconds = 5
# 从Eureka服务器读取信息的超时时间,单位:秒,缺省:8
eureka.client.eureka-server-read-timeout-seconds = 8
# 获取实例时是否只保留状态为 UP 的实例,缺省:true
eureka.client.filter-only-up-instances = true
# Eureka服务端连接空闲时的关闭时间,单位:秒,缺省:30
eureka.client.eureka-connection-idle-timeout-seconds = 30
# 从Eureka客户端到所有Eureka服务端的连接总数,缺省:200
eureka.client.eureka-server-total-connections = 200
# 从Eureka客户端到每个Eureka服务主机的连接总数,缺省:50
eureka.client.eureka-server-total-connections-per-host = 50
2. 配置项说明
Eureka中有一些配置项,通过查看网上的资料可以大概知道其含义,然而如果没有一个直观的指导,并不能清晰地认识他们实际的作用效果。下面通过截图对部分配置项加以解释说明。
2.1 spring.application.name和eureka.instance.appname
同时配置时,eureka.instance.appname
优先级更高。
如果没有配置eureka.instance.appname
,则使用spring.application.name
的值,如果连spring.application.name
都没有配置,则取unknown。
该配置项对应Eureka界面下图红框的内容:
2.2 eureka.instance.instance-id
配置项eureka.instance.instance-id
的值决定了下图右侧红框中的显示内容:
如果没有设置eureka.instance.instance-id
,那么显示的值将是一个由Eureka自动判断生成的编号:
2.3 eureka.instance.prefer-ip-address、eureka.instance.hostname、eureka.instance.ip-address
eureka.instance前缀的配置项中,这几个配置项绝对烧脑,根据周立的博客,在eureka.instance.prefer-ip-address = true
时,实例优先使用eureka.instance.ip-address
的值进行注册,如果没有配置eureka.instance.ip-address
,则使用第一个非回环IP地址进行注册。
此时,我们打开Eureka的界面,在实例上右键,复制链接地址;或将鼠标放在下图右上方的链接上(不点击),就可以获取实例的地址,如下图左下角,可见此时实例注册的是IP:
而当eureka.instance.prefer-ip-address = false
时,同样的方式可以查看实例注册地址采用了主机名eureka.instance.hostname
的值:
3. 配置Bean源码
最后,对应于本文出现的配置项,Eureka中定义的源码类如下。
#eureka.server前缀的配置项
org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean
#eureka.instance前缀的配置项
org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean
#eureka.client前缀的配置项
org.springframework.cloud.netflix.eureka.EurekaClientConfigBean
二、高可用注册中心搭建配置
#application.yml
spring:
profiles:
active: 8761
1. 注册中心peer1
spring: application: name: eureka cloud: client: ipAddress: 127.0.0.1 server: port: 8761 eureka: instance: appname: eureka #这里要跟‘spring.application.name’一致,还有‘prefer-ip-address’为false,同时开启自身注册,‘available-replicas’有效副本才不为空 instance-id: ${spring.cloud.client.ipAddress}:${server.port} prefer-ip-address: false lease-expiration-duration-in-seconds: 30 #续约到期时间(默认90秒) lease-renewal-interval-in-seconds: 10 #续约更新时间间隔(默认30秒),使得eureka及时剔除无效服务 hostname: peer1 client: serviceUrl: defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/,http://peer3:8763/eureka/ #在该默认配置下,注册中心也会将自己作为客户端尝试注册自己,因此要禁用客户端注册行为,高可用集群下相互注册需要为true register-with-eureka: true #是否注册到自身服务端,默认为true,高可用需要注册到本 fetch-registry: true #是否从服务器拉取注册信息,默认为true server: enable-self-preservation: false #关闭自我保护模式(缺省为打开) eviction-interval-timer-in-ms: 10000 #续期时间,清理无效服务的时间间隔,默认是60*1000
2. 注册中心peer2
spring: application: name: eureka cloud: client: ipAddress: 127.0.0.1 server: port: 8762 eureka: instance: appname: eureka #这里要跟‘spring.application.name’一致,还有‘prefer-ip-address’为false,同时开启自身注册,‘available-replicas’有效副本才不为空 instance-id: ${spring.cloud.client.ipAddress}:${server.port} prefer-ip-address: false lease-expiration-duration-in-seconds: 30 #续约到期时间(默认90秒) lease-renewal-interval-in-seconds: 10 #续约更新时间间隔(默认30秒),使得eureka及时剔除无效服务 hostname: peer2 client: serviceUrl: defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/,http://peer3:8763/eureka/ #在该默认配置下,注册中心也会将自己作为客户端尝试注册自己,因此要禁用客户端注册行为,高可用集群下相互注册需要为true register-with-eureka: true #是否注册到自身服务端,默认为true,高可用需要注册到本 fetch-registry: true #是否从服务器拉取注册信息,默认为true server: enable-self-preservation: false #关闭自我保护模式(缺省为打开) eviction-interval-timer-in-ms: 10000 #续期时间,清理无效服务的时间间隔,默认是60*1000
3. 注册中心peer3
spring: application: name: eureka cloud: client: ipAddress: 127.0.0.1 server: port: 8763 eureka: instance: appname: eureka #这里要跟‘spring.application.name’一致,还有‘prefer-ip-address’为false,同时开启自身注册,‘available-replicas’有效副本才不为空 instance-id: ${spring.cloud.client.ipAddress}:${server.port} prefer-ip-address: false lease-expiration-duration-in-seconds: 30 #续约到期时间(默认90秒) lease-renewal-interval-in-seconds: 10 #续约更新时间间隔(默认30秒),使得eureka及时剔除无效服务 hostname: peer3 client: serviceUrl: defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/,http://peer3:8763/eureka/ #在该默认配置下,注册中心也会将自己作为客户端尝试注册自己,因此要禁用客户端注册行为,高可用集群下相互注册需要为true register-with-eureka: true #是否注册到自身服务端,默认为true,高可用需要注册到本 fetch-registry: true #是否从服务器拉取注册信息,默认为true server: enable-self-preservation: false #关闭自我保护模式(缺省为打开) eviction-interval-timer-in-ms: 10000 #续期时间,清理无效服务的时间间隔,默认是60*1000
4. 启动注册中心
java -jar eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=8761 java -jar eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=8762 java -jar eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=8763
4. 注册中心访问效果
三、主流注册中心对比
CAP理论
CAP理论是分布式架构中重要理论
- 一致性(Consistency) (所有节点在同一时间具有相同的数据)
- 可用性(Availability) (保证每个请求不管成功或者失败都有响应)
- 分隔容忍(Partition tolerance) (系统中任意信息的丢失或失败不会影响系统的继续运作)
关于
P的理解,我觉得是在整个系统中某个部分,挂掉了,或者宕机了,并不影响整个系统的运作或者说使用,
而可用性是,某个系统的某个节点挂了,但是并不影响系统的接受或者发出请求,CAP 不可能都取,只能取其中2个
原因是
如果C是第一需求的话,那么会影响A的性能,因为要数据同步,不然请求结果会有差异,但是数据同步会消耗时间,期间可用性就会降低。
如果A是第一需求,那么只要有一个服务在,就能正常接受请求,但是对与返回结果变不能保证,原因是,在分布式部署的时候,数据一致的过程不可能想切线路那么快。
再如果,同事满足一致性和可用性,那么分区容错就很难保证了,也就是单点,也是分布式的基本核心,好了,明白这些理论,就可以在相应的场景选取服务注册与发现了
服务注册中心解决方案
设计或者选型一个服务注册中心,首先要考虑的就是服务注册与发现机制。纵观当下各种主流的服务注册中心解决方案,大致可归为三类:
-
应用内:直接集成到应用中,依赖于应用自身完成服务的注册与发现,最典型的是Netflix提供的Eureka
-
应用外:把应用当成黑盒,通过应用外的某种机制将服务注册到注册中心,最小化对应用的侵入性,比如Airbnb的SmartStack,HashiCorp的Consul
-
DNS:将服务注册为DNS的SRV记录,严格来说,是一种特殊的应用外注册方式,SkyDNS是其中的代表
注1:对于第一类注册方式,除了Eureka这种一站式解决方案,还可以基于ZooKeeper或者Etcd自行实现一套服务注册机制,这在大公司比较常见,但对于小公司而言显然性价比太低。
注2:由于DNS固有的缓存缺陷,本文不对第三类注册方式作深入探讨。
除了基本的服务注册与发现机制,从开发和运维角度,至少还要考虑如下五个方面:
-
测活:服务注册之后,如何对服务进行测活以保证服务的可用性?
-
负载均衡:当存在多个服务提供者时,如何均衡各个提供者的负载?
-
集成:在服务提供端或者调用端,如何集成注册中心?
-
运行时依赖:引入注册中心之后,对应用的运行时环境有何影响?
-
可用性:如何保证注册中心本身的可用性,特别是消除单点故障?
主流注册中心产品
软件产品特性并非一成不变,如果发现功能特性有变更,欢迎评论指正
Nacos | Eureka | Consul | CoreDNS | Zookeeper | |
---|---|---|---|---|---|
一致性协议 | CP+AP | AP | CP | — | CP |
健康检查 | TCP/HTTP/MYSQL/Client Beat | Client Beat | TCP/HTTP/gRPC/Cmd | — | Keep Alive |
负载均衡策略 | 权重/ metadata/Selector |
Ribbon | Fabio | RoundRobin | — |
雪崩保护 | 有 | 有 | 无 | 无 | 无 |
自动注销实例 | 支持 | 支持 | 支持 | 不支持 | 支持 |
访问协议 | HTTP/DNS | HTTP | HTTP/DNS | DNS | TCP |
监听支持 | 支持 | 支持 | 支持 | 不支持 | 支持 |
多数据中心 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
跨注册中心同步 | 支持 | 不支持 | 支持 | 不支持 | 不支持 |
SpringCloud集成 | 支持 | 支持 | 支持 | 不支持 | 支持 |
Dubbo集成 | 支持 | 不支持 | 支持 | 不支持 | 支持 |
K8S集成 | 支持 | 不支持 | 支持 | 支持 | 不支持 |
四、代码链接
工程源码链接:https://github.com/yqlArvin/eurekaServer.git