写点什么

InfoQ 极客传媒 15 周年庆征文| 迁移 Eureka 到 Nacos 之双注册双订阅模式

作者:4ye
  • 2022 年 6 月 09 日
  • 本文字数:3554 字

    阅读完需:约 12 分钟

InfoQ 极客传媒 15 周年庆征文| 迁移 Eureka 到 Nacos 之双注册双订阅模式

小伙伴们好呀,今天来填一下这个坑🕳 —— 将注册中心从 Eureka 迁移到 Nacos 🐷


这里面涉及到这个 双注册双订阅模式 ,下面让我们一起看看叭~ 😄


首先,为啥要迁移呢?🐖

主要是它对比其他注册中心,已经落后太多了🐖


  1. 就拿 Nacos 来说吧,不仅有 配置中心,管理界面,还能手动上下线,而且支持服务列表变更的消息推送模式(实时性高)

  2. Eureka 1.x 的架构有些地方可以改进,比如 在客户端的 pull 模式下,增加这个消息推送模式,增加实时性;还有 集群,Eureka 只支持 AP ,各个客户端都能进行写请求✍ , 没有主从节点之分,各个节点之间通过相互复制来同步数据,无法保证一致性。Nacos 则有 AP 和 CP 两种选择,更灵活。

  3. 2019 年的某个会上,Spring 团队提出如何解决 Netflix 进入维护模式后的 SpringCLoud 组件选择问题。

  4. 就是 Eureka 早已进入维护模式啦!而且 long long ago ,官方就放弃了这个 Eureka2.X 版本的开发(看了下分支,6,7 年前的代码了),而且官方还说了不能用在生产上,后果自负😱(额 咱也不知道它有啥新特点,反正 SpringCloud 一直用的 1.x 版本。现在更新到 1.10 了🙃)




简单了解了这个背景后,咱们再来看看 4ye 搭建的这个 demo 🐷

Eureka 注册中心

比如 老项目中,使用的注册中心是 Eureka 。架构如下



代码也很简单,有三个模块。分别是


  1. 注册中心 : 搭建时选择 Eureka Server 即可。

  2. 服务提供者(provider): 搭建时选择 Eureka Discovery Client 和 **Spring Web **即可。

  3. 服务消费者(consumer):搭建时选择 Eureka Discovery Client 和 **Spring Web **即可。



然后依次启动注册中心,provider,consumer 即可。



访问 http://localhost:8772/hello/Java4ye 可以看到下面的内容。


双注册双订阅模式

接着,我们克隆上面的 provider 和 consumer 模块。


在 pom 文件中直接加入 Nacos 和 Eureka 。



启动时会抛出下面的异常信息 。(引入 Actuator 时会出现另一个,同样排除掉即可)


Description:
Field autoServiceRegistration in org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration required a single bean, but 2 were found: - nacosAutoServiceRegistration: defined by method 'nacosAutoServiceRegistration' in class path resource [com/alibaba/cloud/nacos/registry/NacosServiceRegistryAutoConfiguration.class] - eurekaAutoServiceRegistration: defined by method 'eurekaAutoServiceRegistration' in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.class]
复制代码


可以看到是自动装配时,不知道用哪个导致的异常。但是我们两个都要😝


这里只要在 application.properties 中把这个自动装配移除掉即可。


# 双注册模式下关闭spring.autoconfigure.exclude=org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration,org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration
复制代码


当然,秉着严谨的态度,我们在这两个类中打入相应的断点,可以看到他们都被创建了。



同时,也成功注册到这两个注册中心去了😄




这个时候,再次访问旧的客户端 8772 端口的,可以发现如下效果。



但是要注意,此时项目的架构变成这样,consumer 中只有 Eureka 的客户端,所以调用到的都是 Eureka 中心中的服务此时流量不会走到 Nacos 这边



接着便是看客户端 consumer 正不正常,比如跑个一天看看。


稳定后,下一步就是 下线这个 provider ,然后看看正不正常了。同样稳定后,便是准备启动这个 双订阅的客户端了。

小实验

但是我这里做了一个小实验 哈哈 想看看不下线的情况,我这个 新客户端 上线后是使用哪个注册中心的服务多点。


所以,接着,我们就启动这个新的 consumer,一个双订阅的客户端。🐷


同样修改下配置文件即可。


spring.cloud.nacos.discovery.username=nacosspring.cloud.nacos.discovery.password=nacos# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口spring.cloud.nacos.discovery.server-addr=192.168.175.128:8848# 注册到 nacos 的指定 namespace,默认为 publicspring.cloud.nacos.discovery.namespace=public
# 双注册模式下关闭spring.autoconfigure.exclude=org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration,org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration
复制代码


这个时候,我们访问新的客户端。8872 端口的: http://localhost:8872/hello/Java4ye


发现无论怎么刷新,接口的返回值都是下面这个,无法达到负载均衡的效果 。(⊙o⊙)?



简单翻看了下源码,可以发现系统创建了三个 discoveryClient ,最后一个是兜底用的。


