当前位置:   article > 正文

Eureka,Config到Nacos的无痛迁移_eureka迁移到nacos

eureka迁移到nacos

一.  概述

 

最近公司在做组件的技术升级,需要将原有注册中心 Eureka,配置中心 Spring Cloud Config 替换为 Nacos,主要原因如下:

1. Spring Cloud Netflix Eureka项目宣布闭源

Spring Cloud的这一重要宣布,意味着,随着技术的发展,最终使用Eureka的用户都会面临注册中心迁移的问题

2. Nacos更强

<1> 在服务注册上,Nacos 几乎实现了 Eureka 所支持的所有特性;

<2> 在配置管理上,Nacos 具备 Config 所支持的所有功能;

<3> Nacos 提供了控制台UI,便于更方便地进行服务管理,配置管理;

可以理解为,Nacos = Spring Cloud Eureka + Spring Cloud Config,但是其功能更强大。

因此,本文将探讨:如何以 "零代码" 的方式,将使用 Eureka,Config 的应用迁移到 Nacos 上。

二. Nacos简介及主要特性展示

       Nacos 通过提供简单易用的动态服务发现、服务配置、服务共享与管理等服务基础设施,帮助用户在云原生时代,在私有云、混合云或者公有云等所有云环境中,更好的构建、交付、管理自己的微服务平台,更快的复用和组合业务服务,更快的交付商业创新的价值,从而为用户赢得市场。下面是Nacos的总览图:

一句话总结就是,Nacos提供了服务管理,配置管理,多环境管理,后续还会支持权限管理等模块。关于Nacos的详细功能请参考官网。

三. 实施过程

1. 前期准备

<1> 梳理待迁移的服务列表

目前所有的微服务都需要进行迁移,整理服务清单(便于后期追溯,避免改漏);

<2> 确定组件所使用的版本

版本依赖选型,需要参考官方Wiki:

版本说明 · alibaba/spring-cloud-alibaba Wiki · GitHub

另外,Hibernate-Validator版本低于5.X.X时,Nacos-Client报错;

最终,确定的版本情况如下:

2. Nacos 部署

完成了前期准备,下一步便是Nacos的部署。这里采用集群部署的方式,保证Nacos集群高可用。

部署方式采用官方推荐的方式。物理架构如下图所示:

其中,Nacos节点为无状态节点。因此,只通过域名指定轮询访问其中一台即可保证高可用。

<1> Nacos安装

本次使用的Nacos版本为1.1.4,需要三台机器,每台机器都执行同样的安装操作;

1~ 初始化数据库

初始化SQL脚本为 nacos-mysql.sql,文件位于nacos/conf目录下。初始化的表共有11个,如下图所示:

2~ Nacos下载

下载地址:Release 1.1.4(Oct 24th, 2019) · alibaba/nacos · GitHub

3~ Nacos安装与配置

解压 nacos-server-1.1.4.tar.gz。

修改application.properties,文件位于nacos/conf目录下,修改文件中的数据库配置。

  1. spring.datasource.platform=mysql
  2. db.num=1
  3. db.url.0=jdbc:mysql://10.0.17.21:3306/registry?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
  4. db.user=root
  5. db.password=123456

修改cluster.conf,文件位于nacos/conf目录下,配置集群节点的信息(IP端口形式)。

  1. #it is ip
  2. #example
  3. 10.0.112.64:8848
  4. 10.0.112.65:8848
  5. 10.0.112.66:8848

4~ 启动

进入nacos/bin目录下,通过 sh startup.sh 启动 nacos 即可。

<2> Nginx配置

       因为状态都保存在数据库,因此Nacos是无状态节点,配置Nginx时,只通过域名指定轮询访问其中一台即可保证高可用,配置如下所示:

  1. upstream nacos{
  2. server 10.0.112.64:8848;
  3. server 10.0.112.65:8848;
  4. server 10.0.112.66:8848;
  5. }
  6. server {
  7. listen 8848;
  8. server_name 10.0.17.115;
  9. location / {
  10. proxy_pass http://nacos;
  11. proxy_set_header Host $http_host;
  12. }
  13. }

<3> 验证

通过域名(或者IP端口)的方式访问,出现如下界面,证明部署成功。

3. 配置多环境隔离

Nacos通过命名空间的形式,实现了环境的逻辑隔离。通过不同的命名空间,隔离了不同环境。

登录Nacos控制台,新增命名空间即可。例如需要开发环境和生产环境,则新增 dev,pro 两个命名空间即可。

