默认情况下,Workers 和 Pages Functions 会在距离接收请求位置最近的数据中心运行。如果您的 Worker 需要请求后端基础设施(如数据库或 API),将该 Worker 部署在更靠近后端而非最终用户的位置,可能会获得更好的性能。
{
"placement": {
// Use one of the following options (mutually exclusive):
"mode": "smart", // Cloudflare automatically places your Worker closest to the upstream with the most requests
"region": "gcp:us-east4", // Explicit cloud region to run your Worker closest to - e.g. "gcp:us-east4" or "aws:us-east-1"
"host": "db.example.com:5432", // A host to probe (TCP/layer 4) - e.g. a database host - and place your Worker closest to
"hostname": "api.example.com", // A hostname to probe (HTTP/layer 7) - e.g. an API endpoint - and place your Worker closest to
},
}[placement]
mode = "smart"
region = "gcp:us-east4"
host = "db.example.com:5432"
hostname = "api.example.com"放置功能可以通过减少 Worker 与后端服务之间请求的往返延迟,降低 Worker 请求的整体延迟。对于运行在传统云基础设施中的数据库、API 和其他服务,您可以将延迟降至个位数毫秒级别。
| 选项 | 适用场景 | 配置 |
|---|---|---|
| Smart(智能) | 多个后端服务,或基础设施位置未知 | mode = "smart" |
| Region | 单个后端服务位于已知的云区域 | region |
| Host | 单个后端服务不在主流云提供商中 | host 或 hostname |
假设一位位于澳大利亚悉尼的用户访问运行在 Workers 上的应用程序。该应用程序需要多次往返访问位于德国法兰克福的数据库。
悉尼与法兰克福之间多次往返的延迟会不断累加。通过将 Worker 部署在数据库附近,Cloudflare 可以缩短请求的总耗时。
Smart Placement 会自动分析 Worker 的流量模式,并将其放置在最佳位置。在以下情况下使用 Smart Placement:
- Worker 连接多个后端服务
- 您不知道基础设施的确切位置
- 后端服务是分布式或复制的
Smart Placement 按 Worker 分别启用。启用后,它会定期分析 Worker 在不同 Cloudflare 位置的请求持续时间。
对于每个候选位置,Smart Placement 会考虑 Worker 的性能以及转发请求所增加的网络延迟。如果某个候选位置明显更快,请求会被转发到该位置。否则,Worker 会在距离请求最近的默认位置运行。
Smart Placement 仅考虑 Worker 此前运行过的位置。它无法将 Worker 放置在通常不会收到流量的位置。
- Smart Placement 仅影响 fetch 事件处理程序 的执行。它不影响 RPC 方法 或 命名入口点。
- 没有 fetch 事件处理程序的 Worker 会被 Smart Placement 忽略。
- 静态资源 始终从距离传入请求最近的位置提供。如果您的代码通过静态资源绑定(binding) 获取资源,资源将从 Worker 运行的位置提供。
Smart Placement 适用于所有 Workers 套餐。
在 Wrangler 配置文件中添加以下内容:
{
"placement": {
"mode": "smart",
},
}[placement]
mode = "smart"Smart Placement 在部署后可能需要最多 15 分钟来分析 Worker。
-
前往 Workers & Pages。
Go to Workers & Pages ↗ -
选择您的 Worker。
-
前往 Settings(设置) > General。
-
在 Placement(放置) 下,选择 Smart(智能)。
Smart Placement 需要来自多个位置对 Worker 的稳定流量才能做出放置决策。分析过程可能需要最多 15 分钟。
通过 Workers API 查询 Worker 的放置状态:
curl -X GET https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/services/$WORKER_NAME \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" | jq .可能的放置状态:
| 状态 | 说明 |
|---|---|
| (不存在) | Worker 尚未被分析。它在距离请求最近的默认位置运行。 |
SUCCESS |
Worker 已被分析,将由 Smart Placement 进行优化。 |
INSUFFICIENT_INVOCATIONS |
Worker 尚未收到来自多个位置的足够请求,无法做出放置决策。 |
UNSUPPORTED_APPLICATION |
Smart Placement 使 Worker 变慢并已恢复默认放置。此状态较为罕见(少于 1% 的 Worker)。 |
启用 Smart Placement 后,系统会收集请求持续时间数据。请求持续时间在距离最终用户最近的数据中心测量。默认情况下,1% 的请求不会通过 Smart Placement 路由,以作为对比基准。
查看 Worker 的请求持续时间分析,以衡量 Smart Placement 的影响。
启用放置后,Cloudflare 会在所有请求中添加 cf-placement 标头。使用此标头可以检查请求是否通过 Smart Placement 路由,以及 Worker 在何处处理了请求。
标头值包含放置类型和表示数据中心位置的机场代码:
remote-LHR— 请求通过 Smart Placement 路由到伦敦附近的数据中心。local-EWR— 请求未通过 Smart Placement 路由。Worker 在纽瓦克附近的默认位置运行。
Placement Hints 允许您显式指定 Worker 的运行位置。在以下情况下使用 Placement Hints:
- 您知道后端基础设施的确切位置
- Worker 连接单个数据库、API 或服务
- 基础设施是单点部署(未复制或使用 anycast)
示例包括特定区域中的主数据库、虚拟机或 Kubernetes 集群。将每次查询 20 到 30 毫秒的往返延迟降至 1 到 3 毫秒,可以改善响应时间。
如果您的基础设施运行在 AWS、GCP 或 Azure 上,请使用 {provider}:{region} 格式设置 placement.region 属性:
{
"placement": {
"region": "aws:us-east-1", // Explicit cloud region to run your Worker closest to - e.g. "gcp:us-east4" or "aws:us-east-1"
},
}[placement]
region = "aws:us-east-1"Cloudflare 会将您指定的云区域映射到与该区域延迟最低的数据中心。Cloudflare 会自动调整放置以应对网络维护或变更,因此您无需指定故障转移区域。
如果您的基础设施不在主流云提供商中,您可以指定一个端点供 Cloudflare 探测。Cloudflare 将三角定位外部主机的位置,并将 Workers 放置在附近的区域。
将 placement.host 设置为标识第 4 层服务。Cloudflare 使用 TCP CONNECT 检查来测量延迟,并选择最佳数据中心。
{
"placement": {
"host": "my_database_host.com:5432", // A host to probe (TCP/layer 4) - e.g. a database host - and place your Worker closest to
},
}[placement]
host = "my_database_host.com:5432"将 placement.hostname 设置为标识第 7 层服务。Cloudflare 使用 HTTP HEAD 检查来测量延迟,并选择最佳数据中心。
{
"placement": {
"hostname": "my_api_server.com", // A hostname to probe (HTTP/layer 7) - e.g. an API endpoint - and place your Worker closest to
},
}[placement]
hostname = "my_api_server.com"探测从公共 IP 范围发送,而非 Cloudflare IP 范围。Cloudflare 会定期重新检查服务位置。这些探测用于定位单点部署的资源,对广播、anycast、多播或复制资源无法正确工作。
Placement Hints 支持 Amazon Web Services (AWS)、Google Cloud Platform (GCP) 和 Microsoft Azure 区域标识符:
| 提供商 | 格式 | 示例 |
|---|---|---|
| AWS | aws:{region} |
aws:us-east-1、aws:us-west-2、aws:eu-central-1 |
| GCP | gcp:{region} |
gcp:us-east4、gcp:europe-west1、gcp:asia-east1 |
| Azure | azure:{region} |
azure:westeurope、azure:eastus、azure:southeastasia |
有关完整区域代码列表,请参阅 AWS 区域 ↗、GCP 区域 ↗或 Azure 区域 ↗。
无论使用 Smart Placement 还是 Placement Hints,Workers 放置的行为方式类似。以下行为对两者均适用。
以下限制同时适用于 Smart Placement 和 Placement Hints:
- 放置仅影响 fetch 事件处理程序 的执行。它不影响 RPC 方法 或 命名入口点。
- 没有 fetch 事件处理程序的 Worker 会被放置功能忽略。
- 静态资源 始终从距离传入请求最近的位置提供。如果您的代码通过静态资源绑定(binding) 获取资源,资源将从 Worker 运行的位置提供。
启用放置后,Cloudflare 会在所有请求中添加 cf-placement 标头。使用此标头可以检查请求是否通过放置功能路由,以及 Worker 在何处处理了请求。
标头值包含放置类型和表示数据中心位置的机场代码:
remote-LHR— 请求通过 Smart Placement 路由到伦敦附近的数据中心。local-EWR— 请求未通过 Smart Placement 路由。Worker 在纽瓦克附近的默认位置运行。
如果您在 Workers 上构建全栈应用程序,请将边缘逻辑(身份验证、路由)和后端逻辑(数据库查询、API 调用)拆分为独立的 Workers。使用 Service Bindings 通过类型安全的 RPC 连接它们。
在后端 Worker 上启用放置功能,使其在靠近数据库的位置被调用,而边缘 Worker 则在靠近用户的位置处理身份验证。
此示例展示两个 Workers:
auth-worker— 在边缘运行(无放置),处理身份验证app-worker— 部署在数据库附近,处理数据查询
{
"name": "auth-worker",
"main": "src/index.ts",
"services": [{ "binding": "APP", "service": "app-worker" }],
}name = "auth-worker"
main = "src/index.ts"
[[services]]
binding = "APP"
service = "app-worker"import { AppWorker } from "../app-worker/src/index";
interface Env {
APP: Service<AppWorker>;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const authHeader = request.headers.get("Authorization");
if (!authHeader?.startsWith("Bearer ")) {
return new Response("Unauthorized", { status: 401 });
}
const userId = await validateToken(authHeader.slice(7));
if (!userId) {
return new Response("Invalid token", { status: 403 });
}
// Call the placed back-end Worker via RPC
const data = await env.APP.getUser(userId);
return Response.json(data);
},
};
async function validateToken(token: string): Promise<string | null> {
return token === "valid" ? "user-123" : null;
}{
"name": "app-worker",
"main": "src/index.ts",
"placement": {
// Use one of the following options (mutually exclusive):
// "mode": "smart", // Cloudflare automatically places your Worker closest to the upstream with the most requests
"region": "aws:us-east-1", // Explicit cloud region to run your Worker closest to - e.g. "gcp:us-east4" or "aws:us-east-1"
// "host": "db.example.com:5432", // A host to probe (TCP/layer 4) - e.g. a database host - and place your Worker closest to
// "hostname": "api.example.com", // A hostname to probe (HTTP/layer 7) - e.g. an API endpoint - and place your Worker closest to
},
}name = "app-worker"
main = "src/index.ts"
[placement]
region = "aws:us-east-1"import { WorkerEntrypoint } from "cloudflare:workers";
export default class AppWorker extends WorkerEntrypoint {
async fetch() {
return new Response(null, { status: 404 });
}
// Each method runs near your database - multiple queries stay fast
async getUser(userId: string) {
const user = await this.env.DB.prepare("SELECT * FROM users WHERE id = ?")
.bind(userId)
.first();
return user;
}
async getUserListings(userId: string) {
// Multiple round-trips to the DB are low-latency when placed nearby
const user = await this.env.DB.prepare("SELECT * FROM users WHERE id = ?")
.bind(userId)
.first();
const listings = await this.env.DB.prepare(
"SELECT * FROM listings WHERE owner_id = ?",
)
.bind(userId)
.all();
const reviews = await this.env.DB.prepare(
"SELECT * FROM reviews WHERE listing_id IN (SELECT id FROM listings WHERE owner_id = ?)",
)
.bind(userId)
.all();
return { user, listings: listings.results, reviews: reviews.results };
}
}auth-worker 在边缘运行,可快速拒绝未授权请求。已授权的请求通过 RPC 转发到 app-worker,后者在数据库附近运行以实现快速查询。
Durable Objects 无需配置即可提供自动放置。对 Durable Object 内嵌 SQLite 数据库 的查询实际上是零延迟 ↗的,因为计算与数据运行在同一进程中。
尽可能在 Durable Object 内完成工作并返回组合结果,而不是从 Worker 发起多次往返:
import { DurableObject } from "cloudflare:workers";
type Session = { id: string; user_id: string; created_at: number };
type PromptHistory = {
id: string;
session_id: string;
role: string;
content: string;
};
export class AgentHistory extends DurableObject {
async getSessionContext(sessionId: string) {
// All queries execute with zero network latency — compute and data are colocated
const session = this.ctx.storage.sql
.exec<Session>("SELECT * FROM sessions WHERE id = ?", sessionId)
.one();
const prompts = this.ctx.storage.sql
.exec<PromptHistory>(
"SELECT * FROM prompt_history WHERE session_id = ? ORDER BY created_at",
sessionId,
)
.toArray();
return { session, prompts };
}
}