← 返回资讯

RunPod Serverless 部署推理服务:冷启动、并发与 Worker 伸缩

2026-09-15

把一个已经在 GPU 机器上跑通的推理服务搬到 Serverless 上,最容易出现的落差是这样的:本地测试一切正常,镜像也推上去了,端点建好,点一下测试请求——等了十几秒才出结果。再等半小时没人调用,第二个请求又是十几秒。更让人意外的是过了一两周回头看,端点的最大 Worker 数变成了一个很小的值,谁也没改过它。

这两件事都不是 bug,都是 Serverless 这套形态自带的行为,而且官方文档里都写了。问题在于它们分散在不同的页面里:冷启动在概述页,自动缩容在端点设置页和排错页,Worker 的计费口径在 Worker 概述页的一张表里。等你上线以后一件一件撞上去,代价就是返工。下面按「先搞清结构、再搞清时间、最后搞清钱和失败」的顺序捋一遍,全部依据 RunPod 官方文档的口径,凡是具体金额、并发上限、默认超时时长这类会变的数值一律只讲机制不抄数字——这类值以控制台当时显示和官方文档为准。RunPod 平台整体的两种交付形态(Pod 与 Serverless)怎么选,那是另一篇的事:RunPod 是什么

一、Endpoint、Worker、Handler:三层各管一件事

文档把 Serverless 拆成三个概念,搞混任意两个都会在配置阶段迷路。

Endpoint(端点)是对外的入口。部署完成之后你会拿到一个形如 https://api.runpod.ai/v2/{endpoint_id}/ 的地址,客户端所有请求都打到它上面。端点这一层承载的是配置:用哪一档 GPU、最多能起多少 Worker、伸缩按什么策略、超时怎么设、要不要挂网络卷。同一个镜像可以建多个端点,配不同的算力和伸缩参数,这是做灰度和分流的常用手法。

**Worker(工作者)**是真正执行代码的容器实例,跑的就是你自己的镜像。它的生命周期不由你控制——RunPod 在需要时启动它、空闲时关掉它。你能控制的只有边界条件(最少几个、最多几个、空闲多久关)。这一点心智上要转过来:你不是在管机器,你是在管一条「什么条件下允许有多少机器」的规则。

**Handler(处理函数)**定义一个 Worker 怎么处理单个请求。文档给的骨架很短,import runpod 和最后的 runpod.serverless.start() 都标着 Required:

import runpod  # Required

def handler(event):
    # Extract input data from the request
    input_data = event["input"]

    # Process the input (replace this with your own code)
    result = process_data(input_data)

    # Return the result
    return result

runpod.serverless.start({"handler": handler})  # Required

传进 Handler 的 job 对象里有两个关键字段:id 是 RunPod 随机生成的任务唯一标识,input 是客户端发来的载荷。文档给了一条容易被忽略的最佳实践——模型和其他重资源要在 Handler 外面加载,不要写在函数体里。写在里面等于每个请求都重新加载一遍模型,这是排错页里点名的「冷启动慢」的常见自造原因之一。文档的正反例摆得很直白:模块级 model = load_model() 是好的,Handler 内部 model = load_model() 后面跟一句注释 # Slow!

Handler 本身有几种形态:标准同步型;流式型(用 yield 逐段吐结果,默认只能从 /stream 取,加 return_aggregate_stream: True 才能从 /run/runsync 拿到聚合结果);异步型(async defyield);以及并发型。并发型是用 runpod.serverless.start() 里的 concurrency_modifier 参数注册一个函数,由它根据当前并发水平返回新的并发水平,让一个 Worker 同时处理多个请求。文档说这适合那些「小而快、吃不满 GPU」的任务,同时提醒要盯内存、要做好单个请求失败不影响其他请求的错误处理。还有一条行为值得记住:并发处理时单个任务的过期、超时或取消只会停掉那一个任务,兄弟任务继续跑,这是自动的不用改代码;但如果你的异步 Handler 需要在被停掉时释放资源,得捕获 asyncio.CancelledError、清理完再重新抛出去,否则任务状态标不对。

二、队列型与负载均衡型:文档自己用了 TCP 和 UDP 打比方

这是本文里最值得先定下来的一个选择,因为它决定了你要不要写 Handler。

