8.3 K8s 生产运维:HPA 与 VPA 弹性伸缩

预计阅读时间:15 分钟

📖 目录

弹性伸缩是 Kubernetes 的核心优势之一。Horizontal Pod Autoscaler(HPA)根据 CPU/内存或自定义指标自动调整 Pod 副本数,Vertical Pod Autoscaler(VPA)调整 Pod 的资源请求和限制。

学习目标

  • 理解 HPA 与 VPA 的工作原理、适用场景及限制条件
  • 能够配置基于 CPU、内存和自定义指标的 HPA 策略
  • 掌握 HPA 行为配置(behavior)实现精细化扩缩容控制
  • 了解 VPA 的三种更新模式及其在生产环境中的使用策略

前置知识

  • 熟悉 Kubernetes Pod、Deployment、ReplicaSet 的基本概念
  • 了解 Kubernetes 资源请求(requests)与限制(limits)的含义
  • 具备 Prometheus 指标采集与查询基础(用于自定义指标 HPA)
  • 了解 kubectl top 命令及 Metrics Server 的作用

HPA 水平自动扩缩

工作原理

HPA 定期(默认 15 秒)从 Metrics Server 或 Prometheus 读取指标,计算目标副本数:desiredReplicas = ceil[currentReplicas * (currentMetricValue / desiredMetricValue)]

例如:当前 CPU 使用率 80%,目标 40%,当前 5 个 Pod,则 desiredReplicas = ceil[5 * (80/40)] = 10。HPA 会将副本数从 5 扩展到 10。

HPA 控制器的工作流程

  1. 每隔 --horizontal-pod-autoscaler-sync-period(默认 15 秒)拉取指标
  2. 根据 metrics 和当前副本数计算期望副本数
  3. 如果期望副本数与当前副本数不同,触发扩缩容操作
  4. 扩缩容操作通过调整 Deployment/ReplicaSet 的 spec.replicas 实现

前提条件:安装 Metrics Server

# 安装 Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 如果使用自签名证书,需要添加 --kubelet-insecure-tls 参数
kubectl patch deployment metrics-server -n kube-system --type='json' -p='[
  {"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}
]'

# 验证
kubectl top nodes
kubectl top pods -n default

# 查看 Metrics Server 状态
kubectl get deployment metrics-server -n kube-system

1. 基于 CPU 的 HPA

# 创建 HPA(基于 CPU 使用率)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: webapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: webapp
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70  # CPU 使用率目标 70%

2. 基于内存的 HPA

# 基于内存(注意:内存使用率不会随负载降低而下降)
# 适合缓存类应用
spec:
  metrics:
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

3. 基于自定义指标(Prometheus)

需要 Prometheus Adapter 或 KEDA:

# KEDA 方式(推荐)
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: queue-worker-scaler
spec:
  scaleTargetRef:
    name: queue-worker
  minReplicaCount: 1
  maxReplicaCount: 20
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus.monitoring:9090
      query: |
        sum(rate(rabbitmq_queue_messages_total{queue="work"}[2m]))
      threshold: "100"
  # KEDA 还支持多种触发器类型
  # - type: kafka          (Kafka 消费者组 lag)
  # - type: redis-streams  (Redis Stream 长度)
  # - type: cron           (定时触发)
  # - type: http           (HTTP 请求速率)

4. 基于多项指标的 HPA

spec:
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        type: AverageValue
        averageValue: 1000
  # 取所有指标计算结果的最大值

HPA 行为配置(1.23+)

spec:
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # 缩容稳定窗口(5 分钟)
      policies:
      - type: Percent
        value: 10
        periodSeconds: 60     # 每分钟最多缩 10%
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
      - type: Pods
        value: 4
        periodSeconds: 60     # 每分钟最多扩 4 个 Pod
      - type: Percent
        value: 100
        periodSeconds: 60
        selectPolicy: Max     # 取两个策略中的较大值

行为配置详解

字段说明推荐值
stabilizationWindowSeconds扩缩容后的稳定窗口期,防止频繁抖动扩容 0-60s,缩容 300s
policies[].typePods(固定数量)或 Percent(百分比)扩容用 Percent,缩容用 Pods
policies[].value每次允许变化的最大值扩容 100%,缩容 10%
policies[].periodSeconds策略评估周期(秒)60s
selectPolicy多策略时的选择方式:Max(取大)、Min(取小)、DisabledMax

VPA 垂直自动扩缩

VPA 自动调整 Pod 的 CPU/内存 requests 和 limits。更适用于无法水平扩展的有状态应用(如数据库)。

