K8S的部署策略,重建更新和滚动更新

Deployment Strategies 部署战略

When it comes time to change the version of software implementing your service, a Kubernetes deployment supports two different rollout strategies:

  • Recreate
  • RollingUpdate

当需要更改实施服务的软件版本时,Kubernetes 部署支持两种不同的推出策略:

  • 重新创建

  • 滚动更新

Recreate Strategy 重新创建战略

The Recreate strategy is the simpler of the two rollout strategies. It simply updates the ReplicaSet it manages to use the new image and terminates all of the Pods associated with the deployment. The ReplicaSet notices that it no longer has any replicas, and re-creates all Pods using the new image. Once the Pods are re-created, they are running the new version.

重新创建策略是两种部署策略中最简单的一种。它只需更新其管理的 ReplicaSet 以使用新映像,并终止与部署相关的所有 Pod。ReplicaSet 会注意到它不再有任何副本,并使用新映像重新创建所有 Pod。一旦 Pod 重新创建,它们就会运行新版本。

While this strategy is fast and simple, it has one major drawback—it is potentially catastrophic, and will almost certainly result in some site downtime. Because of this, the Recreate strategy should only be used for test deployments where a service is not user-facing and a small amount of downtime is acceptable.

虽然这种策略快速而简单,但它有一个很大的缺点–有可能造成灾难性后果,几乎肯定会导致网站停机。因此,"重新创建 "策略只能用于服务不面向用户、少量停机时间可以接受的测试部署。

RollingUpdate Strategy 滚动更新策略

The RollingUpdate strategy is the generally preferable strategy for any user-facing service. While it is slower than Recreate, it is also significantly more sophisticated and robust. Using RollingUpdate, you can roll out a new version of your service while it is still receiving user traffic, without any downtime.

对于任何面向用户的服务,RollingUpdate 策略一般都是首选策略。虽然它比 Recreate 慢一些,但也要复杂和强大得多。使用 RollingUpdate,您可以在服务仍在接收用户流量的情况下推出新版本,而无需停机。

As you might infer from the name, the RollingUpdate strategy works by updating a few Pods at a time, moving incrementally until all of the Pods are running the new version of your software.

正如您可能从名称中推断出的那样,RollingUpdate(滚动更新)策略每次更新几个 Pod,循序渐进,直到所有 Pod 都运行新版本的软件。

MANAGING MULTIPLE VERSIONS OF YOUR SERVICE 管理服务的多个版本

Importantly, this means that for a period of time, both the new and the old version of your service will be receiving requests and serving traffic. This has important implications for how you build your software. Namely, it is critically important that each version of your software, and all of its clients, is capable of talking interchangeably with both a slightly older and a slightly newer version of your software.

重要的是,这意味着在一段时间内,新旧版本的服务都将接收请求并提供流量。这对如何构建软件具有重要影响。也就是说,至关重要的是,每个版本的软件及其所有客户端都能与稍旧和稍新版本的软件进行交互对话。

As an example of why this is important, consider the following scenario:

举例说明这一点的重要性,请看下面的情景:

You are in the middle of rolling out your frontend software; half of your servers are running version 1 and half are running version 2. A user makes an initial request to your service and downloads a client-side JavaScript library that implements your UI. This request is serviced by a version 1 server and thus the user receives the version 1 client library. This client library runs in the user’s browser and makes subsequent API requests to your service. These API requests happen to be routed to a version 2 server; thus, version 1 of your JavaScript client library is talking to version 2 of your API server. If you haven’t ensured compatibility between these versions, your application won’t function correctly.

您正在推出您的前端软件;您的服务器一半运行版本 1,一半运行版本 2。用户向您的服务发出初始请求,并下载实现用户界面的客户端 JavaScript 库。该请求由版本 1 服务器提供服务,因此用户收到的是版本 1 客户端库。该客户端库在用户的浏览器中运行,并向您的服务发出后续 API 请求。这些 API 请求恰好被路由到版本 2 服务器;因此,版本 1 的 JavaScript 客户端库正在与版本 2 的 API 服务器进行对话。如果您没有确保这些版本之间的兼容性,您的应用程序将无法正常运行。