4. 服务注册与发现

<1> 引入依赖

建议通过父pom的方式引入,避免parent的方式。依赖如下:

  1. <!-- mvn依赖管理 -->
  2. <dependencyManagement>
  3. <dependencies>
  4. <!-- spring boot -->
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>${spring-boot.version}</version>
  9. <type>pom</type>
  10. <scope>import</scope>
  11. </dependency>
  12. <!-- spring cloud -->
  13. <dependency>
  14. <groupId>org.springframework.cloud</groupId>
  15. <artifactId>spring-cloud-dependencies</artifactId>
  16. <version>${spring-cloud.version}</version>
  17. <type>pom</type>
  18. <scope>import</scope>
  19. </dependency>
  20. <!-- spring cloud alibaba dependencies -->
  21. <dependency>
  22. <groupId>com.alibaba.cloud</groupId>
  23. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  24. <version>${alibaba-spring-cloud.version}</version>
  25. <type>pom</type>
  26. <scope>import</scope>
  27. </dependency>
  28. </dependencies>
  29. </dependencyManagement>

在子项目中直接引入即可:

  1. <!-- nacos discovery -->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  5. </dependency>

同时去掉Eureka的依赖:spring-cloud-starter-netflix-eureka-client

<2> 配置替换

只需要在配置中去掉Eureka的配置,改为Nacos的配置即可。

spring.cloud.nacos.discovery.server-addr=10.0.17.115:8848

<3> 加上注解

在启动类上加上 @EnableDiscoveryClient 即可。

这样子,就完成了服务注册与发现的改造。

5. 服务配置管理

<1> 引入依赖

在前面的基础上,直接引入下面依赖即可:

  1. <!-- nacos config -->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  5. </dependency>

同时去掉 Config 的依赖。

<2> 配置替换

同服务注册与发现,只需要在配置中去掉Config的配置,改为Nacos的配置即可。

spring.cloud.nacos.config.server-addr=10.0.17.115:8848

这样子,服务就加入了Nacos配置中心

四. 存在的问题

在实施的过程中,我们也遇到了一些问题:

1. 多环境管理的做法

我们既然在Nacos配置了多环境隔离,那么服务自然也支持多环境隔离,因此我们的做法是:

首先,我们配置了多个配置文件,如下所示:

boostrap.yml 为公用配置,boostrap-xx.yml 作为不同环境的区分,boostrap-xx.yml 内容如下:

  1. spring:
  2. cloud:
  3. nacos:
  4. discovery:
  5. namespace: 0ec603e3-261f-4705-8530-60093f0c8309
  6. config:
  7. namespace: 0ec603e3-261f-4705-8530-60093f0c8309

可以看到,通过namespace区分不同的环境。最终应用启动时,通过 spring.profiles.active 指定环境即可。

2. 配置的实时生效

Nacos支持客户端配置的自动更新,因此,这里提供三种方法实现配置的自动更新(任一种均可):

<1> 通过@Configuration注解指定的配置类, 且在类上加上@RefreshScope

<2> 通过@Value注解注入的属性,且在类上加上@RefreshScope

<3> 通过ConfigurableApplicationContext

  1. @Autowired
  2. private ConfigurableApplicationContext applicationContext;
  3. applicationContext.getEnvironment().getProperty("user.name")

这样,我们在修改配置的同时,配置也会实时在各个客户端生效。