# 安装 VPA(使用官方清单)
git clone https://github.com/kubernetes/autoscaler.git
kubectl apply -k autoscaler/vertical-pod-autoscaler/deploy/

# VPA 配置示例
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: mysql-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: StatefulSet
    name: mysql
  updatePolicy:
    updateMode: "Auto"  # Auto/Initial/Off
  resourcePolicy:
    containerPolicies:
    - containerName: "*"
      minAllowed:
        cpu: "250m"
        memory: "512Mi"
      maxAllowed:
        cpu: "4"
        memory: "16Gi"

VPA 更新模式

模式行为适用场景
Off仅提供建议,不自动变更先观察建议值
Initial只在创建时应用建议无状态应用
Auto自动更新并重启 Pod可接受重启的应用

VPA 组件说明

  • VPA Recommender:分析历史资源使用数据,给出资源建议值
  • VPA Updater:根据建议值删除 Pod 以触发重新调度(仅 Auto 模式)
  • VPA Admission Controller:在 Pod 创建时注入资源 requests(Auto/Initial 模式)

VPA 资源策略配置

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Off"  # 先用 Off 模式观察
  resourcePolicy:
    containerPolicies:
    - containerName: "app"
      # 允许 VPA 调整的资源类型
      controlledResources: ["cpu", "memory"]
      # 是否控制 limits
      controlledValues: RequestsAndLimits
      minAllowed:
        cpu: "100m"
        memory: "128Mi"
      maxAllowed:
        cpu: "2"
        memory: "8Gi"
    - containerName: "sidecar"
      mode: "Off"  # 不对 sidecar 容器做调整

HPA vs VPA 对比与配合

维度HPAVPA
调整方式改变 Pod 数量改变单个 Pod 资源
响应速度快(15 秒检测周期)慢(需要重启 Pod)
适用业务无状态应用有状态应用
兼容性Metrics Server / Prometheus需 VPA Recommender
资源浪费扩缩期间可能有资源闲置单 Pod 资源利用率高
运维复杂度中(需要重启)

推荐策略:先用 VPA 的推荐模式(updateMode: Off)观察数天确定基线资源,然后设置合理的 requests,再用 HPA 做水平伸缩。HPA 和 VPA 不要同时作用于同一个 Deployment。

测试 HPA 效果

# 部署一个消耗 CPU 的应用
kubectl create deployment php-apache --image=php:7.4-apache
kubectl expose deployment php-apache --port=80

# 部署 HPA
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10

# 使用压测工具生成负载
kubectl run -it --rm load-test --image=busybox -- sh
# 在容器内
while true; do wget -q -O- http://php-apache; done

# 观察 HPA 响应
kubectl get hpa -w

# 查看 HPA 详细信息
kubectl describe hpa php-apache

# 停止测试后,HPA 会逐步缩容

HPA 算法与计算细节

官网对 HPA 的算法描述是:desiredReplicas = ceil[currentReplicas * (currentMetricValue / desiredMetricValue)],但落到具体实现上有几个关键细节,理解了才不会在压测时"看不懂 HPA 的行为":

  • 利用率口径:CPU 利用率 = Pod 当前 CPU / Pod 的 requests.cpu。容器没写 requests 时该 Pod 不参与计算(HPA 会直接报 unable to fetch)
  • 取均值:对多个 Pod 的指标值取算术平均(平均值按副本数加权),再与目标值比较
  • 多指标取最大值:配置多个 metrics 时,每个指标独立算出 desiredReplicas,取其中最大值作为最终目标
  • 向下取整边界:计算出的目标副本数在 minReplicas 与 maxReplicas 之间裁剪;currentMetricValue / desiredMetricValue 小于 0.9(缩容 10% 以上)才触发缩容计算,避免微小波动导致抖动
  • 容忍度:HPA 控制器对比值在 0.9-1.1 之间的波动不做任何操作,这是防抖的第一道防线
  • 副本数为 0 的集群:HPA 不能从 0 扩到 1,也不建议对缩到 0 的场景使用 HPA(应使用 KEDA 的 scale-to-zero)
# 手动推算示例(CPU 目标 50%)
# 当前:3 个副本,实际使用 1.2 核,requests 各 1 核
# 利用率 = (1.2 / 3) / 1 * 100% = 40%
# 比值 = 40 / 50 = 0.8(小于 0.9,触发缩容计算)
# desiredReplicas = ceil(3 * 0.8) = 3(无变化,因为比例不足 10%)