队列型端点(也叫传统端点):请求先进队列,按序被取走处理。访问路径是固定的 /run/runsync 这些。文档对它的定位是「保证执行」,并明确类比成 TCP 保证包投递。它自带失败自动重试。

负载均衡型端点:请求直接路由到可用的 Worker,不经过队列。你不写 Handler,而是自己起一个 HTTP 服务——FastAPI、Flask 都行,自己定义 URL 路径和 API 契约,地址形如 https://ENDPOINT_ID.api.runpod.ai/YOUR_CUSTOM_PATH。文档把它类比成 UDP:延迟更低(单跳),但过载时是丢请求,不是排队,也没有内置重试。

文档给的对照维度可以直接当判据用:请求流向(经队列还是直达 Worker HTTP 服务)、实现方式(Handler 还是自建 HTTP 服务)、API 灵活度(固定路径还是自定义路径)、背压行为(队列缓冲还是过载丢弃)、延迟、错误处理(自动重试还是没有)。

具体该选哪个,文档两边都列了适用条件。倾向队列型的信号是:任务本身跑得久(文档直接说负载均衡不适合长任务,会超时或被丢)、要求每个请求都必须被处理、批量离线任务(夜间跑数据集、预算 embedding、跑评测)、想要不写客户端逻辑就有自动重试。倾向负载均衡型的信号是:需要直连模型自己的 HTTP 服务、推理引擎内部自带批处理(文档点名 vLLM 这种自己管 batching 的)、载荷不是 JSON(二进制、multipart 上传)、一个 Worker 里要暴露多个路径、以及低延迟的实时请求响应。

负载均衡型还有一套单独的健康检查机制,这部分是队列型没有的。每个 Worker 在 PORT_HEALTH 端口上暴露健康检查路径,负载均衡器定期轮询它来决定要不要给这个 Worker 派流量。默认轮询 /ping,但可以用 HEALTH_CHECK_PATH 环境变量改成别的——文档举的例子是某些公共镜像自带的健康检查在 /health,改个变量就不用为了这一件事重新打镜像。响应码的含义是固定的三档:200 表示健康,204 表示还在初始化,其他一律算不健康并被摘出路由池。顺带一个有意思的实现细节:负载均衡端点的冷启动时间指标,官方是按「健康检查第一次返回 204 到第一次返回 200」这段时间算的。

排错页里还有一条几乎必踩的配置错误:如果 HTTP 服务绑在 127.0.0.1 而不是 0.0.0.0,或者端口跟配置对不上,请求就到不了 Worker;而且端口配错时 Worker 不会立刻死,会撑一段时间才终止,这期间外面看到的是 502。Serverless 这套形态的通用取舍,可以对照看Serverless 推理那篇。

三、冷启动到底是什么,官方给的缓解手段有哪几条

这一节是全文最该细看的部分。

文档对冷启动的定义很精确:从一个没有运行中 Worker 的端点收到请求,到 Worker 完全「热」起来可以接活,这中间的时间。它包含启动容器、把模型权重加载进 GPU 显存、初始化运行时这几件事。模型越大加载越慢,冷启动越长,端到端响应时间跟着长。

在指标层面,文档把响应延迟拆成两段,这个拆法比「感觉有点慢」有用得多:Delay time 是请求在队列里等 Worker 的时间(包含冷启动),Execution time 是 Worker 真正在算的时间。Delay time 又能再拆成初始化时间(拉 Docker 镜像)和冷启动时间(把模型装进显存)。这三个量在控制台的 Metrics 标签页里都有 P70 / P90 / P98 三档分位数,另外还单独有一个冷启动次数指标。定位问题的正确顺序是先看是 delay 还是 execution 偏高:前者是伸缩和加载的问题,后者是代码和选卡的问题,两条路的解法完全不搭。

官方给的缓解路径有四条,按「效果大小 + 代价形式」排开来看:

第一条,用缓存模型(cached models)。 这是文档明确推荐的首选,条件是模型托管在 Hugging Face 上(公开、需同意条款的 gated、以及你的 token 有权限的私有库都支持)。机制是你在端点的 Model 字段填模型链接,RunPod 会优先把你的 Worker 调度到已经存有这个模型的宿主机上;如果没有这样的机器,系统会先把模型下到目标机器上再启动 Worker。这里有一个很实的好处:下载模型的这段时间不计费。文档还提到同一台宿主机上的多个 Worker 可以共用同一份缓存模型,省掉重复下载和磁盘。缓存模型在 Worker 里的路径遵循 Hugging Face 缓存约定,挂在 /runpod-volume/huggingface-cache/hub/ 下面,目录名把模型名里的斜杠换成双短横线,再套一层版本哈希的 snapshot 子目录,形如 /runpod-volume/huggingface-cache/hub/models--{org}--{name}/snapshots/{hash}/。用官方 vLLM worker 一类的镜像时你不用管这个路径,填 Model 字段或设 MODEL_NAME 就行;自己写 Worker 就得自己把这个路径解析出来。限制有两条要提前知道:一个端点当前只能挂一个缓存模型;如果一个 Hugging Face 仓库里放了多种量化版本,系统目前会把所有量化版本都下下来,按文档说法「选择特定量化版本」的能力要等后续更新。

第二条,把模型打进镜像。 适用于不在 Hugging Face 上的私有模型。代价是镜像变大、初始化时间变长,但好处是模型在 Worker 启动之前就已经在机器磁盘上了,也就是说它落在「开始计费之前」那一侧,起来之后可以很快接活。

第三条,开 FlashBoot。 机制是 Worker 缩掉之后保留一部分状态,下次「复活」比全新启动快。文档说它对流量比较稳定、Worker 频繁在活跃与空闲之间来回切的端点最有效——反过来说,流量极其稀疏的端点指望它意义不大。新建的 GPU 和 CPU 端点默认是开着的,已有端点可以编辑开关。

第四条,把 active(最小)Worker 数设成大于零。 这条是唯一能彻底消除冷启动的办法,代价也最直白:这些 Worker 一直在跑,就一直在计费。文档甚至给了一个估算需要几个 active worker 的公式:Active workers = (Requests/min × Request duration in seconds) / 60。这个公式的价值不在于算得准,而在于它把「我需要常驻多少算力」变成了一道可以填数的题——你只要估得出每分钟请求数和单请求耗时,就能自己算,不用凭感觉拍。

除这四条之外还有两条工程侧的操作:把镜像做小(下载快、冷启动短)、把模型加载写在 Handler 外面。另外有一个边界值得注意:文档说冷启动时间超过某个阈值,Worker 会被判为 unhealthy,可以用 RUNPOD_INIT_TIMEOUT 这个环境变量(单位是秒)把阈值调大。具体阈值和示例值我不抄进来,这类默认值会变,以官方文档为准。真正要注意的是这个机制的存在:加载特别慢的大模型有可能压根起不来,而表现出来的症状是「Worker 老是不健康」,不是「有点慢」。

四、active 与 flex worker,以及哪几种状态在计费

Worker 按运行模式分两类,这是理解账单形状的关键:

  • Active worker 持续运行,随时可以立刻处理请求,完全没有冷启动。适合对延迟敏感或者流量高的应用。文档明确说它包括空闲的时候也一直在计费
  • Flex worker 按需伸缩,空闲时缩到零,不用的时候不产生费用,代价是扩容时有冷启动。适合流量波动或者零零散散的负载。

另外文档提到系统在流量尖峰时可能会额外起几个 worker,条件是镜像已经在宿主机上有缓存,这部分是系统行为,不是你配的。

Worker 的状态一共六种,我把文档那张表的计费列单独拎出来,因为这是最容易算错账的地方:

状态含义是否计费
Initializing正在下载镜像、加载代码、下载缓存模型
Idle已缩容,等请求
Running正在处理请求
Throttled受宿主机资源限制暂时跑不了
Outdated更新后被标记待替换处理任务期间计费
Unhealthy崩过;会自动重试一段时间

这张表里有两条反直觉的:Initializing 不计费(所以缓存模型和打进镜像这两条路才有成本上的意义,它们把加载时间挪到了不计费那一侧);Throttled 不计费,但它也不干活——抢不到资源的时候你看着 Worker 数不少,实际吞吐上不去,账单也不涨,这种情况下加 max workers 是无效的,该做的是在端点配置里多勾几档 GPU 类型。

但要注意 Running 状态覆盖的范围比「在算」更宽。按计费页的口径,计费是从 Worker 启动到完全停止、按秒向上取整,其中包含三段:启动时间(初始化容器、把模型装进显存)、执行时间、以及空闲超时那段时间——也就是 Worker 处理完一个请求之后为了等下一个请求而保持活跃的那段。这段时间文档写得很清楚:你是被计费的,换来的是 Worker 保持热态。所以 idle timeout 这个参数本质上是一个「拿钱买热态」的旋钮,调大它省的是冷启动,花的是常驻时间。关于 Pod 与 Serverless 两套计费机制的完整拆解,见 RunPod 计费机制

说到 Worker 状态,还有一个你不改配置也会发生的行为:如果一个端点反复产出不健康的 Worker,RunPod 会自动把它缩下来,目的是停止计费、避免来回抖动,并且会发邮件通知。这就是开头那个「最大 Worker 数自己变小了」的第二种原因。

五、伸缩策略与几个会咬人的超时

端点侧的伸缩参数就几个,但每个都有明确的语义:

Active workers 是始终保持热态的最小 Worker 数,设成一以上就没有冷启动了,代价是持续计费。Max workers 是这个端点最多能扩到多少个并发实例,它同时是成本安全阀和并发上限。文档给的经验是在预期的最大并发之上留一点余量,好处是流量尖峰时不会被卡住;具体留多少比例文档给了一个建议值,这类建议值我不抄,重点是「要留余量」这个动作。GPUs per worker 是每个 Worker 分几张卡,文档的倾向很明确:宁可用更少的高端卡,也不要堆多张低端卡。

伸缩策略(Auto-scaling type)有两种,选哪个取决于你更在意利用率还是响应:

  • Queue delay:请求在队列里等的时间超过阈值就加 Worker。适合能容忍一点延迟、想把利用率做高的场景。
  • Request count:按「排队中 + 正在处理」的总量算,更激进。公式文档给得很明确:Math.ceil((requestsInQueue + requestsInProgress) / scalerValue)。把 scaler value 设成 1 就是最灵敏的档。文档特别推荐 LLM 负载和高频短请求用这个策略

这个推荐是有道理的:LLM 请求的耗时方差很大,按「等了多久」触发扩容会在长请求堆积时反应迟钝,而按「有多少请求在手上」触发更接近真实压力。吞吐和并发这两个量到底该怎么量、瓶颈一般卡在哪,可以接着看推理吞吐

超时这块有三个参数,其中两个的关系是本节最容易出事的地方:

Idle timeout 是 Worker 处理完请求后保持活跃的时长,前面说了,这段计费。Execution timeout 是单个任务允许跑的最长时间,超了任务失败、Worker 停掉;文档建议保持开启,防止跑飞的任务无限烧钱。它可以在端点的 Advanced 设置里配,也能在单次请求的 policy 里用 executionTimeout 覆盖,覆盖只对那一个任务生效。

Job TTL 是任务在系统里的总寿命,计时从提交那一刻开始,不是从开始执行那一刻开始。这就是陷阱所在:TTL 到期时任务数据会被直接删掉,不管它当时是排队、运行还是已完成。文档用了加粗警告——TTL 是硬限制,如果任务正在跑的时候 TTL 到了,任务会被立刻移除,查状态返回 404,哪怕它再过几秒就能成功。文档举的例子很直观:一个任务排了很久的队,剩给执行的时间就只有 TTL 减掉排队时间那么多。所以设长任务的正确做法是两步:先按需要的最长运行时间设 executionTimeout,再把 ttl 设成同时覆盖预期排队时间和执行时间。这两个参数的上限文档都给了,是同一个值,我不抄具体天数。

还有一个不是你配的、但会改你配置的机制:端点长时间没有任何请求,RunPod 会自动缩容。文档描述的是两级——连续若干天没有请求,先把 max workers 压到一个很小的值并给你发邮件;再过几天,max workers 被设成零。具体天数以文档为准。关键的三点是:计时基于请求活动,任何一个新请求都会把计时器重置;缩下去之后不会自己恢复,得你自己回控制台把 max workers 调回去;想不被缩,唯一办法是让它持续有请求。这条对「建了个端点先放着、过两周再接上游」这种节奏杀伤力最大——回来发现端点还在、但扩不上去了。

六、请求怎么发:/run/runsync/status 和其余几个操作

队列型端点的操作是一组固定路径,方法也是固定的:提交任务用 POST,查状态和健康用 GET

/runsync 是同步提交,客户端等到任务完成拿完整结果,适合短任务和交互式应用;/run 是异步提交,后台处理,之后用 /status 取结果,适合长任务和批处理。两者的结果保留时长不一样,异步那边明显更长——文档给了具体时长,我不抄;要记住的是「结果是有保留期的,过期就永久删除」,排错表里「结果不见了」这一条的原因就是没在保留窗口内取走。另外 /runsync 还有一个 ?wait= 参数可以调它等多久,文档特别提醒:这个参数控制的是等待时长,不是结果保留时长,两件事别搞混。

请求体的形状是硬约定:必须是一个 JSON 对象,里面有 input 键,input 的内容由你的 Handler 决定。

{
  "input": {
    "prompt": "Your input here"
  }
}

input 之外可以带几个顶层可选字段:webhook 填一个回调地址,任务完成时通知你(你的 webhook 要返回 200,失败时 RunPod 会重试几次);policy 里放前面说的 executionTimeoutttl,还有一个 lowPriority——设成 true 的任务不会触发扩容,这个字段对「顺手跑一批不着急的活、但不想因此把 Worker 数拉起来」的场景很有用,容易被忽略;s3Config 用来传 S3 兼容存储的凭据和桶信息,适合处理大文件,但文档说得很清楚,Worker 里得自己写使用这些信息的逻辑,平台不代劳。载荷大小是有上限的,/run/runsync 的上限不同,负载均衡端点另有一个上限,超了文档建议把结果放到对象存储、只返回链接。

其余操作按用途记就行:/stream 增量取结果,/cancel 停掉正在跑或还在排队的任务,/retry 用同一个任务 ID 和输入把失败或超时的任务重新排队,/purge-queue 清掉队列里所有待处理任务,/health 看端点整体状态(Worker 和任务的统计)。这些操作都有速率限制,而且限制不是固定的——文档说会按端点的 Worker 数动态放大,取「固定基线」和「运行中 Worker 数 × 每 Worker 配额」里较大的那个。超了返回 429,官方的建议是客户端做指数退避重试。具体数值我不抄,这类配额随时可能调。

任务状态一共七种,值得记的是它们能告诉你问题出在哪一段:IN_QUEUE(在队列里等 Worker,等太久说明伸缩或容量有问题)、IN_PROGRESSRUNNING(已被 Worker 取走并在处理)、COMPLETEDFAILED(执行中出错)、CANCELLED(被 /cancel 主动取消)、TIMED_OUT(要么在被取走之前就过期了,要么 Worker 没在超时阈值内报告回来)。注意 TIMED_OUT 把两种完全不同的故障合并在一个状态里:一种是没人来处理你(容量问题),一种是处理了但没在时限内完成(代码或选卡问题)。看到这个状态别急着加超时,先去 Metrics 里分清是 delay 高还是 execution 高。

最后一个跟上线节奏相关的机制:更新端点镜像或配置时,RunPod 走的是滚动发布。空闲的旧版 Worker 会被立刻终止换成新的,正在处理任务的 Worker 会被允许跑完当前任务再替换,整个过程端点继续收请求。文档在这里给了一条很实在的建议:用带版本号的镜像标签,不要用 :latest。因为用 latest 的话,已有 Worker 上可能还是缓存的旧镜像——Worker 只有在被替换时才会拉新镜像。想要严格的版本一致性,文档给的做法是先把 max workers 设成 0,等所有任务跑完、Worker 全部终止,再更新镜像并把 max workers 调回去。

七、出问题时从哪儿查

排错的入口只有三个,按顺序用:控制台的端点日志、SSH 进 Worker 实时调试、Metrics 标签页看模式。文档里症状到原因的映射,几条高频的值得记住:

Worker 起不来:看日志报错、确认本地测试能过、确认依赖都装进了镜像、确认镜像和你选的 GPU 类型兼容、确认输入格式和 Handler 的预期一致。

Worker 起来了但每个请求都失败:文档给的四类原因是输入校验、缺依赖、模型加载失败(检查显存需求和模型路径)、文件权限。这类问题的正确防法其实在上线之前——RunPod 有一套 fitness checks(也叫 preflight checks)机制,在 Worker 开始接单之前按顺序跑你注册的检查项,专门用来在请求进来之前就抓出「GPU 没挂上」「模型没加载」「配置不对」。自建推理服务最怕的就是 Worker 看起来起来了、实际每个请求都返回错误,这个机制值得一开始就用上。

任务卡在 IN_QUEUE:三类原因——没有可用 Worker(检查 max workers 设得合不合适)、Worker 被 throttled(去 Workers 标签页确认)、冷启动延迟(考虑提高最小 Worker 数或开 FlashBoot)。

任务全挤在一个 Worker 上:这一条是文档里少见的、明确点名 SDK 缺陷的条目。症状是端点有多个 Worker,但几乎所有任务都跑在其中一个上、其余闲着,同时任务还停在 IN_QUEUE。文档说这是某个版本区间的 RunPod Python SDK 在使用了网络卷的端点上会损坏按 Worker 的任务追踪,导致大部分 Worker 不再拉新任务,最常出现在 ComfyUI 这类挂网络卷的 Worker 上。修法是升级 SDK 到修复版本以上,然后重新构建并重新推送镜像才生效,不需要改代码和配置。涉及的版本区间和修复版本以官方文档为准。这条的价值在于它提醒了一个排查方向:看起来像伸缩策略没生效的现象,有可能根本不在伸缩层

日志没有:文档列的原因里有两条容易忽略——日志打太多会触发限流;日志只对成功初始化的 Worker 才有。也就是说「Worker 起不来又没日志」是可能同时发生的,这时候得靠 SSH 进去看。另外日志有保留期,超期自动清掉。

八、什么流量形态不该用 Serverless

说反面。按文档暴露出来的机制,下面几种情况我认为不该往 Serverless 上走,或者至少不该只用它:

流量稀疏且对首字延迟敏感。 这是最典型的错配。稀疏意味着 Worker 经常缩到零,敏感意味着用户等不了冷启动。四条缓解手段里,前三条(缓存模型、打进镜像、FlashBoot)都只是把冷启动变短,唯一能消除它的是常驻 active worker——而一旦常驻,Serverless「没请求不花钱」这个核心好处就没了。这种形态下 Serverless 并不比租一台机器长跑更划算,只是把账单换了个形状。

单请求特别长的任务走负载均衡型端点。 文档明说了负载均衡不适合长任务,会超时或者被丢。长任务要走队列型,并且要把 executionTimeoutttl 一起算清楚。

要求严格版本一致的强事务场景。 滚动发布期间必然有一段时间新旧镜像的 Worker 并存。如果你的更新改变了请求或响应的语义,这个重叠期就是不一致窗口。文档给的解法是先缩到零再更新,但那意味着一段计划内的不可用。

不能容忍丢请求、又想要低延迟的场景。 这两个要求在文档给的两类端点里是分开的:队列型保证执行但多一跳延迟,负载均衡型延迟低但过载丢请求。想同时要,得自己在客户端补退避重试和幂等,那部分复杂度不会消失,只是转移到了你的代码里。

你真正需要的只是一个模型接口的时候。 如果你要的就是发个请求拿个结果,那么打镜像、写 Handler、调伸缩、盯冷启动、管滚动发布这一整套是纯成本。该不该自己扛这套,是自建推理还是直接调 API那篇要算的账。

反过来说,Serverless 真正合适的形态也很清楚:流量忽高忽低、单请求不算长、能容忍一点排队延迟、且你已经有一个能跑起来的镜像。这四条同时成立时,它省下来的是「没人调用的那些小时」,这部分省下来的钱通常比任何参数调优都多。

最后说明一句:本文所有事实都来自 RunPod 的官方文档,我没有拿账号逐项验证过控制台的实际行为,文中也不包含任何跑分和单价。文档没有明确说明的地方(比如不同 GPU 档位的实际冷启动分布、不同区域的调度成功率、FlashBoot 在你自己镜像上的实际效果)官方文档没有明确说明,以控制台 Metrics 里的实际数据为准。可行的做法是:先按文档把伸缩策略、两个超时、缓存模型这三件事配对,然后用一个最小端点跑一轮真实流量形态,把 delay time 和 cold start count 这两个指标看明白再上量。这个顺序能省掉大部分返工。

算完账发现自建推理不划算?

先用托管端点把业务跑起来,量上来了再回头算自建的平衡点。

去试用

这个页面有问题?

提交时会附带当前页面地址和浏览器信息,帮助我们定位问题。不填联系方式即为匿名。