|
| 1 | +--- |
| 2 | +title: Springboot Serverless 实战 - 性能调优 |
| 3 | +description: 'Springboot Serverless 实战 - 性能调优' |
| 4 | +position: 14 |
| 5 | +category: 'FC_Blog' |
| 6 | +--- |
| 7 | + |
| 8 | +作者 | 西流 |
| 9 | + |
| 10 | +[SpringBoot](https://spring.io/projects/spring-boot) 是基于 Java Spring 框架的套件,它预装了 Spring 的一系列组件,让开发者只需要很少的配置就可以创建独立运行的应用程序。在云原生的世界,有大量的平台可以运行 SpringBoot 应用,例如虚拟机,容器等。但其中最有吸引力的,是以 Serverless 的方式运行 SpringBoot 应用。我将通过一系列文章,从架构,部署,监控、性能、安全等5个方面来分析 Serverless 平台运行 SpringBoot 应用的优劣。为了让分析更有代表性,我选择了 github 上 star 数超过 50k 的电商应用 [mall](https://github.com/macrozheng/mall) 作为示例。这是系列文章的第四篇, 向大家展示如何对 Serverless 应用性能调优。 |
| 11 | + |
| 12 | +## 1. 实例启动速度优化 |
| 13 | + |
| 14 | +在之前的教程中,相信大家都感受到 Serverless 的快捷,上传代码包和镜像,就上线了一个弹性高可用的 Web 应用。但其中一个不好的点是首次启动会很慢,因为一段时间没有请求后,Serverless 平台会回收函数实例。下一次再有请求,系统会实时拉起实例,这个过程称之为冷启动。Mall 应用实例的启动大约 30 秒左右,用户会感受较长时间的冷启动延时。 |
| 15 | + |
| 16 | +在优化冷启动之前,我们首先分析清楚冷启动各个阶段的耗时。在函数计算(FC) 控制台的服务配置界面,开启链路追踪功能。 |
| 17 | + |
| 18 | + |
| 19 | + |
| 20 | +对 mall-admin 服务发起请求,成功后查看 FC 控制台,我们能看到相应的请求信息。注意关闭“仅查看函数错误”,这样才会显示所有请求。指标监控和调用链路数据收集有一定延时,如果没有显示,请等待一会再刷新。找到冷启动标记的请求,点击 “更多” 下的 “请求详情”。 |
| 21 | + |
| 22 | + |
| 23 | + |
| 24 | +调用链路会显示冷启动各个环节的耗时。冷启动包含以下几个环节: |
| 25 | + |
| 26 | +- 代码准备(PrepareCode):主要是下载代码包或者镜像。由于我们已经启用了镜像加速功能,不需要下载全部的镜像,因此这一步的延时非常短 |
| 27 | +- 运行时初始化(RuntimeInitialization):从启动函数开始,到函数计算(FC)系统探测到应用端口就绪为止。这中间包含了应用启动时间。在命令行执行 `s mall-admin logs`查看相应的日志时间,我们也能看到 SpringBoot 应用的启动需要花大量的时间 |
| 28 | +- 应用初始化(Initialization):函数计算提供了 Initializer 接口,用户可以将一些初始化逻辑放在 initializer 中执行 |
| 29 | +- 调用延时(Invocation):处理请求的延时,这个延时非常短 |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | +从上述链路追踪图来看,实例启动时间是瓶颈,我们可以采取多种方式来优化。 |
| 34 | + |
| 35 | +### 1.1. 使用预留实例 |
| 36 | + |
| 37 | +Java 类应用普遍启动较慢。应用在初始化时,也需要和很多外部服务交互,耗时较长。这类流程是业务逻辑需要的,很难优化延时。因此函数计算提供了预留实例功能。预留实例的起停由用户自己控制,没有请求也会常驻在那,因此不会有冷启动的问题,当然用户需要为整个实例的运行付费,即便实例没有处理任何请求。 |
| 38 | + |
| 39 | +在函数计算控制台,我们可以在“弹性伸缩”页面为函数设置预留实例。 |
| 40 | + |
| 41 | + |
| 42 | + |
| 43 | +用户在控制台中配置最小和最大实例数。平台会预留最小实例数目的实例,最大实例是指该函数下实例的上限。用户也可以设置定时预留和按指标预留的规则。 |
| 44 | + |
| 45 | + |
| 46 | + |
| 47 | +创建预留规则后,系统就会创建预留实例。当预留实例就绪后,我们再访问函数就不会有冷启动。 |
| 48 | + |
| 49 | + |
| 50 | + |
| 51 | +### 1.2. 优化实例启动速度 |
| 52 | + |
| 53 | +#### 延迟初始化 |
| 54 | + |
| 55 | +在 Spring Boot 2.2 及更高版本中,可以开启一个全局延迟初始化标志。这将提高启动速度,但代价是第一个请求的延迟时间可能变长,因为需要等待组件首次初始化。 |
| 56 | + |
| 57 | +可在 s.yaml 中为相关应用配置以下环境变量 |
| 58 | + |
| 59 | +```shell |
| 60 | +SPRING_MAIN_LAZY_INITIATIALIZATION=true |
| 61 | +``` |
| 62 | + |
| 63 | +#### 关闭优化编译器 |
| 64 | + |
| 65 | +默认情况下,JVM 有多个阶段的 JIT 编译。虽然这些阶段可以逐渐提高应用的效率,但它们也会增加内存使用的开销,并增加启动时间。对于短期运行的 serverless 应用,请考虑关闭此优化,以牺牲长期效率换取更短的启动时间。 |
| 66 | + |
| 67 | +可在 s.yaml 中为相关应用配置以下环境变量: |
| 68 | + |
| 69 | +```shell |
| 70 | +JAVA_TOOL_OPTIONS="-XX:+TieredCompilation -XX:TieredStopAtLevel=1" |
| 71 | +``` |
| 72 | + |
| 73 | +#### s.yaml 中设置环境变量示例: |
| 74 | + |
| 75 | +如下图所示,对 mall-admin 函数配置环境变量。然后执行 `sudo -E s mall-admin deploy` 部署。 |
| 76 | + |
| 77 | + |
| 78 | + |
| 79 | +#### 登录实例检查环境变量是否配置正确 |
| 80 | + |
| 81 | +在控制台函数详情页的请求列表中找到对应的请求,点击`更多`中的`实例详情`链接。 |
| 82 | + |
| 83 | + |
| 84 | + |
| 85 | +在实例详情页中点击`登录实例`。 |
| 86 | + |
| 87 | + |
| 88 | + |
| 89 | +在 shell 界面中执行 echo 命令,查看对应的环境变量是否设置正确。 |
| 90 | + |
| 91 | +> 注意:对于非预留实例,一段时间没有请求后,函数计算系统会自动回收实例。此时无法再登入实例(上面的`实例详情`页面中的`登录实例`按钮会变灰)。所以请执行调用后,在实例被回收之前尽快登录。 |
| 92 | +
|
| 93 | + |
| 94 | + |
| 95 | + |
| 96 | +## 2. 配置合理的实例参数 |
| 97 | + |
| 98 | +当我们选择了应用实例规格,比如 2C4G 或者 4C8G,接下来我们希望知道一个实例处理多少请求是合适的,既能充分利用资源又能保证性能。当处理的请求超过一个限制后,系统能够快速弹出实例,保证应用性能平滑。如何度量实例过载有多个维度,例如 qps 超过一定阈值,或者实例 CPU/Memory/Network/Load 等指标超过阈值等等。函数计算使用实例并发度(Instance Concurrency)来作为实例负载的度量和实例伸缩的依据。实例并发度(Instance Concurrency)是指一个实例能同时执行的请求数。例如将实例并发度设置为20,则意味着一个实例在任意时刻最大能**同时**执行20个请求。 |
| 99 | + |
| 100 | +> 注意:请区分实例并发度和 QPS 的区别。 |
| 101 | +
|
| 102 | + |
| 103 | +使用实例并发度来度量负载有如下优势: |
| 104 | + |
| 105 | +- 系统能够迅速统计实例并发度指标值进行扩缩容。CPU/Memory/Network/Load 等实例级别的指标通常是后台统计,需要花费数十秒的指标统计后才能进行伸缩,难以满足在线应用的弹性伸缩要求 |
| 106 | +- 在各种条件下,实例并发度指标都能够稳定的反映系统负载高低。如果以请求延时作为指标,系统难以区分是实例过载导致延时变大,还是下游服务成为瓶颈导致延时变大。例如一个典型的 Web 应用,通常会访问 MySQL 数据库。如果数据库成为瓶颈,请求延时变大,此时扩容不但毫无意义,而且会压垮数据库,让情况更加恶化。QPS 和请求延时相关,也会有上述问题 |
| 107 | + |
| 108 | +实例并发度作为伸缩依据虽然有上述优点,但用户常常并不知道该设置多大的实例并发度。推荐按照下述流程确定合理的并发度: |
| 109 | + |
| 110 | +1. 将应用函数的最大实例数设置为1,确保压测到单个实例的性能。 |
| 111 | +1. 使用负载压测工具对应用进行压测,查看 tps 和请求延时等指标 |
| 112 | +1. 逐步调大实例并发度,如果性能仍然良好,则继续调大;如果性能不符合预期,则调小并发度。 |
0 commit comments