# 当前:3 个副本,实际使用 2.1 核
# 利用率 = (2.1 / 3) / 1 * 100% = 70%
# 比值 = 70 / 50 = 1.4
# desiredReplicas = ceil(3 * 1.4) = 5(扩容到 5)

# 查看 HPA 的决策过程(status 字段会显示每一步)
kubectl describe hpa webapp-hpa
# 关注 Conditions 里的 AbleToScale / ScalingActive / ScalingLimited

指标不可用时的行为

当 HPA 连续 2 分钟无法获取指标(Metrics Server 宕机、Pod 重启)时,控制器进入"延迟模式":暂停所有扩缩容决策,直到指标恢复。这在故障排查中很容易被误判为"HPA 失灵"——实际它是刻意保护,避免在无数据时做出错误决策。

Metrics Server 原理

Metrics Server 是 CPU/内存 HPA 的数据来源,理解它的工作链路是排障的前提:

  1. Metrics Server 每隔 15s(--metric-resolution)向每个节点的 kubelet 请求 /metrics/resource 端点
  2. kubelet 通过 cAdvisor 采集容器实际使用量(来自 cgroup 统计),并按"Pod 实际使用 vs requests"返回
  3. Metrics Server 把结果聚合并暴露为 metrics.k8s.io API,注册到 API Server 的聚合层(aggregation layer)
  4. HPA 控制器通过 /apis/metrics.k8s.io/v1beta1 读取指标
现象可能断点
kubectl top nodes 无输出kubelet 指标端口不可达 / cAdvisor 异常
kubectl top pods 有节点没 PodMetrics Server 对 Pod 的 label selector 匹配失败
HPA 报 unable to fetch metricsmetrics-server 未注册到聚合层 / 证书不信任(--kubelet-insecure-tls 场景)
# 排障 Metrics Server
kubectl -n kube-system logs -l k8s-app=metrics-server --tail=50
kubectl -n kube-system describe pod -l k8s-app=metrics-server
# 直接请求聚合层(验证 API 注册)
kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes | jq
# 检查 kubelet 的容器指标是否正常
curl -k -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
  https://$(hostname):10250/metrics/resource 2>/dev/null | head -5
Metrics Server 的边界 它只提供 CPU/内存两项资源指标,且数据仅保留约 1 分钟(滚动窗口)。自定义指标(QPS、队列长度)必须走 custom.metrics.k8s.io 或 external.metrics.k8s.io——这就是需要 Prometheus Adapter 或 KEDA 的原因。

自定义指标体系详解

K8s 的指标 API 分四个层,HPA 可以消费其中三种:

API 组指标来源典型用途
metrics.k8s.ioMetrics ServerCPU / 内存利用率
custom.metrics.k8s.ioPrometheus Adapter / 自定义收集器单 Pod 或整个资源的自定义指标(QPS、连接数)
external.metrics.k8s.io云厂商 / 外部系统集群外部指标(SQS 队列长度、CloudWatch 指标)
# Prometheus Adapter 配置:把 HTTP 请求速率暴露为 custom 指标
# adapter-config.yaml
rules:
- seriesQuery: 'http_requests_total{namespace!="",pod!=""}'
  resources:
    overrides:
      namespace: {resource: namespace}
      pod: {resource: pod}
  name:
    matches: "^(.*)_total"
    as: "${1}_per_second"
  metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'

# 部署 Prometheus Adapter
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus-adapter prometheus-community/prometheus-adapter \
  --namespace monitoring --create-namespace \
  --set prometheus.url=http://prometheus.monitoring:9090 \
  -f adapter-config.yaml

# 验证指标暴露
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq .resources
# 查询某个 Pod 的 http_requests_per_second
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second" | jq
KEDA vs Prometheus Adapter 怎么选 已经有 Prometheus 且指标查询稳定 → Prometheus Adapter(HPA 原生语义);需要消息队列/事件/定时等 50+ 种触发器、要 scale-to-zero → KEDA。KEDA 底层也是把触发器换算成 HPA,只是多了一个"触发器 → 指标"的转换层。

扩缩容测试场景设计

光配置不验证等于没配置。生产级验证至少要覆盖三类场景:

场景一:CPU 突发扩容

# 用 hey 生成瞬时高并发
kubectl run loadgen --image=williamyeh/hey --restart=Never -- \
  -z 5m -c 200 -q 50 http://webapp.default.svc:8080/api

# 观察时间线(应看到 1-2 个同步周期内完成扩容)
kubectl get hpa webapp-hpa -w
kubectl get pods -l app=webapp -w