而且 nacos 排在第一个,这意味着从 nacos 的注册中心中找到服务的话,就不会调用到 Eureka 中的了。



了解了这个原理后,将 nacos 中的服务进行下线。


然后去刷新新的客户端,8872 端口的,可以发现,又出现了负载均衡的效果了。



而且得益于 Nacos 的服务列表变更推送机制,我们客户端可以实时感知到 服务列表的 变化,这个时候直接去刷新新客户端的接口,可以发现它已经切换到 Eureka 中了,没有延迟感!


所以当我们在迁移的过程中,如果发现 Nacso 上新的 provider 有什么异常时,可以将其下线先🐷 轻轻一点真的太方便了


优雅下线

结束上面的小实验,回到正常流程中,我们要来下线这个 provider 了。



这里就得考虑这个 优雅下线 的问题了。


网上的方案很多,这里用 Springboot 的 actuator 来实现。



这个 graceful 配置是 Springboot2.3 之后才有的,会让内嵌服务器拒绝外部请求,然后处理完已经在内部的请求后,进入关闭状态。


通过这个暴露的 api,去修改 eureka 中 service 的状态。


# 优雅下线server.shutdown=graceful# 关闭超时spring.lifecycle.timeout-per-shutdown-phase=20s
#management.endpoints.web.exposure.include= service-registry
复制代码


这里直接访问 curl "localhost:8771/actuator" 来获取我们注册的这个 API (可以看到我们 - 符号被吃掉了 坑🕳)



接着,我们通过这串请求,改变 Eureka 中服务的状态: DOWN


curl -X "POST" "http://localhost:8771/actuator/serviceregistry?status=down" -H "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8"
复制代码



然后,在等待若干时间后,应该是客户端 consumer 重新去拉取服务列表信息后。(哈哈 我没数)😝



不过我配了 10s ,然后我们不断刷新请求,会发现这个负载均衡的效果已经消失了。只剩新的 provider 提供的服务了🐖


然后在服务稳定一段时间后,可以通过 Prometheus 来观察这个旧的 provider 的 qps 等,当它已经没有啥流量进入了,便可以直接关闭下线了。( kill -9)

上线双订阅客户端

接着,上线这个 新的 consumer ,这里也没啥特别的了。


同样等系统稳定后,下线这个旧的客户端 consumer 了。🐖



而且从上面小实验环节中,我们可以知道流量会先来到这个 Nacos 中,确认里面没有这个服务的话,才去这个 Eureka 中查找。所以到这里,这个 Eureka 中的流量就会少了大部分了。

再次上线

到了这里,我们还不能直接关闭这个 Eureka,还得再次上线新版本的只有 Nacos 注册中心的 provider 和 consumer 🐷


这次的新版要注意这个负载均衡,我们去掉了 Netflix 后,得手动引入 SpringCloud 的 loadbalancer 组件。其他也就删删配置了。



同样的,稳定后,才去下线双订阅客户端 consumer,再下线双注册服务端 Provider,最后才下线这个 Eureka。 🐷


这里通过 Nginx 等去控制流量,将他们打到新的只订阅 Nacos 的 consumer 上,最后等双订阅的 consumer 客户端没啥流量就给它下线了。


接着,在 Nacos 上 ,下线那个双注册的服务,然后再去下线它。


最后就直接关闭 Eureka 了。


这样就完成了这个注册中心的迁移了🐖


整体流程

这里其实就是上线新版本后,等其稳定,下线旧版本的一个规则。🐖



关于应用的发布,这里就不多赘述了🐖,网上大把的 蓝绿发布,灰度发布,还有 K8s 的 pod 容器,docker 等环境下的决策。

最后

https://github.com/Java4ye/springcloud-alibaba-demo-4ye


整个 demo 我也弄到 GitHub 上啦,新开的坑🕳 哈哈,后面也会逐步完善的😝


觉得不错的话,可以 Star 支持一波哦😝


总结

通过本案例,可以快速了解到这个迁移过程中:


  1. 这个代码基本都没改!这得益于这个 SpringCloud 的统一服务注册和发现的编程模型

  2. 使用双注册双订阅模型时,要排除掉自动装配的坑🕳,而且在这个模式下,流量基本都跑到 Nacos 这边。

  3. 对比下两个注册中心,更能感觉到 Nacos 这么多便利的功能:上下线和服务列表变化的推送机制。

  4. 了解到 Springboot 在优雅下线这一块做的变化,谨记不要轻易 kill -9!



发布于: 2022 年 06 月 09 日阅读数: 39
用户头像

4ye

关注

公众号:J a v a 4 y e 2021.07.19 加入

定个小目标,写个三年~ 分享一个普通程序员的技术生涯,生活点滴,让学习成为一种习惯!

评论

发布
暂无评论
InfoQ 极客传媒 15 周年庆征文| 迁移 Eureka 到 Nacos 之双注册双订阅模式_架构_4ye_InfoQ写作社区