3. Nacos权重配置不生效,且服务无法秒级下线

       经过测试发现,Nacos的权限配置不生效。经过查阅资料,最终通过自定义负载均衡器解决,它是一个基于权重的自定义Nacos负载均衡器,并将Ribbon使用的负载均衡策略由轮询改为它。实现过程如下:

  1. import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
  2. import com.alibaba.cloud.nacos.ribbon.NacosServer;
  3. import com.alibaba.nacos.api.exception.NacosException;
  4. import com.alibaba.nacos.api.naming.pojo.Instance;
  5. import com.netflix.client.config.IClientConfig;
  6. import com.netflix.loadbalancer.AbstractLoadBalancerRule;
  7. import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
  8. import com.netflix.loadbalancer.Server;
  9. import lombok.extern.slf4j.Slf4j;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. /**
  12. * 基于权重的自定义负载均衡器
  13. * @author zz
  14. * @date 2019/12/5 13:55
  15. **/
  16. @Slf4j
  17. public class NacosWeightLoadBalancerRule extends AbstractLoadBalancerRule {
  18. @Override
  19. public Server choose(Object o) {
  20. DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
  21. String name = loadBalancer.getName();
  22. try {
  23. Instance instance = discoveryProperties.namingServiceInstance().selectOneHealthyInstance(name);
  24. log.info("select instance:{}", instance);
  25. return new NacosServer(instance);
  26. } catch (NacosException ee) {
  27. log.error("select instance error! message:", ee);
  28. } catch (Exception e) {
  29. log.error("select instance error! message:", e);
  30. }
  31. return null;
  32. }
  33. @Override
  34. public void initWithNiwsConfig(IClientConfig iClientConfig) {
  35. }
  36. @Autowired
  37. private NacosDiscoveryProperties discoveryProperties;
  1. import com.netflix.loadbalancer.IRule;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. /**
  5. * Ribbon配置
  6. * @author zz
  7. * @date 2019/12/5 14:14
  8. **/
  9. @Configuration
  10. public class RibbonConfig {
  11. @Bean
  12. public IRule getRibbonRule() {
  13. return new NacosWeightLoadBalancerRule();
  14. }
  15. }

这样,在Nacos进行权重变更时,客户端也能及时根据变更,进行正确的负载。

4. Feign的 @RequestBody 无法继承

看下面的例子,第一个为Feign客户端,第二个为服务端的Controller

  1. @FeignClient("user")
  2. public interface UserApi {
  3. @RequestMapping("/saveUser")
  4. public String saveUser(@RequestBody User user);
  5. }
  1. @RestController
  2. public class UserController implements UserApi{
  3. @Override
  4. public String saveUser(User user) {
  5. return userService.save(user);
  6. }
  7. }

通1过测试发现,使用该 Feign 客户端去调用的时候,报错:FeignException:status 404。而且发现服务端收到的参数均为null。

原因及解决:UserController无法继承UserApi的@RequestBody属性。因此,最笨的方法就是在UserController上加上@RequestBody,除此之外,另一种优雅的做法是,实现一个定制化的Processor,修改supportParameter的判断方法。判断到为Spring Cloud定义的接口,并且是自定义对象时,使用@RequestBody相同的内容转换器。

  1. @Override
  2. public boolean supportsParameter(MethodParameter parameter)
  3. {
  4. if (AnnotatedElementUtils.hasAnnotation(parameter.getContainingClass(), FeignClient.class) && isCustomizedType(parameter.getParameterType())) {
  5. return true;
  6. }
  7. return super.supportsParameter(parameter);
  8. }

五. 改造带来的收益

改造完成后,经过多轮测试,最终成功投产到生产环境。经过一段时间的验证,我们发现Nacos还是很香的。

1. 经济价值
我们替换了旧的配置和注册中心,目前开发测试共有5套环境,每套环境的配置和注册中心都部署集群的话,需要部署5*2*2=20个节点,现在只需要部署3个节点,即可实现高可用。这为我们省下了一笔机器的花销。

2. 实用价值

<1> 服务管理: 随时随地上下线应用,随时随地修改权重。
<2> 配置管理: 高效管理配置,支持修改对比,回滚配置,并且记录修改记录。

要知道,这两个功能,在Eureka均需要二次开发,这对中小企业来说,不够友好。而Nacos天然地支持服务,配置管理。

3. 其他价值

使用Nacos后,我们的应用完美融入了微服务生态。我们知道,Eureka和Config在融入云原生方面存在很大欠缺(虽然有解决方案,但较为繁琐)。而Nacos则不同,它天然地融入云原生中,据官方消息,Nacos将为融入Service Mesh做出更大改进。

六. 总结

经过上述改造,服务得以顺利地从 Eureka,Config 迁移到 Nacos 上,后续在微服务生态上能发挥更好的价值。

下面做个简单的总结:

1. Spring Cloud Alibaba 实现了Spring Cloud服务注册规范,这使得开发者能够无痛地迁移 Eureka 到 Nacos;

2. 在功能上,Nacos = Eureka + Nacos;

3. 在生态上,Nacos亲近开发者,无论是对dubbo,SpringCloud还是k8s的兼容,深得人心;

因此,可以相信,随着技术的演进, Nacos 一定会在微服务体系上走得更远,走得更好。

七. 参考资料

Nacos官网:https://nacos.io/

扩展Ribbon支持Nacos权重的三种方式:扩展Ribbon支持Nacos权重的三种方式 - 简书

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号