场景二:内存增长扩容(缓存类应用)

# 在应用内注入内存占用(如 Redis 的 DEBUG JMAP 或自定义压测脚本)
# 内存指标的特点:扩容触发快,但缩容几乎不会发生
# 因为内存使用率不会随流量下降而下降——这是设计行为,不是 bug
# 验证时注意:缩容只可能在内存真正释放后发生

场景三:自定义指标(队列深度)

# 向 RabbitMQ 灌入消息,观察消费者 Pod 数量是否随队列深度变化
# 配合 KEDA 的 cooldownPeriod(默认 300s),消息清空后不会立刻缩容
kubectl get scaledobject worker-scaler -o yaml | grep -E "cooldown|polling"
# 观察指标
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1" | jq .

测试验收清单

  • 扩容时延:从负载上升到副本数达到目标 ≤ 3 个同步周期(45s)
  • 扩容速率符合 behavior.scaleUp 策略(不被 selectPolicy 卡住)
  • 缩容时延:负载消失后,副本数回到 minReplicas 的时间符合 stabilizationWindow 设计
  • 全程无 5xx:扩容期间流量不中断(应用需正确处理扩容时序,勿在启动时拒绝流量)

HPA 与 Cluster Autoscaler 的配合

HPA 扩容的终点是集群容量:节点资源不足时,新 Pod 只能 Pending。Cluster Autoscaler(CA)负责补齐节点,两者配合的时序是:

  1. 负载上升 → HPA 在 15s 内扩容副本数
  2. Pod 进入 Pending(节点资源不足)→ CA 检测到"无法调度的 Pod"(默认 10s 检查一次)
  3. CA 扩容节点(云厂商虚拟机,通常 3-10 分钟)
  4. Pod 调度到新节点,HPA 维持副本数
# 观察 Pending Pod(扩容延迟的根源)
kubectl get pods -o wide | grep Pending
kubectl describe pod <pending-pod> | grep -A 5 Events

# CA 日志(确认扩容决策)
kubectl -n kube-system logs -l app=cluster-autoscaler --tail=100 | grep "scale-up"

# 关键配置:给节点池设置合理的 min/max,防止 CA 无限扩容
# 并通过 CA 的 --max-nodes-total 设置集群级上限
联动经验 虚拟机扩容需要分钟级时间,纯靠 CA 兜底无法应对秒级流量尖峰。生产实践是"预留 20-30% 节点余量 + HPA 快速扩缩 + CA 只做长期容量调整",而不是把 CA 当作即时扩容手段。

扩缩容场景模式库

不同业务形态适合不同的扩缩容策略,把常见场景沉淀为可复用的模式,比每次临时配参数靠谱:

业务形态推荐指标行为配置要点典型应用
请求驱动型CPU / HTTP QPS扩容快(0s 稳定窗口 + 100% 速率)、缩容慢(300s+)Web 服务、API 网关
队列消费型队列深度(KEDA)按消息积压扩容,cooldown 防抖异步任务、批处理 worker
内存敏感型内存利用率只扩不缩(或极慢缩容),防 OOM缓存、流计算
定时突发型cron 触发器(KEDA)提前扩容、事后缓慢缩容日报生成、定时报表
有状态型VPA 推荐 + 手动评估不用 HPA(副本数由分片决定)数据库、消息中间件

模式一:Web 服务的标准配置

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: webapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: webapp
  minReplicas: 3
  maxReplicas: 30
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 0     # 扩容不设稳定窗口
      policies:
      - type: Percent
        value: 100
        periodSeconds: 15                # 每 15s 最多翻倍
    scaleDown:
      stabilizationWindowSeconds: 300    # 缩容观察 5 分钟
      policies:
      - type: Pods
        value: 2
        periodSeconds: 60                # 每分钟最多缩 2 个

模式二:队列消费型(KEDA)

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: worker-scaler
spec:
  scaleTargetRef:
    name: worker-deployment
  pollingInterval: 10          # 每 10s 查一次队列深度
  cooldownPeriod: 180          # 队列清空后 3 分钟才开始缩容
  minReplicaCount: 1
  maxReplicaCount: 20
  triggers:
  - type: rabbitmq
    metadata:
      queueName: work-queue
      queueLength: "20"        # 每积压 20 条消息加一个副本
  advanced:
    horizontalPodAutoscalerConfig:
      behavior:
        scaleDown:
          stabilizationWindowSeconds: 600
