前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot如何应用轻松上线

SpringBoot如何应用轻松上线

作者头像
阿珍
发布2024-09-20 11:45:16
990
发布2024-09-20 11:45:16

背景

服务刚启动时,如果没有做任何优化的话,前面几分钟的请求,响应都会特别的慢。

下面,针对该问题,全方面介绍,如何解决!

Ingress 负载均衡

Ingress 负载均衡,可以考虑使用 ewma

nginx.ingress.kubernetes.io/load-balance=ewma

ewma 算法可以简单描述为:响应时间越长,分配的请求越少,这样刚启动的 pod, 就只会被分配到少量的流量。

有的云厂商,可能不支持 ewma 算法,也可以考虑使用 least_conn, 即最少请求数。

ewma 更多的内容

应用预热 - 自调用

在大部分框架中,大部分都存在懒加载情况。开始加载时,一般会使用锁来阻止并发。 如果在 Pod 接受用户请求后,再初始化,则会导致前面的几次请求特别慢。 因此,我们有必要在用户请求进入 Pod 前,对程序执行初始化。 初始化懒加载的代码,最简单的方式是在 Pod 对外提供服务前,进行自调用。 在 K8s 中,允许 Pod 定义 启动探针、就绪探针、存活探针。 当 K8s 就绪探针通过后,Pod 就可以对外提供服务了。 简单的说,我们可以等待程序完成自调用后,再通过就绪探针的探测。 大致的流程如下:

1.png
1.png

程序的自调用流程如下:

2.png.png
2.png.png
提高 cpu 上限

自调用的目的主要是为了提前初始化,而不是为了让 JIT 进行编译优化。(不排除有的服务,需要通过大量的自调用,来让 JIT 进行提前的编译优化。)

因为 Mock 过多的请求,会影响服务启动时间,也会影响 Pod 扩容。

在 Pod 启动后,接收请求的前几分钟,CPU 都会特别的高,从而影响用户线程。有比较大的方面是 JIT 的 C1, C2 线程会消耗大量的 CPU。

对于该问题,可以考虑设置更高的 resource.limits.cpu 来避免此问题。

K8s 探针更多信息

Dubbo 预热

Consumer 在调用 Provider 时,本身已经存在预热逻辑。

即:刚启动的 Provider 权重会比较低,并随着时间的增长,权重最终会和其他 Provider 一致。也就是说,刚启动的 Provider 只会接收到少量的请求。 需要注意的是:不同的 Dubbo 版本该逻辑可能会不一样。笔者所在的公司,Dubbo 版本为 2.7.12。 预热代码位置: AbstractLoadBalance#getWeight(Invoker, Invocation) 上诉说的是 Dubbo 本身已有的预热逻辑。

Dubbo Provider 线程池预热

Provider 线程池,默认为 fixed, 可通过 SPI 机制,自定义线程池,并初始化一定数量线程。

服务暴露前预热 Provider

Dubbo 服务暴露触发时机: Spring 容器完成刷新,触发 ContextRefreshedEvent 事件。 代码位置:DubboBootstrapApplicationListener#onApplicationContextEvent(ApplicationContextEvent) 我们可以监听 ContextRefreshedEvent 事件,实现 Ordered 接口,在 DubboBootstrapApplicationListener 逻辑执行前,执行预热 Provider 逻辑。

常见线程池预热

Tomcat 线程池预热

具体的线程数,需要根据应用自行评估

代码语言:javascript
复制
ini 代码解读复制代码
server.tomcat.min-SpareThreads=20
Mysql 连接池预热
代码语言:javascript
复制
java 代码解读复制代码private ApplicationContext ac;

private void preheatDataSource() {
    Map<String, DataSource> map = ac.getBeansOfType(DataSource.class);
    if (CollectionUtils.isEmpty(map)) {
        return;
    }

    for (Map.Entry<String, DataSource> entry : map.entrySet()) {
        DataSource source = entry.getValue();
        if (source instanceof DruidDataSource) {
            DruidDataSource druidDataSource = (DruidDataSource) source;
            int initialSize = druidDataSource.getInitialSize();
            if (initialSize > 0) {
                try {
                    druidDataSource.fill(initialSize);
                } catch (Exception e) {
                }
            }
        }
    }
}
Redis 连接池预热
代码语言:javascript
复制
java 代码解读复制代码private ApplicationContext ac;

private void preheatRedis() {
    Map<String, RedisConnectionFactory> map = ac.getBeansOfType(RedisConnectionFactory.class);
    if (CollectionUtils.isEmpty(map)) {
        return;
    }

    for (Map.Entry<String, RedisConnectionFactory> entry : map.entrySet()) {
        RedisConnectionFactory connectionFactory = entry.getValue();
        List<RedisConnection> connections = new ArrayList<>(3);
        for (int i = 0; i < 3; i++) {
            connections.add(RedisConnectionUtils.getConnection(connectionFactory));
        }

        for (RedisConnection connection : connections) {
            RedisConnectionUtils.releaseConnection(connection, connectionFactory, false);
        }
    }
}

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • Ingress 负载均衡
    • ewma 更多的内容
    • 应用预热 - 自调用
      • 提高 cpu 上限
        • K8s 探针更多信息
        • Dubbo 预热
          • Dubbo Provider 线程池预热
            • 服务暴露前预热 Provider
            • 常见线程池预热
              • Tomcat 线程池预热
                • Mysql 连接池预热
                  • Redis 连接池预热
                  相关产品与服务
                  云数据库 Redis®
                  腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档