横云断岭 2020-01-19
??回忆一下,在上一篇文章中,我们创建了两个springboot项目,并且在consumer项目中通过restTemplate进行HTTP通信,成功访问到了producer提供的接口,思考一下这样的实现方式有什么问题?
??1.consumer必须知道producer的IP,才能调用对方的HTTP接口,并且在consumer代码中使用硬编码的方式来访问producer的HTTP接口,代码耦合度高,实现方式不优雅.也许有童鞋会说,我们可以在application.properties配置文件进行配置,那么请看第二个问题.
??2.一般来说,生产环境的producer是一个集群,有多个IP,那我consumer该怎么写请求地址?并且假如producer集群的IP变了,consumer应用需要修改配置,重新打包上线.这对于一个高并发访问的生产项目来说是不可接受的.因此,consumer应用需要一种机制,可以在访问producer的时候不需要关心producer的IP,并且该机制还应该提供类似于观察者模式的通知机制,在producer的IP进行变更的时候,及时通consumer,并且还能提供类似Nginx的负载均衡的功能,这就是eureka注册中心的作用.
??eureka是netflix公司开发的一款用于服务发现的框架,spring-cloud将其集成到spring-cloud-netflix子项目中,包括我们后续会使用的负载均衡ribbon,服务熔断与降级Hystrix等等都是netflix公司开发的.可以看出,springcloud其实整合了许多优秀公司的框架.
??我们通过一张图来说明一下eureka工作机制:
??假如我们现在有许多的微服务作为服务提供方,每个微服务是一个集群,他们将自己的集群节点的IP与端口号注册到eureka中心,当有消费者需要消费服务的时候,即可从注册中心拉取所有的服务提供方列表,选择需要消费的服务,此时,eureka会根据负载算法将消费者需要的服务的IP与端口号返回给消费者,此时,消费者就可以根据IP和端口号去消费对应的服务了.此外,eureka还必须接收注册服务的心跳,确保注册的服务可用.并且从图中我们可以得知:
??接下来,我们改造上一篇文章中已有的代码,使用eureka进行服务治理,producer注册自身到eureka,consumer从eureka获取producer的信息并调用.
??首先,我们要新建一个子模块,用于充当eureka-server的角色:
??将本模块加入父项目中:
??然后新增pom.xml中的配置:
??修改配置文件:
??然后在启动类加上@EnableEurekaServer:
??然后启动试一试,此时控制台会有错误信息:
??我们暂时先不管这些错误信息,先访问一下,看看是否能访问:
??可以看到,eureka是能正常访问的,接下来,我们修改producer的代码,将producer注册到eureka-server中.
首先修改pom.xml:
??然后修改配置文件:
??最后在启动类加上@EnableEurekaClient:
??此时,我们再启动producer项目,然后访问eureka-server,看看是否producer已经注册成功:
??此时我们再访问该页面,我们需要关注的主要是笔者使用红框标识的3条信息,其中第一条我们暂时先不管(第一次访问页面不会出现,但过一会儿刷新就可以看到),待会儿我们再倒回来说,第二条,表示我们的producer应用已经注册到eureka-server,但应用名未设置,所以目
前显示的是UNKNOWN,因此需要我们设置应用名.第三条状态为UP(1),表示该服务正常启动,且地址是: DongHP:7001,点击访问试一试:
??可以看到,访问的域名是donghp(我的电脑名是DongHP):7001,后面跟的是actuator/info,并且页面报错,报错信息提示我们没有该页面(404),因此我们需要添加spring-actuator,该模块是spring进行健康检查的模块,我们先分别解决第二和第三个问题:先修改配置文件,新增应用名:dhp-micro-service-producer
??接下来为了让我们看到真实的IP地址,而不是 donghp:7001 ,我们再加上显示真实IP的配置:
??最后,再添加spring-actuator健康检查的依赖:
??再重启producer,并刷新eureka-server页面:
??可以看到,修改后的producer已经成功注册到eureka-server中了,但是我们会发现,之前注册的服务还在,并没有消失,这是什么原因呢?是缓存吗?并不是,我们可以试一试,过一会儿再刷新,仍然还是有,这并不是缓存,还记得我们之前所说的第一条:
提示信息吗?这是eureka提示我们触发了eureka的自我保护机制.
??所谓eureka自我保护机制,就是当服务未按时进行心跳续约时(之前我们在介绍eureka的时候说了,服务如果注册到eureka后,会定时向eureka发送心跳),Eureka会统计服务实例最近15分钟心跳续约的比例是否低于了85%(eureka.server.renewal-percent-threshold默认情况下=0.85)。当server在15分钟内,比值低于percent,即少了15%的微服务心跳,server会进入自我保护状态,Self-Preservation。在此状态下,server不会删除任何注册信息,这就有可能导致在调用微服务时,实际上服务并不存在。由此我们可以分析出eureka自我保护机制的缺点:有可能保留确实已经不可用的微服务,但是相比之下,它的优点是能最大化保存所有的微服务,因为在生产环境下,网络问题导致的心跳丢失太常见了,我们不能简单以是否收到心跳来判断一个微服务是否不可用,因此建议生产环境开启自我保护机制,开发时的测试环境可以关闭.
??因此上图中出现的问题就能够解释了,首先我们已经关闭了之前的UNKNOWN的微服务,重新修改配置启动了新的DHP-MICRO-SERVICE-PRODUCER,此时eureka服务器并没有重启,UNKNOWN的微服务不再向eureka发送心跳(默认30秒发送一次心跳),因此eureka的心跳比例只有50%,低于85%,页面弹出eureka触发自我保护机制的提示,并且eureka进入自我保护状态,不会删除任何微服务.因此不管我们如何刷新页面,UNKNOWN的微服务始终都在,如果需要禁用eureka的自我保护状态,可以使用配置:eureka.server.enable-self-preservation=false(默认是开启的).
??此时先启动eureka-server,再还原producer的配置启动,再修改producer的配置启动:
??上图中①提示我们目前关闭了自我保护模式,②说明目前有两个已注册的微服务,但是UNKNOWN已经下线了,因此我们过一分钟刷新:
??此时就只有一个了,我们再访问一下:
??得出两个信息:
1.我们的ip是192.168.1.105,去验证一下:
2.我们没有配置健康检查的信息,因此我们在producer中配置相关信息:
??到此,我们的eureka-server已经成功启动,并且producer也注册到eureka了,一切看似很完美了,但大家是否记得之前我们说eureka-server启动的时候会报错的问题呢?
??这是因为eureka-server配置还不完整,我们还需要添加配置:
??然后再启动eureka-server和producer:
??可以看到,producer服务已经成功注册到eureka中了,并且eureka-server也没有报错信息了.
??此时我们再通过consumer项目验证一下.修改consumer项目代码:
??首先consumer也需要添加eureka-client的依赖:
??其次配置eureka相关信息:
??然后在启动类加上注解:
??最后修改代码:
??可以发现,这里以前是直接使用ip:port,现在通过eureka发现服务,就对应于我们之前所说的不再关心对方服务的ip和端口,并且对方服务地址变化也不会再对我们的代码造成任何影响了,代码的优雅性和可维护性大大提升!
??由于这种方式走eureka服务发现,因此还需要加上@LoadBalanced注解:
??最后测试一下:
??访问成功!自此,我们成功使用了eureka注册中心来解决文章一开始抛出的两个问题,那是不是这样就完美了?是否还有值得继续优化的地方?敬请期待下一篇文章.
本文由博客一文多发平台 OpenWrite 发布!