At first, this might seem like an extra burden. But in truth, you always had this problem; you may just not have noticed. Concretely, a user can make a request at time t just before you initiate an update. This request is serviced by a version 1 server. At t_1 you update your service to version 2. At t_2 the version 1 client code running on the user’s browser runs and hits an API endpoint being operated by a version 2 server. No matter how you update your software, you have to maintain backward and forward compatibility for reliable updates. The nature of the RollingUpdate strategy simply makes it more clear and explicit that this is something to think about.

起初,这似乎是一个额外的负担。但事实上,你一直都有这个问题,只是没有注意到而已。具体来说,用户可以在启动更新之前的 t 时刻发出请求。该请求由版本 1 服务器提供服务。在 t_1 时,您将服务更新为版本 2。在 t_2 时,运行在用户浏览器上的版本 1 客户端代码会运行并点击由版本 2 服务器操作的 API 端点。无论以何种方式更新软件,都必须保持向后和向前的兼容性,以实现可靠的更新。RollingUpdate 策略的本质只是让我们更清楚、更明确地认识到这一点。

Note that this doesn’t just apply to JavaScript clients—the same thing is true of client libraries that are compiled into other services that make calls to your service. Just because you updated doesn’t mean they have updated their client libraries. This sort of backward compatibility is critical to decoupling your service from systems that depend on your service. If you don’t formalize your APIs and decouple yourself, you are forced to carefully manage your rollouts with all of the other systems that call into your service. This kind of tight coupling makes it extremely hard to produce the necessary agility to be able to push out new software every week, let alone every hour or every day. In the decoupled architecture shown in Figure 10-1, the frontend is isolated from the backend via an API contract and a load balancer, whereas in the coupled architecture, a thick client compiled into the frontend is used to connect directly to the backends.

请注意,这不仅适用于 JavaScript 客户端–编译到其他服务的客户端库也是如此,这些服务会调用您的服务。您更新了客户端库并不意味着他们也更新了客户端库。这种向后兼容性对于将您的服务与依赖于您的服务的系统解耦至关重要。如果您不将 API 正式化并自行解耦,您就不得不仔细管理与调用您的服务的所有其他系统之间的扩展。这种紧密的耦合关系使得你很难实现每周推出新软件所需的敏捷性,更不用说每小时或每天推出新软件了。在图 10-1 所示的解耦架构中,前端通过 API 合同和负载平衡器与后端隔离,而在耦合架构中,编译到前端的厚客户端用于直接连接后端。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

CONFIGURING A ROLLING UPDATE 配置滚动更新

RollingUpdate is a fairly generic strategy; it can be used to update a variety of applications in a variety of settings. Consequently, the rolling update itself is quite configurable; you can tune its behavior to suit your particular needs. There are two parameters you can use to tune the rolling update behavior: maxUnavailable and maxSurge.

RollingUpdate 是一种相当通用的策略,可用于在各种设置下更新各种应用程序。因此,滚动更新本身具有很强的可配置性;您可以调整其行为以满足您的特定需求。有两个参数可用于调整滚动更新行为:maxUnavailable 和 maxSurge。

The maxUnavailable parameter sets the maximum number of Pods that can be unavailable during a rolling update. It can either be set to an absolute number (e.g., 3, meaning a maximum of three Pods can be unavailable) or to a percentage (e.g., 20%, meaning a maximum of 20% of the desired number of replicas can be unavailable).

maxUnavailable 参数设置滚动更新期间不可用 Pod 的最大数量。它可以设置为一个绝对数(例如 3,表示最多只能有 3 个 Pod 不可用),也可以设置为一个百分比(例如 20%,表示最多只能有所需副本数量的 20%不可用)。

Generally speaking, using a percentage is a good approach for most services, since the value is correctly applicable regardless of the desired number of replicas in the deployment. However, there are times when you may want to use an absolute number (e.g., limiting the maximum unavailable Pods to one).

一般来说,对大多数服务来说,使用百分比是一种很好的方法,因为无论部署中需要多少副本,该值都能正确适用。不过,有时您可能希望使用一个绝对数字(例如,将不可用 Pod 的最大值限制为 1)。

At its core, the maxUnavailable parameter helps tune how quickly a rolling update proceeds. For example, if you set maxUnavailable to 50%, then the rolling update will immediately scale the old ReplicaSet down to 50% of its original size. If you have four replicas, it will scale it down to two replicas. The rolling update will then replace the removed Pods by scaling the new ReplicaSet up to two replicas, for a total of four replicas (two old, two new). It will then scale the old ReplicaSet down to zero replicas, for a total size of two new replicas. Finally, it will scale the new ReplicaSet up to four replicas, completing the rollout. Thus, with maxUnavailable set to 50%, our rollout completes in four steps, but with only 50% of our service capacity at times.

maxUnavailable 参数的核心是帮助调整滚动更新的速度。例如,如果将 maxUnavailable 设置为 50%,那么滚动更新会立即将旧的 ReplicaSet 缩减到原始大小的 50%。如果有四个副本,它将缩减为两个副本。然后,滚动更新会通过将新的 ReplicaSet 扩展到两个副本来替换被移除的 Pod,总共有四个副本(两个旧的,两个新的)。然后,它将把旧的 ReplicaSet 减少到零个副本,新副本的总大小为两个。最后,它将把新的 ReplicaSet 扩展到四个副本,完成扩展。因此,在 maxUnavailable 设置为 50%的情况下,我们的扩展分四个步骤完成,但有时只能使用 50%的服务容量。

Consider what happens if we instead set maxUnavailable to 25%. In this situation, each step is only performed with a single replica at a time and thus it takes twice as many steps for the rollout to complete, but availability only drops to a minimum of 75% during the rollout. This illustrates how maxUnavailable allows us to trade rollout speed for availability.

如果我们将 maxUnavailable 设置为 25%,会发生什么情况?在这种情况下,每个步骤一次只执行一个副本,因此需要两倍的步骤才能完成推出,但在推出过程中,可用性只下降到最低 75%。这说明了 maxUnavailable 如何让我们用推出速度来换取可用性。

The observant among you will note that the Recreate strategy is identical to the RollingUpdate strategy with maxUnavailable set to 100%.

细心的人会发现,Recreate 策略与 RollingUpdate 策略完全相同,只是 maxUnavailable 设置为 100%。

Using reduced capacity to achieve a successful rollout is useful either when your service has cyclical traffic patterns (e.g., much less traffic at night) or when you have limited resources, so scaling to larger than the current maximum number of replicas isn’t possible.

当您的服务具有周期性流量模式(例如,夜间流量较少),或者当您的资源有限,无法将复制数量扩展到超过当前最大复制数量时,使用减少容量来实现成功推出是非常有用的。

However, there are situations where you don’t want to fall below 100% capacity, but you are willing to temporarily use additional resources in order to perform a rollout. In these situations, you can set the maxUnavailable parameter to 0%, and instead control the rollout using the maxSurge parameter. Like maxUnavailable, maxSurge can be specified either as a specific number or a percentage.

不过,在某些情况下,您不希望容量低于 100%,但又愿意暂时使用额外资源来执行启动。在这种情况下,可以将 maxUnavailable 参数设置为 0%,然后使用 maxSurge 参数来控制启动。与 maxUnavailable 一样,maxSurge 也可以指定为一个具体数字或百分比。

The maxSurge parameter controls how many extra resources can be created to achieve a rollout. To illustrate how this works, imagine we have a service with 10 replicas. We set maxUnavailable to 0 and maxSurge to 20%. The first thing the rollout will do is scale the new ReplicaSet up to 2 replicas, for a total of 12 (120%) in the service. It will then scale the old ReplicaSet down to 8 replicas, for a total of 10 (8 old, 2 new) in the service. This process proceeds until the rollout is complete. At any time, the capacity of the service is guaranteed to be at least 100% and the maximum extra resources used for the rollout are limited to an additional 20% of all resources.

maxSurge 参数可控制创建多少额外资源来实现推出。为了说明其工作原理,假设我们有一个包含 10 个副本的服务。我们将 maxUnavailable 设为 0,maxSurge 设为 20%。扩展要做的第一件事就是将新的 ReplicaSet 扩展到 2 个副本,使服务中的副本总数达到 12 个(120%)。然后,它会将旧的 ReplicaSet 缩减至 8 个副本,服务中的副本总数为 10 个(8 个旧的,2 个新的)。这个过程一直持续到扩展完成。在任何时候,服务的容量都保证至少为 100%,用于扩展的最大额外资源限制为所有资源的 20%。

Setting maxSurge to 100% is equivalent to a blue/green deployment. The deployment controller first scales the new version up to 100% of the old version. Once the new version is healthy, it immediately scales the old version down to 0%.

将 maxSurge 设置为 100% 相当于蓝/绿部署。部署控制器首先会将新版本缩放到旧版本的 100%。版本的 100%。一旦新版本健康,它就会立即将旧版本缩放到 0%。

Slowing Rollouts to Ensure Service Health 放慢推广速度,确保服务健康

The purpose of a staged rollout is to ensure that the rollout results in a healthy, stable service running the new software version. To do this, the deployment controller always waits until a Pod reports that it is ready before moving on to updating the next Pod.

分阶段推出的目的是确保推出运行新软件版本的健康、稳定的服务。为此,部署控制器总是等到某个 Pod 报告准备就绪后,才继续更新下一个 Pod。

The deployment controller examines the Pod’s status as determined by its readiness checks. Readiness checks are part of the Pod’s health probes, and they are described in detail in Chapter 5. If you want to use deployments to reliably roll out your software, you have to specify readiness health checks for the containers in your Pod. Without these checks, the deployment controller is running blind.

部署控制器会根据 Pod 的就绪检查来检查 Pod 的状态。就绪检查是 Pod 健康探针的一部分,第 5 章对此有详细介绍。如果要使用部署来可靠地推出软件,就必须为 Pod 中的容器指定就绪状态检查。没有这些检查,部署控制器就会盲目运行。

Sometimes, however, simply noticing that a Pod has become ready doesn’t give you sufficient confidence that the Pod actually is behaving correctly. Some error conditions only occur after a period of time. For example, you could have a serious memory leak that takes a few minutes to show up, or you could have a bug that is only triggered by 1% of all requests. In most real-world scenarios, you want to wait a period of time to have high confidence that the new version is operating correctly before you move on to updating the next Pod.

但有时,仅仅注意到 Pod 已准备就绪,并不能让你充分相信 Pod 的实际行为是正确的。有些错误只有在一段时间后才会出现。例如,你可能有一个严重的内存泄漏,需要几分钟才会出现,或者你可能有一个错误,只有 1%的请求才会触发。在大多数实际情况下,您都希望在更新下一个 Pod 之前等待一段时间,以便对新版本的正确运行有较高的信心。

For deployments, this time to wait is defined by the minReadySeconds parameter:

对于部署,等待时间由 minReadySeconds 参数定义:

...
spec:minReadySeconds: 60
...

Setting minReadySeconds to 60 indicates that the deployment must wait for 60 seconds after seeing a Pod become healthy before moving on to updating the next Pod.

将 minReadySeconds 设置为 60 表明,部署必须在看到 Pod 恢复健康后等待 60 秒,才能继续更新下一个 Pod。

In addition to waiting a period of time for a Pod to become healthy, you also want to set a timeout that limits how long the system will wait. Suppose, for example, the new version of your service has a bug and immediately deadlocks. It will never become ready, and in the absence of a timeout, the deployment controller will stall your rollout forever.

除了等待一段时间让 Pod 恢复健康外,您还想设置一个超时时间,限制系统等待的时间。例如,假设新版本的服务出现错误,并立即出现死锁。如果没有超时,部署控制器将永远无法推出新版本。

The correct behavior in such a situation is to time out the rollout. This in turn marks the rollout as failed. This failure status can be used to trigger alerting that can indicate to an operator that there is a problem with the rollout.

在这种情况下,正确的做法是让推出超时。这反过来会将推出标记为失败。这种失败状态可用于触发警报,向操作员说明滚动出现了问题。

At first blush, timing out a rollout might seem like an unnecessary complication. However, increasingly, things like rollouts are being triggered by fully automated systems with little to no human involvement. In such a situation, timing out becomes a critical exception, which can either trigger an automated rollback of the release or create a ticket/event that triggers human intervention.

乍一看,定时推出可能是一个不必要的麻烦。然而,越来越多的情况是,像发布这样的事情是由完全自动化的系统触发的,几乎没有人工参与。在这种情况下,超时就成了一个关键的异常情况,它既可以触发发布的自动回滚,也可以创建一个触发人工干预的票据/事件。

To set the timeout period, the deployment parameter progressDeadlineSeconds is used:

要设置超时时间,可使用部署参数 progressDeadlineSeconds:

...
spec:progressDeadlineSeconds: 600
...

This example sets the progress deadline to 10 minutes. If any particular stage in the rollout fails to progress in 10 minutes, then the deployment is marked as failed, and all attempts to move the deployment forward are halted.

此示例将进度截止时间设置为 10 分钟。如果推出过程中的任何特定阶段未能在 10 分钟内取得进展,那么部署就会被标记为失败,所有推进部署的尝试都会停止。

It is important to note that this timeout is given in terms of deployment progress, not the overall length of a deployment. In this context, progress is defined as any time the deployment creates or deletes a Pod. When that happens, the timeout clock is reset to zero. Figure 10-2 is an illustration of the deployment lifecycle.

需要注意的是,超时时间是根据部署进度而不是部署的总长度来确定的。在这种情况下,进度被定义为部署创建或删除 Pod 的任何时间。发生这种情况时,超时时钟会重置为零。图 10-2 是部署生命周期的示意图。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/611436.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跟着我学Python进阶篇:02.面向对象(上)

往期文章 跟着我学Python基础篇:01.初露端倪 跟着我学Python基础篇:02.数字与字符串编程 跟着我学Python基础篇:03.选择结构 跟着我学Python基础篇:04.循环 跟着我学Python基础篇:05.函数 跟着我学Python基础篇&#…

Linux C/C++ 显示NIC流量统计信息

NIC流量统计信息是由操作系统维护的。当数据包通过NIC传输时,操作系统会更新相关的计数器。这些计数器记录了数据包的发送和接收数量、字节数等。通过读取这些计数器,我们可以获得关于网络流量的信息。 为什么需要这些信息? 可以使用这些信息来监控网络…

Java建筑工程建设智慧工地源码

智慧工地管理平台依托物联网、互联网,建立云端大数据管理平台,形成“端云大数据”的业务体系和新的管理模式,从施工现场源头抓起,最大程度的收集人员、安全、环境、材料等关键业务数据,打通从一线操作与远程监管的数据…

C++11_lambda表达式

文章目录 一、lambda表达式1.lambda的组成2.[capture-list] 的其他使用方法2.1混合捕捉 二、lambda表达式的使用场景1.替代仿函数 总结 一、lambda表达式 lambda表达式是C11新引入的功能,它的用法与我们之前学过的C语法有些不同。 1.lambda的组成 [capture-list] …

【C++进阶05】AVL树的介绍及模拟实现

一、AVL树的概念 二叉搜索树的缺点 二叉搜索树虽可以缩短查找效率 但如果数据有序或接近有序 二叉搜索树将退化为单支树 查找元素相当于在顺序表中搜索元素,效率低下 AVL树便是解决此问题 向二叉搜索树中插入新结点 并保证每个结点的左右子树 高度之差的绝对值不超…

Java诊断利器Arthas

https://arthas.aliyun.com/doc/https://arthas.aliyun.com/doc/ 原理 利用java.lang.instrument(容器类) 做动态 Instrumentation(执行容器) 是 JDK5 的新特性。使用 Instrumentation,开发者可以构建一个独立于应用程序的代理程序(Agent)&…

汽车IVI中控开发入门及进阶(十二):手机投屏

前言: 汽车座舱有车载中控大屏、仪表/HUD多屏的显示能力,有麦克风/喇叭等车载环境更好的音频输入输出能力,有方控按键、旋钮等方便的反向控制输入能力,还有高精度的车辆数据等。但汽车座舱中控主机硬件计算能力升级迭代周期相对较长,汽车的应用和服务不够丰富。现在很多汽…

.NetCore部署微服务(二)

目录 前言 概念 一 Consul注册服务中心 1.1 consul下载 1.2 consul运行 二 服务注册 2.1 安装Consul包 2.2 修改配置文件 2.3 注入Consul服务 2.3 修改Controller,增加HealthCheck方法 三 运行服务 3.1 docker运行服务 前言 上一篇讲到微服务要灵活伸缩…

「超级细菌」魔咒或将打破,MIT 利用深度学习发现新型抗生素

作者:加零 编辑:李宝珠、三羊 MIT 利用图神经网络 Chemprop 识别潜在抗生素,特异性杀死鲍曼不动杆菌。 自然界中充满了各种各样的微生物,例如结核杆菌(导致肺结核)、霍乱弧菌(导致霍乱&#…

数据结构实验4:链表的基本操作

目录 一、实验目的 二、实验原理 1. 节点 2. 指针 3.链表的类型 3.1 单向链表 3.2 双向链表 3.3 单向循环链表 3.4 双向循环链表 4. 单链表的插入 4.1 头插法 4.2 尾插法 4.3 在指定位置插入元素 5. 单链表的删除 5.1 删除指定数值的节点 5.2 删除指定位置的节点 …

Pytorch从零开始实战16

Pytorch从零开始实战——ResNeXt-50算法的思考 本系列来源于365天深度学习训练营 原作者K同学 对于上次ResNeXt-50算法,我们同样有基于TensorFlow的实现。具体代码如下。 引入头文件 import numpy as np from tensorflow.keras.preprocessing.image import Ima…

TensorRt(5)动态尺寸输入的分割模型测试

文章目录 1、固定输入尺寸逻辑2、动态输入尺寸2.1、模型导出2.2、推理测试2.3、显存分配问题2.4、完整代码 这里主要说明使用TensorRT进行加载编译优化后的模型engine进行推理测试,与前面进行目标识别、目标分类的模型的网络输入是固定大小不同,导致输入…

【现代密码学】笔记3.4-3.7--构造安全加密方案、CPA安全、CCA安全 《introduction to modern cryphtography》

【现代密码学】笔记3.4-3.7--构造安全加密方案、CPA安全、CCA安全 《introduction to modern cryphtography》 写在最前面私钥加密与伪随机性 第二部分流加密与CPA多重加密 CPA安全加密方案CPA安全实验、预言机访问(oracle access) 操作模式伪随机函数PR…

Java微服务系列之 ShardingSphere - ShardingSphere-JDBC

🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 系列专栏目录 [Java项…

报错解决:No module named ‘pytorch_lightning‘ 安装pytorch_lightning

报错记录 执行如下代码: import pytorch_lightning报错: No module named ‘pytorch_lightning’ 解决方式 安装pytorch_lightning包即可。 一般情况下,缺失的包通过pip安装,即: pip install pytorch_lightning然…

1 快速前端开发

1 前端开发 目的:开发一个平台(网站)- 前端开发:HTML、CSS、JavaScript- Web框架:接收请求并处理- MySQL数据库:存储数据地方快速上手:基于Flask Web框架让你快速搭建一个网站出来。1.快速开发…

HarmonyOS应用开发学习笔记 应用上下文Context 获取文件夹路径

1、 HarmoryOS Ability页面的生命周期 2、 Component自定义组件 3、HarmonyOS 应用开发学习笔记 ets组件生命周期 4、HarmonyOS 应用开发学习笔记 ets组件样式定义 Styles装饰器:定义组件重用样式 Extend装饰器:定义扩展组件样式 5、HarmonyOS 应用开发…

14-股票K线图功能-个股日K线SQL分析__ev

需求:统计个股日K线数据,也就是把某只股票每天的最高价,开盘价,收盘价,最低价形成K线图。

山西电力市场日前价格预测【2024-01-11】

日前价格预测 预测说明: 如上图所示,预测明日(2024-01-11)山西电力市场全天平均日前电价为231.43元/MWh。其中,最高日前电价为422.21元/MWh,预计出现在18:00。最低日前电价为0.00元/MWh,预计出…

现代软件测试中的自动化测试工具

自动化测试的重要性和优势 引言:随着软件开发的不断发展,自动化测试工具在现代软件测试中扮演着重要角色。提高效率:自动化测试可以加快测试流程,减少人工测试所需的时间和资源。提升准确性:自动化测试工具可以减少人…