无服务器的容器化已经席卷了世界,因为它为开发人员提供了一种部署无状态微服务的方法,而无需承受沉重的基础设施管理负担。Cloud Run 抽象了所有的基础设施管理,可以推送一个带有web服务器和无状态逻辑的容器映像,并指定内存/CPU和允许并发性的组合。
Cloud Run负责创建HTTP端点,将请求路由到容器,并上下缩放容器以处理请求量。虽然CloudRun提供了一些本机特性来减少响应时间延迟,比如空闲实例,另外还可以通过编写有效的 services 继续提升,具体详情参见下文。
1.空闲实例
随着流量的波动,CloudRun试图通过保持一些空闲实例来处理流量尖峰以减少冷启动的风险。例如,当容器实例完成处理请求时,它可能会在一段时间内保持空闲状态,以防需要处理另一个请求。
但是,如果没有请求需要处理,CloudRun将在一段时间后终止未使用的容器。这意味着仍有可能出现冷启动。容器实例将根据需要进行缩放,并将完全初始化执行环境。而您也可以使用min实例设置使空闲实例永久可用,但即使服务没有主动地为请求提供服务,这也会增加成本。
因此,假设我们希望在可能的冷启动过程中最小化成本和响应时间延迟,并且不想设置最小数量的空闲实例,但是我们知道当容器启动时,在它可以开始监听请求之前,任何额外的计算都意味着更长的加载时间和延迟。
2.Cloud Run 容器启动
云运行容器启动是可以通过一些技巧来优化容器启动时间的服务。这里的目标是尽量减少容器实例服务请求时的延迟。但首先,让我们回顾一下云运行容器启动例程。
在高级别,它包括:
1.开始服务
a.启动容器
b.运行Enrypoint命令来启动服务器
2.检查开放服务端口
我们希望优化服务以尽量减少步骤1a所需的时间,因此,在这里让我们介绍3种优化云运行响应时间服务的方法。
创建更精简的服务
在使用动态语言编写应用程序时,需要格外小心。例如,如果使用Node.js或Python,在进程启动时发生的模块加载将在冷启动期间增加延迟。
还要注意某些模块在导入时运行初始化代码。
要构建更精简的服务,可以进行以下操作:
-
如果使用动态语言,则最小化依赖项的数量和大小。
-
与其在启动时计算,不如慢慢地计算。全局变量的初始化总是在启动过程中进行,这会增加冷启动时间。对不经常使用的对象使用延迟初始化,以推迟时间成本并减少冷启动时间。
-
缩短初始化时间并加快启动HTTP服务器的时间。
-
使用代码加载优化,比如PHP的Composer自动优化。
使用更精简的基本图像
首先,在Cloud Run 时,容器映像的大小不会影响冷启动或请求处理时间。冷启动并不受图像大小的影响,而是受图像系统复杂性和初始化时间的影响。例如,一个基本映像,它有12个慢启动OS级别的包,这在冷启动期间会增加延迟。另一方面,你可以有一个超级简单的基本映像,在这个映像中复制一个500GB的数据文件,而这个更大的映像不会增加启动时间。
可以通过处理一个精简的基本映像来构建一个最小的容器,如:alpine, distroless.
你也可以用scratch这是一个空映像,可以在该映像上构建自己的运行环境。如果您的应用程序是静态链接的二进制文件,则可以很容易地使用scratch base映像:
FROM scratchCOPY mybinary
/mybinary
CMD [ "/mybinary" ]
这些映像也较小,在工作流的其他部分,比如本地开发或构建系统中,它们的处理速度往往更快。例如,alpine 3.7图像比centos 7图像小71 MB。 并且要只在映像中安装严格需要的内容。换句话说,不要安装不需要的额外软件包。
使用全局变量
在Cloud Run 中,不能假设在请求之间保留服务状态。但是,Cloud Run确实重用了单个容器实例来服务正在进行的通信。
这意味着可以声明一个全局变量。一旦容器被旋转,初始化并存储在内存中的全局变量中的对象可以在请求之间重用。将此从请求逻辑转移到全局范围意味着在流量持续时具有更好的性能。虽然这并不能准确地帮助冷启动时间,但是一旦容器被初始化,缓存对象可以帮助减少后续持续请求期间的延迟。
例如,如果将每个请求逻辑移到全局范围,它应该会使冷启动持续的时间大致相同(如果添加额外的逻辑来缓存温暖请求中的缓存,则会增加冷启动时间),但是由该温实例提供的任何后续请求都有较低的延迟时间。
// Global (instance-wide) scope
// This computation runs at instance cold-start
const instanceVar = heavyComputation();
/**
* HTTP function that declares a variable.
*
* @param {Object} req request context.
* @param {Object} res response context.
*/
exports.scopeDemo = (req, res) => {
// Per-function scope
// This computation runs every time this function is called
const functionVar = lightComputation();
res.send(`Per instance: ${instanceVar}, per function: ${functionVar}`);
};
一个可以帮助冷启动的选项是将全局状态卸载到内存中的数据存储,如Memorystore,它提供了对应用程序缓存的极低延迟数据访问。
3.结语
其中很多归结为创建精简服务,因此可以将容器初始化期间计算的逻辑最小化,并且可以尽快开始服务请求。尽管这些只是设计Cloud Run服务的一些最佳实践,但是还有许多其他技巧可以编写有效的服务和优化性能,您可以在Google Cloud 官网阅读有关这些技巧,或关注我们,会有不定期的干货技巧分享哦~
编译自:3 ways to optimize Cloud Run response times
电话:18651688484
邮箱合作:cloud@webeye.com
想了解更多,可扫描下方二维码留下您的问题
我们会及时与您联系