参数从哪里来 模式里的数字不是拍脑袋:先用压测确认"单副本处理能力"(如 100 QPS),再反推目标值(60% CPU = 该副本还有 40% 余量应对突发),最后用两周的真实负载曲线校验抖动情况。

常见错误

问题原因解决方案
HPA 显示 "unable to fetch metrics"Metrics Server 未安装或无法连接确认 kubectl top nodes 能正常返回,检查 Metrics Server Pod 日志
HPA 不扩容Pod 未设置 resource requests确保 Deployment 中每个容器都设置了 resources.requests.cpu
HPA 频繁抖动缩容稳定窗口太短增大 stabilizationWindowSeconds 到 300s 以上
VPA 删除 Pod 但新 Pod 资源未变VPA Admission Controller 未正确配置检查 kubectl get pods -n kube-system | grep vpa,确认 Admission Controller 正常运行
VPA 建议值异常高历史数据不足或应用有突发流量等待 7-14 天积累足够数据,或手动设置 maxAllowed 上限

最佳实践

  • HPA 结合 PodDisruptionBudget 实现优雅缩容
  • 缩容时设置 stabilizationWindowSeconds 避免抖动
  • 数据类应用(消息队列、缓存)优先用自定义指标
  • VPA 的 maxAllowed 一定要设,防止意外申请过量资源
  • 配合 Cluster Autoscaler 实现集群级别的弹性伸缩
  • 生产环境建议先用 VPA Off 模式观察 1-2 周,确定基线后再启用 HPA
  • 为 HPA 配置合理的 minReplicas,避免流量突增时扩容不及时

练习题

  1. HPA 配置:为一个 Nginx Deployment 创建 HPA 配置,要求:CPU 使用率目标 60%,最小 3 个 Pod,最大 15 个 Pod。配置扩缩容行为:扩容时每分钟最多扩 50%,缩容时每 5 分钟最多缩 2 个 Pod。使用压测工具验证 HPA 行为符合预期。
  2. VPA 观察:安装 VPA 并为一个测试应用创建 VPA(updateMode: Off),观察 7 天后获取推荐的 CPU 和 memory 值。将推荐值与你手动设置的 requests 进行对比,分析差异原因。
  3. 混合伸缩场景:设计一个包含 HPA、VPA 和 Cluster Autoscaler 的完整伸缩方案。说明三者的协作关系:HPA 负责 Pod 级别伸缩,VPA 负责资源推荐,Cluster Autoscaler 负责节点级别伸缩。画出决策流程图。

学习检查点

学完本章后,请检验自己是否掌握以下内容:

检查项自测问题验证方法
概念理解能用自己的话解释 HPA 和 VPA 的工作原理和指标来源尝试向他人讲解
命令操作能不查文档完成 HPA 配置和自定义指标适配在终端实际执行
原理掌握能说出 HPA 的算法原理和 VPA 的推荐机制画出流程图
故障排查能独立排查 HPA 不触发或副本数震荡的问题模拟故障并修复
最佳实践能说明为什么需要为应用配置资源请求和限制对比不同方案

KEDA 安装示例

# 通过 Helm 安装 KEDA
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --namespace keda --create-namespace

# 验证安装
kubectl get pods -n keda

# KEDA ScaledObject 示例(基于 RabbitMQ 队列深度)
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: worker-scaler
spec:
  scaleTargetRef:
    name: worker-deployment
  pollingInterval: 15
  cooldownPeriod: 300
  minReplicaCount: 1
  maxReplicaCount: 20
  triggers:
  - type: rabbitmq
    metadata:
      host: amqp://rabbitmq.default.svc:5672
      queueName: work-queue
      queueLength: "50"

本章总结

HPA 与 VPA 解决不同维度的问题:HPA 水平调整副本数、响应快,适合无状态应用;VPA 垂直调整单 Pod 资源、需重启,适合有状态应用——两者不应同时作用于同一 Deployment。生产推荐先以 VPA Off 模式观察 1-2 周确定资源基线,再配置 HPA 的行为参数(稳定窗口、扩缩容速率),并基于真实负载压测验证效果,而不是拍脑袋定阈值。

延伸阅读

  • 6.2:Kubernetes 入门 Kubernetes 容器编排入门——Pod 与 Deployment
  • 3.12:系统监控与告警 系统监控与告警——Prometheus 指标采集
  • Kubernetes HPA 官方文档:https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscaler/
  • KEDA 官方文档:https://keda.sh/docs/latest/
  • Cluster Autoscaler:https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler
↑ 回到顶部