借助Nacos完成 关路由动态配置、灰度发布、服务优雅上下线

随着业务和架构的发展,微服务的开发部署方式已经变成了如今技术发展的趋势,而在微服务流量入口控制上基本都是通过 关来实现的。 关的作用:路由转发、熔断、限流、安全认证、日志监控等,在前面也发布过一篇关于从零开始搭建微服务之 关建设的文章,大家感兴趣的话可以去了解下 关的基本介绍。

背景

目前我们的服务流量入口已统一由 关进行转发,路由信息定义在配置文件中,但是这种方式有一个缺点就是修改路由信息必须重启服务才能生效。 关作为支付全部流量的入口,需要保证其高可用,所以需要做到不重启服务而修改路由信息,现结合Nacos去实现配置动态路由,同时需要转发服务统一注册到Nacos注册中心, 关直接在注册中心中选择机器进行转发。下面介绍具体改造的代码。

关接入Nacos动态刷新 关路由配置表

如果要实现动态路由配置,主要需要做到2点,

  1. Nacos能够监听到客户端前台配置文件的修改;
  2. 将修改的配置文件变更新到 关路由中;

针对以上2点,我们需要通过代码来监听Nacos配置文件修改变化,同时利用Spring事件发布将配置文件变更信息动态刷新到路由配置表中,核心代码如下:

@Component
@Slf4j
public class NacosDynamicRouteService implements ApplicationEventPublisherAware {
 
    @Value("${spring.cloud.nacos.config.server-addr}")
    private String serverAddr;
 
    @Value("${nacos.group}")
    private String group;
 
    @Value("${nacos.dataId}")
    private String routeConfigDataId;
 
    @Value("${nacos.namespace}")
    private String namespace;
 
    @Resource
    private RouteDefinitionWriter routeDefinitionWriter;
 
    private ApplicationEventPublisher applicationEventPublisher;
 
    private static final List<String> ROUTE_LIST = new ArrayList<>();
 
    @Override
    public void setApplicationEventPublisher(@NotNull ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
 
    @PostConstruct
    public void dynamicRouteListener() {
        try {
            Properties properties = new Properties();
            properties.put("serverAddr", serverAddr);
            properties.put("namespace", namespace);
            ConfigService configService = NacosFactory.createConfigService(properties);
 
            // 程序首次启动, 并加载初始化路由配置
            String initConfigInfo = configService.getConfig(routeConfigDataId, group, 5000);
            addAndPublishBatchRoute(initConfigInfo);
 
            configService.addListener(routeConfigDataId, group, new Listener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    addAndPublishBatchRoute(configInfo);
                }
 
                @Override
                public Executor getExecutor() {
                    return null;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 批量 添加及发布 路由
     * @param configInfo 配置文件字符串, 必须为json array格式
     */
    private void addAndPublishBatchRoute(String configInfo) {
        try {
            clearRoute();
            List<RouteDefinition> gatewayRouteDefinitions = JSONObject.parseArray(configInfo, RouteDefinition.class);
            for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {
                addRoute(routeDefinition);
            }
            publish();
            log.info(">>>>>>>>>>>>>>>>>Nacos Dynamic config gateway route finished | {}", JSON.toJSONString(gatewayRouteDefinitions));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 清空所有路由
     */
    private void clearRoute() {
        for(String id : ROUTE_LIST) {
            this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
        }
        ROUTE_LIST.clear();
    }
 
    /**
     * 添加单条路由信息
     * @param definition RouteDefinition
     */
    private void addRoute(RouteDefinition definition) {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        ROUTE_LIST.add(definition.getId());
    }
 
    /**
     * 发布路由表变更事件
     */
    private void publish() {
        this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
    }
}

配置文件yml

nacos:
    group: DEFAULT_GROUP
    dataId: gateway-outer-nacos-beta
    namespace: beta

Nacos控制台配置路由信息

路由转发JSON

具体JSON配置如下:注意my-service为转发服务注册到Nacos的服务名

[{
    "id": "service",
    "order": 0,
    "predicates": [{
        "args": {
            "pattern": "/service/**"
        },
        "name": "Path"
    }],
    "filters":[{
        "args": {
            "_genkey_0": "1"
        },
        "name": "StripPrefix"
    }],
    "uri": "lb://my-service"
}]

转发服务注册到Nacos注册中心

第一步:引入Nacos注册中心和spring-cloud依赖

<alibaba.nacos.version>2.1.4.RELEASE</alibaba.nacos.version>
 
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>${alibaba.nacos.version}</version>
</dependency>
 
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>${alibaba.nacos.version}</version>
</dependency>
 
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

第二步:SpringBootApplication增加服务发现注解 @EnableDiscoveryClient

@SpringBootApplication
@EnableDiscoveryClient
public class Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

第三步:增加bootstrap.yml 注册服务中心名称, 关负载转发

spring:
    application:
        name: my-service

第四步:配置文件增加Nacos注册中心配置地址


http://192.168.x.1:8848/nacos/index.html 为后台登陆管理界面

spring:
    cloud:
        nacos:
            config:
                server-addr: 192.168.x.1:8848,192.168.x.2:8848,192.168.x.3:8848  
                namespace: beta # 命名空间进行环境隔离
            discovery:
                server-addr: 192.168.x.1:8848,192.168.x.2:8848,192.168.x.3:8848  
                namespace: beta # 命名空间进行环境隔离

流量灰度,Nacos权重设置

首先,需要在 关项目增加负载均衡策略,权重设置才会生效,代码如下:

@Configuration
public class Configuration {    @Bean
    @Scope(value="prototype")
    public IRule loadBalanceRule(){
        return new NacosRule();
    }
}

接下来就可以在Nacos控制台界面进行权重设置,完成流量倾斜转发了。

注册服务列表

服务详情操作页

服务流量转发权重设置

在服务滚动发布过程中,可以通过点击服务下线按钮,停止正在上线服务的转发,避免因服务重启造成的数据问题。以上就是 关(SpringCloud Gateway)结合Nacos完成 关路由动态配置、灰度发布、服务优雅上下线等功能。

不断分享开发过程用到的技术和面试经常被问到的问题,如果您也对IT技术比较感兴趣可以「关注」我,让我们共同学习,共同进步!

声明:本站部分文章内容及图片转载于互联 、内容不代表本站观点,如有内容涉及侵权,请您立即联系本站处理,非常感谢!

(0)
上一篇 2021年3月6日
下一篇 2021年3月6日

相关推荐