侧边栏壁纸
博主头像
博主等级

  • 累计撰写 19 篇文章
  • 累计创建 34 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

K8s平滑更新基于Nacos注册微服务

前尘一梦
2022-02-04 / 0 评论 / 0 点赞 / 25 阅读 / 3956 字

前言

最近公司的一个新业务线集成了K8s集成部署多个项目,项目使用Nacos作为注册中心,版本是1.4.x,服务间通过Feign调用通信,最近发现在服务在重新部署的期间,会存在应用间接口调用超时的情况,此处记录下问题的排查和解决。

过程

通过追踪Nacos源码及查阅相关资料初步排查原因有如下几点

  • NacosAutoServiceRegistration继承了Spring Cloud中的AbstractAutoServiceRegistration类重写了deregister方法进行服务下线,由于hook机制,Spring容器停止的时候会触发该方法调用,但此处存在调用到Nacos Server端及Server端把下线消息通知到订阅者的延迟;

5b043aeeef5349b1a7d0878a65fd7e3d~tplv-k3u1fbpfcp-watermark.jpg

  • Nacos默认心跳超时15s后才会标记为不健康

  • 被调用服务其实已经在停止过程中不再接收请求,调用方本地还缓存着该服务的实例地址,NacosDiscoveryClient实现了spring cloud中的DiscoveryClient类,跟踪其getInstances方法发现去服务端拉取提供方列表的定时任务默认10s才会执行一次

93a022139b9d453d9c0764fbdaf2c7ef~tplv-k3u1fbpfcp-watermark.jpg

2c9f93b861bf49e6a02174ec6a86953e~tplv-k3u1fbpfcp-watermark.jpg

964a3d6b6c5a49d78afa8ba76484cb3f~tplv-k3u1fbpfcp-watermark.jpg

解决

从上面的排查中,我们最容易想到的就是缩短服务下线感知的延时,比如缩短客户端拉取提供者服务的定时任务周期,把10s改成1,2秒,这样确实有些效果,但不能完全解决问题。用户量访问较频繁的接口很容易就出现问题,要想做到平滑更新,用户无感知,需要保证以下两点

  • 在该服务停机之前,已经从注册中心下线

  • 下线的信息已全部同步到各订阅者

此时很容易想到是否能在服务停机之前将其从服务端下线。从上面的源码中可以看到NacosAutoServiceRegistration这个类正好能为我们所用。只要在服务停止前调用一下,等一段时间后再停止服务即可,与运维沟通了解到K8s中存在postStart 和 preStop 处理函数

可以在停止容器前做一些操作,另一方面项目里有使用到Spirngboot Actuator 做JVM监控及健康检查,就顺便增加了一个自定义端点来处理服务下线,代码如下

@Slf4j
@Component
@Endpoint(id = "shutdownGraceFul")
public class ServiceShutDownEndpoint {

    @Resource
    private NacosAutoServiceRegistration serviceRegistration;

    @Resource
    private  ApplicationContext context;

    /** 下线服务后关闭应用前等待的时间(秒) */
    @Value("${stopService.waitTime:120}")
    private int waitTime;



    @WriteOperation
    public Map<String, Object> shutdownGraceFul() {
        log.info("开始服务下线");
        serviceRegistration.stop();
        log.info("完成服务下线");
        log.info("等待{}s, 关闭应用", waitTime);
        try {
            TimeUnit.SECONDS.sleep(waitTime);
        } catch (InterruptedException e) {
            log.info("interrupted!", e);
        }
        log.info("Closing application...");
        SpringApplication.exit(context);
        Map<String, Object> result = new HashMap<>();

        result.put("shutdownGraceFul", true);
        return result;
    }

}

k8s中yml配置如下

639007c6787d4a769ed439fc00e83d7e~tplv-k3u1fbpfcp-watermark.jpg

等待的时间可根据实际情况调整,不能太短,得保证下掉应用后Nacos服务端能把节点下线消息完全同步到所有调用方

总结

看了下Nacos2.x版本以后使用Grpc和Rsocket替代了之前大部分的Http请求和基于Udp协议的请求,极大的缩短了延迟,但试了下还是存在此问题,小伙伴可针对自己项目使用的版本进行测试。

0

评论区