1.理解Eureka高可用集群
1.1.为什么要做Eureka集群
当微服务数量达到上百之数,一个EurekaServer所需要承担的压力会比较大,加上单节点故障问题可能会导致整个微服务不可被访问,由于EurekaServer在微服务中举足轻重,我们需要考虑对EurekaServer做高可用集群。
1.2.Eureka的弱一致性
分布式领域有个CAP理论,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。
- 一致性(Consistency):可以理解为分布式中存在多个数据副本,当其中某个数据副本发生数据更新需要实时同步到其他节点上。多个节点数据总是保持一致。例如:同一个数据同时存在于A服务器和B服务器,那么当A服务器的数据发生改变,B服务器的数据始终保持同步。
- 可用性(Availability): 客户端在任何时候访问集群,请求都可以正常返回结果,可以允许有一定的延迟。
- 分区容错性(Partition tolerance):能够容忍当服务之间通信发生故障,整个集群别分割为多个无法相互通信的分区的情况。即当集群因为网络故障被划分为多个分区,集群仍然可用。
因为网络不可控问题,分区容错总是存在的,所以系统必须具备分区容错性,即需要在AP和CP做选择。
Eureka的集群模式为对等复制,集群不分主从,任何Eureka节点都可以进行读写操作,节点之间相互同步数据。
Eureka选择了CAP理论中的AP,保证了可用性和分区容错,放弃了数据一致性。当Eureka自身发生故障,或集群发生分网络分区问题时(多个Eureka之间不可通信)需要保证服务可用,还能够正常的提供服务注册和发现功能,那么EurakServer就必须选择可用性,放弃一致性,所以多个Eureka集群节点间的数据并不是强一致性的(多个EurekaServer之间数据不会实时同步,但是最终可能会同步数据)。
Eureka的设计思想是保留过期但可用的数据也比丢失掉可用的数据强。客户端很有可能拿到一些过期的服务实例数据导致服务不可访问,这就需要客户端能够支持负载均衡和请求重试机制,而Ribbon提供了这一功能。
2.EurekaServer集群实战
2.1.EurekaServer集群方案
准备三个EurekaServer 相互注册,也就是说每个EurekaServer都需要向所有的EureakServer注册,包括自己 ,每个EurekaServer即充当了服务端,也充当了客户端。咱们的其他微服务(order,user)只需要把注册地址指向所有的EurekaServer就可以了。
2.2.搭建EurekaServer集群
1.创建两个本地域名
修改主机文件: C:\Windows\System32\drivers\etc\hosts 模拟三台主机,内容如下:
127.0.0.1 peer1 127.0.0.1 peer2 127.0.0.1 peer3
2.eureka-server集群
修改注册中心eureka-server-1010实现高可用配置,注意配置规则:
- 采用SpringBoot单配置文件多环境配置
- 因为三个EurekaServer要相互注册 ,那么三个EurekaServer的 serviceUrl都是一样的,我们就把serviceUrl抽取到最上面,其中包括 使用ip地址注册 (prefer-ip-address),EureakServer自我保护机制(enable-self-preservation) ,以及服务名(application.name)都是相同点的,都可以抽到最上面。
- 每个EurekaServer不一样的配置:端口(port) ,环境名字(profiles),主机名(hostname),实例id(instance-id:) , 具体配置如下:
eureka client serviceUrl defaultZone http //peer1 1010/eureka/,http //peer2 1011/eureka/,http //peer3 1012/eureka/ instance prefer-ip-addresstrue server enable-self-preservation false #关闭自我保护警告ospring profiles active peer1 application name eureka-peer ---#peer1第一个Eurekaspring profiles peer1 server port 1010 #端口eureka instance hostname peer1 #主机 instance-id eureka-peer11010---#peer2第二个Eurekaspring profiles peer2 server port 1011 #端口eureka instance hostname peer2 #主机 instance-id eureka-peer21011---#peer3第三个Eurekaspring profiles peer3 server port 1012 #端口eureka instance hostname peer3 #主机 instance-id eureka-peer31012
这里做了三个Eureak Server配置,端口分别是:1010,1011,1012。
2.3.启动EurekaServer集群
1.需要指定IDEA的多实例启动配置
2.启动EurekaServer集群
启动三次EurekaServerApplication1010,每次启动的时候需要修改spring.profiles.active的值激活不同的环境
#...省略....pring profiles active peer1 #这里启动一次需要修改一次 ,每次启动使用不同的环境配置
3.测试集群
分别访问http://localhost:1010 ;http://localhost:1011;http://localhost:1012 ,在三个Eureak Server的监控界面都呈现如下效果:
3.Eureka Client注册到Eureka Server集群
3.1.修改user-server和order-server
用户和订单的微服务的配置中,注册中心地址修改为所有的EurekaServer注册地址即可,修改springcloud-user-server-1020和springcloud-order-server-1030的注册地址如下
eureka client serviceUrl defaultZone http //peer1 1010/eureka/,http //peer2 1011/eureka/,http //peer3 1012/eureka/ #注册中心地址 ...
3.2.测试集群
分别启动三个Eureka Server注册中心服务 ,启动用户和订单服务,
分别访问:http://localhost:1010 ;http://localhost:1011;http://localhost:1012 ,
可以看到订单服务和用户服务在三个Eurea Server监控界面都可以看到,如图:
4.Eureka参数调优
4.1.Eureka Server为什么会保留下线的服务数据
在开发阶段我们会频繁的重启服务,在Eureak Server可能会出现这样的情况,就是一些服务明明已经下线了但是我们可能还是会在注册列表看到它,这可能是因为下面几个原因导致:
自我保护机制导致
微服务已经下线,但是Eureka Server依然会残留已经下线的服务数据,原因之一可能是因为开启了自我保护机制,为了防止服务被误删除Eureka不会立即删除过时的服务数据,但是这样的机制可能会导致客户端从注册中心获取到已经下线的服务发起调用,很显然调用会失败,这时需要客户端可以通过重试机制减少出错的可能性。
开发阶段可以过eureka.server.enable-self-preservation=false
关闭自我保护机制 ,在生产环境中建议打开该配置,因为Eureka自我保护是为了防止因为网络波动服务未及时续约而服务本身健康所造成的服务误剔除问题,如果大量的服务被误剔除会造成没有服务可用。同时可以通过调整如下两个参数提高自我保护机制的出发频率:
eureka.server.renewal-percent-threshold=0.85
: 每分钟需要收到的续约次数默认0.85eureka.server.leaseRenewalIntervalInseconds=10
:续约频率,默认30s
客户端未正常下线导致
当然除了上面原因也有可能是因为Eureka Client客户端意外宕机没及时通知Eureka Server导致,该种情况可以通过 eureka.server.eviction-interval-timer-in-ms=5000
来指定Eureka Server定时清除过期数据的频率(默认是60/s),尽量早的清楚掉过时的数据。
Eureaka Server缓存导致
Eureka Server缓存可能会导致服务信息残留问题,可以通过 eureka.server.use-read-only-response-cache=false
关闭缓存
4.2.Eureka Server剔除服务时间设置
eureka server在收到eureka client的心跳续约请求之后,默认会等90s如果没有收到第二次续约请求就会把服务从服务注册列表剔除掉,可以通过 eureka.instance.lease-expiration-duration-in-seconds=90
修改服务该时间。
4.3.Eureka Client获取服务慢
Eureka Client默认从Eureka Server获取服务注册列表的间隔时间为 30/s,在开发阶段我们可以适当调整该参数让客户端可以更快的发现服务,如:eureka.client.registry-fetch-interval-seconds=10
将定时获取服务注册列表时间调整为 10s一次。
4.4.Eureka Client服务续约频率
Eureka Client默认每个30s发送一个心跳请求到Eureka Server进行服务续约,表明它仍然活着,默认为30 秒,如果达到3次续约失败(leaseExpirationDurationInSeconds默认90s),Eurea Server将会把续约失败的服务剔除掉,可以通过 eureka.instance.lease-renewal-interval-in-seconds=10s
来修改心跳频率时间。
5.Eureka设置账号认证
5.1.为什么要设置账号认证
在之前的案例中,我们可以直接通过浏览器访问Eureka的控制台界面看到注册的服务列表,这是一个很危险的操作,在生产环境中我们需要有相关的认证机制,即需要通过输入用户名和密码认证后才能访问Eureak的控制台界面
5.2.EurekaServer服务端设置认证账号
我们需要改造 springcloud-eureka-server-1010,添加安全依赖security
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
导入该依赖后,我们需要添加一个security的配置,这个配置目的是忽略跨域伪造请求检查,因为EurekaServer集成了Security后,默认是要求向EureakServer发起的请求中带有CSRF令牌,而EurekaClient的请求不可能有这个令牌,所以我们要禁用该行为,增加如下配置代码
importorg.springframework.context.annotation.Configuration; importorg.springframework.security.config.annotation.web.builders.HttpSecurity; importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity; importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; classWebSecurityConfigextendsWebSecurityConfigurerAdapter { protectedvoidconfigure(HttpSecurityhttp) throwsException { //忽略伪造跨站检查http.csrf().ignoringAntMatchers("/eureka/**"); super.configure(http); } }
接着我们需要在yml中配置账号和密码, 同时需要修改注册中心的注册地址,也需要加上账号和密码,如下配置即可:
spring security user name user #账号,自己定义 password admin #密码,自己定义eureka client#客户端配置 serviceUrl#注册中心的注册地址 defaultZone http //user admin@localhost 1010/eureka/
注意:serviceUrl.defaultZone的注册地址要修改,格式:http://账号:密码@主机:端口/eureka/
然后我们启动EurekaServer,访问http://localhost:1010,使用密码进行登录即可:
5.3EureakClient客户端注册地址设置认证账号
由于服务端设置了账号和密码,所以Eureak 客户端在向服务端注册的时候需要修改URL设置账号和密码,这里我修改了springcloud-order-server的配置如下:
eureka client serviceUrl#这里和服务端的地址写法一样 defaultZone http //user admin@localhost 1010/eureka/
启动order服务之后,该服务就会自动的注入到EureakServer
5.4.Eureka集群下的账号配置
其实集群的认证账号配置和不做集群的配置是一样的,我这里配置了2个Eureka的集群如下:
spring security user name user password admin profiles active eureka1 application name eureka-server eureka client#客户端配置 serviceUrl#多个注册中心的注册地址,让他们互相注册,注意加上账号 defaultZone http //user admin@peer1 1010/eureka/,http //user admin@peer2 1011/eureka/ instance prefer-ip-addresstrue---server port 1010 #端口eureka instance hostname peer1 #主机 instance-id eureka-server1010 profiles eureka1 ---server port 1011 #端口eureka instance hostname peer2 #主机 instance-id eureka-server1011 profiles eureka2
可以看到,这里的账号和密码在最上面配置的,意思是多个Eureak的账号和密码是一样的,Eureka在互相注册的时候,地址也是需要加上账号和密码的
那么Eureaka客户端指向Eureka服务端的注册地址需要跟上多个地址,并且需要指定账号,如下
#注册到EurekaServereureka client serviceUrl#多个注册中心,主要要指定账号 defaultZone http //user admin@peer1 1010/eureka/,http //user admin@peer2 1011/eureka/
最终Eureka控制台界面效果如下: