arrow_back

在 Google Kubernetes Engine 上调试应用

登录 加入
访问 700 多个实验和课程

在 Google Kubernetes Engine 上调试应用

实验 1 小时 15 分钟 universal_currency_alt 5 个积分 show_chart 中级
info 此实验可能会提供 AI 工具来支持您学习。
访问 700 多个实验和课程

GSP736

Google Cloud 自学实验的徽标

概览

Cloud Logging 及其配套工具 Cloud Monitoring 都是功能齐全的产品,并且都与 Google Kubernetes Engine 深度集成。本实验将通过常见的日志记录应用场景,教您了解 Cloud Logging 如何与 GKE 集群和应用配合使用,以及日志收集的一些最佳实践。

目标

在本实验中,您将学习如何完成以下操作:

  • 使用 Cloud Monitoring 检测问题
  • 使用 Cloud Logging 排查在 GKE 上运行的应用的问题

本实验中使用的演示应用

为了使用具体示例,您将对部署到 GKE 集群的示例微服务演示应用进行问题排查。在此演示应用中,有许多微服务,并且它们之间存在依赖关系。您将使用 loadgenerator 生成流量,然后使用 Logging、Monitoring 和 GKE 来发现错误(提醒/指标),使用 Logging 确定根本原因,最后使用 Logging 和 Monitoring 修复/确认问题已修复。

Cloud Logging 架构图

设置和要求

点击“开始实验”按钮前的注意事项

请阅读以下说明。实验是计时的,并且您无法暂停实验。计时器在您点击开始实验后即开始计时,显示 Google Cloud 资源可供您使用多长时间。

此实操实验可让您在真实的云环境中开展实验活动,免受模拟或演示环境的局限。为此,我们会向您提供新的临时凭据,您可以在该实验的规定时间内通过此凭据登录和访问 Google Cloud。

为完成此实验,您需要:

  • 能够使用标准的互联网浏览器(建议使用 Chrome 浏览器)。
注意:请使用无痕模式(推荐)或无痕浏览器窗口运行此实验。这可以避免您的个人账号与学生账号之间发生冲突,这种冲突可能导致您的个人账号产生额外费用。
  • 完成实验的时间 - 请注意,实验开始后无法暂停。
注意:请仅使用学生账号完成本实验。如果您使用其他 Google Cloud 账号,则可能会向该账号收取费用。

如何开始实验并登录 Google Cloud 控制台

  1. 点击开始实验按钮。如果该实验需要付费,系统会打开一个对话框供您选择支付方式。左侧是“实验详细信息”窗格,其中包含以下各项:

    • “打开 Google Cloud 控制台”按钮
    • 剩余时间
    • 进行该实验时必须使用的临时凭据
    • 帮助您逐步完成本实验所需的其他信息(如果需要)
  2. 点击打开 Google Cloud 控制台(如果您使用的是 Chrome 浏览器,请右键点击并选择在无痕式窗口中打开链接)。

    该实验会启动资源并打开另一个标签页,显示“登录”页面。

    提示:将这些标签页安排在不同的窗口中,并排显示。

    注意:如果您看见选择账号对话框,请点击使用其他账号
  3. 如有必要,请复制下方的用户名,然后将其粘贴到登录对话框中。

    {{{user_0.username | "<用户名>"}}}

    您也可以在“实验详细信息”窗格中找到“用户名”。

  4. 点击下一步

  5. 复制下面的密码,然后将其粘贴到欢迎对话框中。

    {{{user_0.password | "<密码>"}}}

    您也可以在“实验详细信息”窗格中找到“密码”。

  6. 点击下一步

    重要提示:您必须使用实验提供的凭据。请勿使用您的 Google Cloud 账号凭据。 注意:在本实验中使用您自己的 Google Cloud 账号可能会产生额外费用。
  7. 继续在后续页面中点击以完成相应操作:

    • 接受条款及条件。
    • 由于这是临时账号,请勿添加账号恢复选项或双重验证。
    • 请勿注册免费试用。

片刻之后,系统会在此标签页中打开 Google Cloud 控制台。

注意:如需访问 Google Cloud 产品和服务,请点击导航菜单,或在搜索字段中输入服务或产品的名称。 “导航菜单”图标和“搜索”字段

激活 Cloud Shell

Cloud Shell 是一种装有开发者工具的虚拟机。它提供了一个永久性的 5GB 主目录,并且在 Google Cloud 上运行。Cloud Shell 提供可用于访问您的 Google Cloud 资源的命令行工具。

  1. 点击 Google Cloud 控制台顶部的激活 Cloud Shell “激活 Cloud Shell”图标

  2. 在弹出的窗口中执行以下操作:

    • 继续完成 Cloud Shell 信息窗口中的设置。
    • 授权 Cloud Shell 使用您的凭据进行 Google Cloud API 调用。

如果您连接成功,即表示您已通过身份验证,且项目 ID 会被设为您的 Project_ID 。输出内容中有一行说明了此会话的 Project_ID

Your Cloud Platform project in this session is set to {{{project_0.project_id | "PROJECT_ID"}}}

gcloud 是 Google Cloud 的命令行工具。它已预先安装在 Cloud Shell 上,且支持 Tab 自动补全功能。

  1. (可选)您可以通过此命令列出活跃账号名称:
gcloud auth list
  1. 点击授权

输出:

ACTIVE: * ACCOUNT: {{{user_0.username | "ACCOUNT"}}} To set the active account, run: $ gcloud config set account `ACCOUNT`
  1. (可选)您可以通过此命令列出项目 ID:
gcloud config list project

输出:

[core] project = {{{project_0.project_id | "PROJECT_ID"}}} 注意:如需查看在 Google Cloud 中使用 gcloud 的完整文档,请参阅 gcloud CLI 概览指南

设置区域和可用区

某些 Compute Engine 资源位于区域和可用区内。区域是指某个地理位置,您可以在其中运行自己的资源。每个区域包含一个或多个可用区。

在 Cloud 控制台中运行以下 gcloud 命令,设置实验的默认区域和可用区:

gcloud config set compute/zone "{{{project_0.default_zone|ZONE}}}" export ZONE=$(gcloud config get compute/zone) gcloud config set compute/region "{{{project_0.default_region|REGION}}}" export REGION=$(gcloud config get compute/region)

任务 1. 基础架构设置

连接到一个 Google Kubernetes Engine 集群,并验证该集群已正确创建。

  1. 设置项目 ID 变量:
export PROJECT_ID={{{project_0.startup_script.project | Project ID}}}
  1. 使用以下命令查看集群的状态:
gcloud container clusters list

集群状态将显示为“正在预配”。

  1. 稍等片刻,再次运行上述命令,直到状态显示为“正在运行”。这可能需要几分钟时间。

  2. 验证名为 central 的集群已创建。

您还可以在 Cloud 控制台中监控进度,方法是依次前往导航菜单 > Kubernetes Engine > 集群

  1. 当集群状态显示为“正在运行”后,获取集群凭据:
gcloud container clusters get-credentials central --zone $ZONE

输出:

Fetching cluster endpoint and auth data. kubeconfig entry generated for central.
  1. 验证节点已经创建:
kubectl get nodes

输出的内容应如下所示:

NAME STATUS ROLES AGE VERSION gke-central-default-pool-5ff4130f-qz8v Ready 24d v1.27.2-gke.1200 gke-central-default--pool-5ff4130f-ssd2 Ready 24d v1.27.2-gke.1200 gke-central-default--pool-5ff4130f-tz63 Ready 24d v1.27.2-gke.1200 gke-central-default--pool-5ff4130f-zfmn Ready 24d v1.27.2-gke.1200

任务 2. 部署应用

接下来,将一个名为 Hipster Shop 的微服务应用部署到集群中,创建您可以监控的工作负载。

  1. 运行以下命令以克隆此代码库:
git clone https://github.com/xiangshen-dk/microservices-demo.git
  1. 切换到 microservices-demo 目录:
cd microservices-demo
  1. 使用 kubectl 安装应用:
kubectl apply -f ./release/kubernetes-manifests.yaml
  1. 确认一切正常运行:
kubectl get pods

输出应类似以下内容:

NAME READY STATUS RESTARTS AGE adservice-55f94cfd9c-4lvml 1/1 Running 0 20m cartservice-6f4946f9b8-6wtff 1/1 Running 2 20m checkoutservice-5688779d8c-l6crl 1/1 Running 0 20m currencyservice-665d6f4569-b4sbm 1/1 Running 0 20m emailservice-684c89bcb8-h48sq 1/1 Running 0 20m frontend-67c8475b7d-vktsn 1/1 Running 0 20m loadgenerator-6d646566db-p422w 1/1 Running 0 20m paymentservice-858d89d64c-hmpkg 1/1 Running 0 20m productcatalogservice-bcd85cb5-d6xp4 1/1 Running 0 20m recommendationservice-685d7d6cd9-pxd9g 1/1 Running 0 20m redis-cart-9b864d47f-c9xc6 1/1 Running 0 20m shippingservice-5948f9fb5c-vndcp 1/1 Running 0 20m
  1. 重新运行该命令,直到所有 Pod 都报告 Running 状态,然后再继续执行下一步。

点击“检查我的进度”,验证已完成以下目标: 部署应用

  1. 运行以下命令以获取应用的外部 IP。此命令只有在服务部署完成后才会返回 IP 地址,因此您可能需要重复运行此命令,直到分配了外部 IP 地址:
export EXTERNAL_IP=$(kubectl get service frontend-external | awk 'BEGIN { cnt=0; } { cnt+=1; if (cnt > 1) print $4; }')
  1. 最后,确认应用已启动并正在运行:
curl -o /dev/null -s -w "%{http_code}\n" http://$EXTERNAL_IP

确认信息将类似:

200

应用部署完成后,您还可以前往 Cloud 控制台查看状态。

Kubernetes Engine > 工作负载页面中,您会看到所有 Pod 均正常运行。

工作负载页面

  1. 现在,选择网关、服务和入站流量,然后点击服务标签页,验证所有服务都正常。请停留在该界面,以便为应用设置监控。

任务 3. 打开应用

  1. 向下滚动到 frontend-external,然后点击该服务的端点 IP。

“服务和入站流量”页面,突出显示了前端外部 IP 地址

这应该会打开应用,您将看到如下所示的页面:

显示商品图块的 Online Boutique 网页

任务 4. 创建基于日志的指标

现在,您将配置 Cloud Logging 以创建基于日志的指标,这是 Cloud Monitoring 中根据日志条目创建的自定义指标。基于日志的指标非常适合统计日志条目的数量,以及跟踪日志中某个值的分布情况。在本例中,您将使用基于日志的指标来计算前端服务中的错误数。然后,您可以在信息中心和提醒中使用该指标。

  1. 返回 Cloud 控制台,从导航菜单中打开 Logging,然后点击日志浏览器

“日志浏览器”页面

  1. 启用显示查询,并在查询构建器框中添加以下查询:
resource.type="k8s_container" severity=ERROR labels."k8s-pod/app": "recommendationservice"

查询构建器页面,显示上述查询中的三行代码

  1. 点击运行查询

您使用的查询可让您找到前端 Pod 中的所有错误。不过,由于目前还没有错误,您现在应该看不到任何结果。

  1. 如需创建基于日志的指标,请点击操作下拉菜单,然后选择创建指标

界面上显示的“创建指标”按钮

  1. 将指标命名为 Error_Rate_SLI,然后点击创建指标以保存该基于日志的指标:

“创建日志指标”对话框,其中“日志指标名称”字段已填充

现在,您会看到该指标列在“基于日志的指标”页面上的“用户定义的指标”部分。

点击“检查我的进度”,验证已完成以下目标: 创建基于日志的指标

任务 5. 创建提醒政策

借助提醒,您可以及时得知云端应用中出现的问题,从而快速加以解决。现在,您将使用 Cloud Monitoring 来监控前端服务的可用性,方法是根据之前创建的基于日志的前端错误指标创建提醒政策。当满足提醒政策的条件时,Cloud Monitoring 会在 Cloud 控制台中创建并显示突发事件。

  1. 导航菜单中,打开 Monitoring,然后点击提醒

  2. 工作区创建完成后,点击顶部的创建政策

注意:如果需要,请点击试试看!,以使用更新后的提醒创建流程。
  1. 点击选择指标下拉菜单。取消选中活跃

  2. 按资源和指标名称过滤字段中,输入 Error_Rate

  3. 点击 Kubernetes 容器 > 基于日志的指标。选择 logging/user/Error_Rate_SLI,然后点击应用

您的屏幕应如下所示:

“选择指标”页面

  1. 滚动窗口函数设置为速率

  2. 点击下一步

  3. 0.5 设置为阈值

正如预期的那样,没有出现故障,您的应用达到了可用性服务等级目标 (SLO)。

  1. 再次点击下一步

  2. 停用使用通知渠道

  3. 提供提醒名称,例如 Error Rate SLI,然后点击下一步

  4. 审核该提醒并点击创建政策

注意: 在本实验中,您不会创建通知渠道,但对于在生产环境中运行的应用,您应该创建通知渠道,以便通过电子邮件、移动应用、短信、Pub/Sub 和 webhook 等多种方式发送通知。

点击“检查我的进度”,验证已完成以下目标: 创建提醒政策

触发应用错误

现在,您将使用负载生成器为 Web 应用创建一些流量。由于此版本的应用中故意引入了一个 bug,因此达到一定流量时会触发错误。您将按照步骤找出并修复该 bug。

  1. 导航菜单中,依次选择 Kubernetes Engine网关、服务和入站流量,然后点击服务标签页。

  2. 找到 loadgenerator-external 服务,然后点击端点链接。

“服务和入站流量”页面打开,显示在“服务”标签页页面上,其中突出显示了 loadgenerator-external 服务和端点链接。

或者,您可以打开一个新的浏览器标签页或窗口,将 IP 复制/粘贴到网址字段中,例如:http://\[loadgenerator-external-ip\]

现在,您应该会看到 Locust 负载生成器页面:

Locust 负载生成器页面

Locust 是一款开源负载生成器,可用于对 Web 应用进行负载测试。它可以模拟一定数量的用户以特定速率同时访问某个应用端点。

  1. 模拟 300 位用户以 30 的生成速率访问应用。Locust 将每秒添加 30 个用户,直到达到 300 个用户。

  2. 对于主机字段,您将使用 frontend-external。从“网关、服务和入站流量”页面复制网址,确保不包含端口。例如:

“Start new Locust swarm”(启动新的 Locust Swarm)页面,其中显示了“Start swarming”(开始生成请求)按钮

  1. 点击 Start swarming(开始生成请求)按钮。在几秒钟内,您应该会有大约 300 个用户访问该预定义的网址。

显示 300 位用户列表的“统计信息”页面

  1. 点击失败标签页,查看是否开始出现失败。可以看到,有大量的 500 错误。

“失败”标签页页面

同时,如果您点击首页上的任何商品,要么速度明显很慢,要么会收到如下错误:

Online Boutique 显示 HTTP 状态错误:500 内部服务器错误。

确认提醒和应用错误

  1. 在控制台中,从导航菜单中依次点击 Monitoring提醒。您很快就会看到与 logging/user/Error_Rate_SLI 相关的突发事件。如果您没有立即看到突发事件,请等待一两分钟,然后刷新页面。提醒最多可能需要 5 分钟才会触发。

  2. 点击突发事件的链接:

“提醒”页面,其中“突发事件”部分显示了突发事件链接

您随即会进入详情页面。

  1. 在“日志”部分,点击在 Logs Explorer 中查看,然后从下拉菜单中选择项目 ID,以查看 Pod 日志。

“突发事件指标”页面,其中突出显示了“查看日志”按钮

  1. 您还可以点击“日志字段浏览器”面板中的 Error(错误)标签,仅查询错误。

或者,您可以点击“查询预览”字段以显示查询构建器,然后点击严重级别下拉菜单,将错误添加到查询中。点击添加按钮,然后点击运行查询。通过下拉菜单可以添加多个严重级别值。

无论哪种方式,结果都是在查询中添加 severity=ERROR。完成此操作后,您应该会看到 recommendationservice Pod 的所有错误。

Logs Explorer 页面打开,显示“查询构建器”标签页页面,并在“查询结果”部分显示错误列表

  1. 展开错误事件,查看错误详情。例如:

展开的“连接失败”查询结果

  1. 展开 textPayload

  2. 点击错误消息,然后选择向摘要行添加字段,将错误消息显示为摘要字段:

展开的错误消息菜单中突出显示了“向摘要行添加字段”选项

从那里,您可以确认 RecommendationService 服务确实存在许多错误。根据错误消息,RecommendationService 似乎无法连接到某些下游服务来获取商品或推荐。不过,我们仍然不清楚这些错误的根本原因。

如果您重新查看架构图,会发现 RecommendationServiceFrontend 服务提供建议列表。不过,Frontend 服务和 RecommendationService 都会调用 ProductCatalogService 来获取产品列表。

架构图,其中突出显示了 ProductCatalogService 和 RecomendationService 类别。

接下来,您将查看主要嫌疑对象 ProductCatalogService 的指标,以查找任何异常情况。无论如何,您都可以在日志中深入挖掘,以获得一些分析洞见。

使用 Kubernetes 信息中心和日志进行问题排查

  1. 首先,您可以在 Monitoring 控制台的 Kubernetes Engine 部分查看指标(导航菜单 > 监控> 信息中心 > GKE)。

  2. 查看工作负载部分。

  3. 依次前往 Kubernetes Engine > 工作负载 > productcatalogservice。您可以看到,该服务的 Pod 不断崩溃并重新启动。

Deployment 详情页面上突出显示的“有效修订版本”部分

接下来,看看日志中是否有任何值得注意的内容。

您可以通过以下两种方式轻松获取容器日志:

  1. 点击日志标签页,快速查看最新日志。接下来,点击日志面板右上角的外部链接按钮,返回 Logs Explorer。

“日志”标签页页面

  1. 在概览页面中,点击“部署详情”页面上的容器日志链接。

“部署详情”页面上突出显示的“容器日志”链接

您再次进入 Logs Explorer 页面,现在页面上有一个预定义的查询,专门用于过滤您在 GKE 中查看的容器的日志。

从日志查看器中,日志消息和直方图都显示容器在短时间内重复解析商品目录。这似乎非常低效。

在查询结果的底部,可能还会出现如下所示的运行时错误:

panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation

这可能实际上导致了 Pod 崩溃。

为了更好地了解原因,在代码中搜索日志消息。

  1. 在 Cloud Shell 中,运行以下命令:
grep -nri 'successfully parsed product catalog json' src

输出应如下所示,其中包含源文件名和行号:

src/productcatalogservice/server.go:237: log.Info("successfully parsed product catalog json")
  1. 如需查看源文件,点击 Cloud Shell 菜单中的打开编辑器按钮,然后点击在新窗口中打开(如果您看到“由于第三方 Cookie 已停用,无法加载代码编辑器”错误,请点击 Chrome 页面顶部的眼睛图标)。

界面中突出显示的“打开编辑器”按钮

  1. 点击文件 microservices-demo/src/productcatalogservice/server.go,向下滚动到第 237 行,您会发现 readCatalogFile 方法记录了以下消息:

The message: log.Info(&quot;successfully parsed product catalog json&quot;) return nil

再仔细检查,你会发现,如果布尔值变量 reloadCatalog 为 true,则每次调用服务时,服务都会重新加载并解析产品目录,这似乎没有必要。

在代码中搜索 reloadCatalog 变量,您可以看到它由环境变量 ENABLE_RELOAD 控制,并为其状态写入一条日志消息。

reloadCatalog 状态的日志消息

将此消息添加到查询中,再次检查日志,确定是否存在任何相关条目。

  1. 返回打开了 Logs Explorer 的标签页,并将以下代码行添加到查询中:
jsonPayload.message:"catalog reloading"

这样,查询构建器中的完整查询如下:

resource.type="k8s_container" resource.labels.location="{{{project_0.startup_script.zone | ZONE}}}" resource.labels.cluster_name="central" resource.labels.namespace_name="default" labels.k8s-pod/app="productcatalogservice" jsonPayload.message:"catalog reloading"
  1. 再次点击运行查询,在容器日志中找到“Enable catalog reloading”(启用目录重新加载)消息。这确认了目录重新加载功能已启用。

容器日志中的“启用目录重新加载”消息

至此,您可以确定前端错误是由于每次请求都加载目录而造成的开销所致。当您增加负载时,该开销导致服务失败并生成错误。

任务 6. 修复问题并验证结果

根据代码和日志中显示的内容,您可以尝试通过停用目录重新加载来修复此问题。现在,您将移除商品目录服务的 ENABLE_RELOAD 环境变量。完成变量更改后,您可以重新部署应用,验证更改是否解决了观察到的问题。

  1. 如果 Cloud Shell 终端已关闭,点击打开终端按钮以返回该终端。

  2. 运行以下命令:

grep -A1 -ni ENABLE_RELOAD release/kubernetes-manifests.yaml

输出将显示清单文件中环境变量的行号:

373: - name: ENABLE_RELOAD 374- value: "1"
  1. 运行以下命令,删除这两行代码以停用重新加载:
sed -i -e '373,374d' release/kubernetes-manifests.yaml
  1. 然后重新应用清单文件:
kubectl apply -f ./release/kubernetes-manifests.yaml

您会注意到,只有 productcatalogservice 得到配置。其他服务保持不变。

  1. 返回到 Deployment 详情页面(导航菜单 > Kubernetes Engine > 工作负载 > productcatalogservice),并等待 Pod 成功运行。等待 2-3 分钟,或直到确认应用不再崩溃。

“Deployment 详情”页面,其中突出显示了“有效修订版本”部分

  1. 如果您再次点击容器日志链接,您会发现重复的 successfully parsing the catalog json 消息已消失:

“查询构建器”页面

  1. 如果您返回到 Web 应用网址并点击首页上的商品,会发现响应速度也快了很多,并且不会遇到任何 HTTP 错误。

  2. 返回负载生成器,点击右上角的重置统计信息按钮。失败百分比已重置,您应该不会再看到它增加。

显示 0% 的失败百分比

上述所有检查都表明问题已得到解决。如果您仍然看到 500 错误,请再等待几分钟,然后再次点击产品。

恭喜!

您使用 Cloud Logging 和 Cloud Monitoring 在故意包含配置错误的微服务演示应用版本中找到了一个错误。这与您在生产环境中缩小 GKE 应用问题范围时使用的故障排除流程类似。

首先,您将应用部署到 GKE,然后为前端错误设置了指标和提醒。接下来,您生成了负载,然后注意到提醒被触发。根据提醒,您使用 Cloud Logging 将问题范围缩小到特定服务。然后,您使用 Cloud Monitoring 和 GKE 界面查看了 GKE 服务的指标。为了解决此问题,您将更新后的配置部署到 GKE,并确认该修复解决了日志中的错误。

后续步骤/了解详情

  • 本实验基于这篇博文,其中介绍了如何使用 Logging 来记录在 GKE 上运行的应用的日志。
  • 您可能还会对后续博文感兴趣,该博文介绍了 DevOps 团队如何使用 Cloud Monitoring 和 Logging 快速查找问题。

Google Cloud 培训和认证

…可帮助您充分利用 Google Cloud 技术。我们的课程会讲解各项技能与最佳实践,可帮助您迅速上手使用并继续学习更深入的知识。我们提供从基础到高级的全方位培训,并有点播、直播和虚拟三种方式选择,让您可以按照自己的日程安排学习时间。各项认证可以帮助您核实并证明您在 Google Cloud 技术方面的技能与专业知识。

上次更新手册的时间:2025 年 2 月 21 日

上次测试实验的时间:2025 年 2 月 21 日

版权所有 2025 Google LLC 保留所有权利。Google 和 Google 徽标是 Google LLC 的商标。其他所有公司名和产品名可能是其各自相关公司的商标。

准备工作

  1. 实验会创建一个 Google Cloud 项目和一些资源,供您使用限定的一段时间
  2. 实验有时间限制,并且没有暂停功能。如果您中途结束实验,则必须重新开始。
  3. 在屏幕左上角,点击开始实验即可开始

使用无痕浏览模式

  1. 复制系统为实验提供的用户名密码
  2. 在无痕浏览模式下,点击打开控制台

登录控制台

  1. 使用您的实验凭证登录。使用其他凭证可能会导致错误或产生费用。
  2. 接受条款,并跳过恢复资源页面
  3. 除非您已完成此实验或想要重新开始,否则请勿点击结束实验,因为点击后系统会清除您的工作并移除该项目

此内容目前不可用

一旦可用,我们会通过电子邮件告知您

太好了!

一旦可用,我们会通过电子邮件告知您

一次一个实验

确认结束所有现有实验并开始此实验

使用无痕浏览模式运行实验

请使用无痕模式或无痕式浏览器窗口运行此实验。这可以避免您的个人账号与学生账号之间发生冲突,这种冲突可能导致您的个人账号产生额外费用。