Cloudflare Resource Optimization Strategy — Cost Reduction and Efficiency Improvement Roadmap

Background

Cravatar’s overseas Cloudflare (CF) acceleration has gone live (see Full Record of Pitfalls Encountered). The current architecture is as follows:

Overseas users → CF Worker → HTTP origin fetch → Origin server port 80 → Response relayed back  
Domestic users → Alibaba Cloud DNS → cn.cravatar.com → Direct HTTPS connection to origin server port 443

Currently, over 30,000 daily requests from overseas users are all routed directly to the Nanjing origin server — each request triggers PHP + MySQL + disk I/O. Meanwhile, the CF free plan still has substantial unused resources. Below are actionable optimization directions, listed in descending order of priority.


I. Immediate Actions (Zero Cost)

1.1 Tiered Cache

What it is: Adds an upstream caching layer among CF’s global Points of Presence (PoPs). Without Tiered Cache, Tokyo and Osaka PoPs independently fetch from the origin; with it enabled, Osaka can retrieve cached content from Tokyo’s cache, reducing origin fetches.

Benefits: Expected reduction in origin-fetch requests by 50–70%, proportionally lowering origin bandwidth usage and PHP load.

Implementation: Dashboard → Caching → Tiered Cache → Enable Smart Tiered Cache. One-click setup—no code changes required.

1.2 Fine-Grained Cache Rules

Currently, the Worker sets a 30-day edge cache for /avatar/*. Further refinement can be achieved via zone-level Cache Rules:

  • /avatar/*: Edge TTL = 30 days, Browser TTL = 30 days (aligned with the already-fixed Cache-Control: public, max-age=2592000)
  • Static assets (JS/CSS/images): Edge TTL = 1 year
  • API endpoints: Bypass cache entirely

Implementation: Dashboard → Caching → Cache Rules — no Worker modifications needed.


II. Short-Term Initiatives

2.1 R2 Object Storage — Highest-Impact Optimization

Current Issue: Every avatar request hits PHP, which queries MySQL to locate the avatar path, then reads the file from disk and returns it. Even with edge caching, origin pressure remains high on cache misses.

Solution:

Before: Worker → Origin PHP → MySQL query → Disk read → Return  
After:  Worker → Query R2 → Hit → Return directly; Miss → Fetch from PHP → Store result in R2 after processing

Once generated, avatars are stored in R2; subsequent requests serve directly from R2. PHP only handles first-time generation and avatar updates.

Free Quotas:

  • Storage: 10 GB/month (average avatar size ≈ 5 KB → supports ~2 million avatars)
  • Class B operations (reads): 10 million/month
  • Class A operations (writes): 1 million/month
  • Egress traffic: Permanently free, unlimited

Key Advantages: R2 and Workers reside within the same CF network, enabling ultra-low latency (<10 ms). Critically, R2 egress is zero-cost — a decisive advantage over S3/OSS.

Implementation Essentials:

  • Worker intercepts /avatar/{hash} requests
  • First checks R2 bucket; if hit, returns image directly (with Cache-Control)
  • On miss, fetches from PHP origin, then asynchronously writes response to R2
  • Avatar updates trigger R2 cleanup via webhook or scheduled job
  • Bind R2 bucket to Worker via binding; access directly in code using env.BUCKET.get(key)

2.2 Workers KV — Edge Metadata Caching

Use Case: Even with R2, the Worker must query R2 on every request to verify avatar existence. For popular avatars (e.g., default avatars, high-frequency users), mapping relationships (hashR2 key) can be cached in KV.

Worker flow:
1. Query KV: Does hash → R2 key mapping exist?
2. KV hit → Fetch image directly from R2 and return  
3. KV miss → Fetch from PHP origin → Write to R2 + write mapping to KV

Free Quotas:

  • Reads: 100,000/day
  • Writes: 1,000/day
  • Storage: 1 GB

KV read quota is ample for caching hot mappings. Limited write quota makes it ideal for caching only high-frequency hashes.


III. Mid-Term Optimizations

3.1 Cache Reserve ($5/month minimum)

Problem: CF’s free-tier edge cache evicts infrequently accessed resources. Cravatar hosts many long-tail avatars (low-traffic), causing repeated eviction and re-caching — wasting origin bandwidth.

Solution: Cache Reserve persists cached objects in an R2 backend, preventing eviction of cold resources.

Timing: Enable after R2 deployment, once real-world origin-fetch rates are observed. If long-tail avatars continue driving high origin-fetch rates, Cache Reserve delivers strong ROI — $5/month is typically far less than saved origin bandwidth costs.

3.2 Email Routing

For domains under management (e.g., wpcy.net, wpbaike.com, cravatar.cn, wpavatar.com), Cloudflare Email Routing can replace paid email forwarding services.

Features:

  • Forward domain-based email addresses → Gmail / corporate mailboxes
  • Supports catch-all routing
  • Fully free, unlimited forwarding

Setup: Dashboard → Email → Email Routing → Add MX records.

3.3 Cloudflare Pages

If documentation sites, landing pages, or other static content still run on servers, migrate them to Cloudflare Pages:

  • Unlimited bandwidth
  • 500 builds/month
  • Automatic HTTPS
  • Global CDN distribution

Ideal for knowledge-base sites like wpbaike.com.


IV. End-to-End Architecture Evolution

                    ┌─────────────────────────────────────────┐
                    │              Cloudflare Edge             │
                    │                                         │
Overseas users ───▶ │  Worker ──▶ KV (hot hash → R2 key map)  │
                    │    │          │                          │
                    │    │   Hit     ▼                          │
                    │    │ ◀──── R2 Bucket (avatar files)       │
                    │    │                                     │
                    │    │ Miss                                │
                    │    ▼                                     │
                    │  HTTP origin fetch ──▶ Origin PHP       │
                    │    │          │                          │
                    │    │   ◀──────┘ Async write to R2 + KV   │
                    │    ▼                                     │
                    │  Tiered Cache ──▶ Return to user         │
                    └─────────────────────────────────────────┘

Domestic users ───▶ Alibaba Cloud DNS ──▶ cn.cravatar.com ──▶ Origin server port 443

Expected Outcomes:

  • Origin-fetch rate drops from 100% to <5% (leveraging triple-layer caching: R2 + KV + Tiered Cache)
  • Drastic reduction in origin PHP/MySQL load — potential for server downscaling to cut infrastructure costs
  • Lower latency for overseas users (R2 reads <10 ms vs. origin round-trip: 200–500 ms)
  • Near-zero egress bandwidth cost (R2 egress is free)

V. Implementation Priority

Priority Item Cost Engineering Effort Benefit
P0 Tiered Cache Free 5 minutes 50–70% fewer origin fetches
P0 Fine-grained Cache Rules Free 15 minutes Higher cache hit rate
P1 R2 Avatar Storage Within free tier Worker refactoring >90% reduction in origin fetches
P1 Workers KV Within free tier Integrated with R2 Zero-origin for hot requests
P2 Cache Reserve $5/month One-click enable Prevents eviction of long-tail assets
P2 Email Routing Free MX record config Eliminates paid email forwarding fees
P3 Pages Static Deployment Free Site migration Reduces server resource usage

We welcome discussion — especially around concrete implementation details for the R2 migration and cache-invalidation strategies for avatar updates.


Discussion Guidelines

  • :+1: Use the post’s built-in Reactions (:+1:/emoji) to express simple agreement — no need to reply “Agreed.”
  • :speech_balloon: Replies should focus on your professional perspective: real pain points, use cases, or risk concerns.
  • :thinking: Constructive disagreement is highly valued — thoughtful critique adds more value than passive agreement.
  • :ballot_box: Please vote below to indicate your final stance.
  • :white_check_mark: Support
  • :pause_button: Requires revision
  • :x: Oppose
0 投票人

Discussion invite: @wenpai-dev @kali-sec @fedora-ai @elementary @weixiaoduo @translate @studio @fedora-devops

Technical Review: Overall Support, with Additional Implementation Details

The proposed solution is sound—the tiered caching path (Tiered Cache → R2 → KV) is correct. The two P0 items (Tiered Cache + Cache Rules) should be enabled today; they carry zero risk and zero cost.

Below are several key considerations for the R2 migration:

1. R2 Key Design Must Account for Size Variants

Cravatar supports the ?s=SIZE parameter, meaning a single hash can correspond to multiple sizes (e.g., 80, 120, 256). An R2 key must not rely solely on the hash—otherwise, different sizes will overwrite one another.

Recommended key format:

avatar/{hash}/{size}    # e.g., avatar/abc123/80, avatar/abc123/256
avatar/{hash}/original  # original image
default/{type}/{size}   # default avatars (e.g., mystery person, identicon, etc.)

Default avatars constitute a finite set; all size variants can be pre-generated and written to R2 in bulk once—subsequent requests will always hit the cache.

2. Concurrent Origin Fetch Deduplication (“Thundering Herd”)

When multiple PoPs simultaneously request the same uncached hash, multiple origin fetches may be triggered. The Worker layer must deduplicate these:

// Use the Cache API for edge-level deduplication
const cache = caches.default;
const cacheKey = new Request(`https://cache-internal/avatar/${hash}/${size}`);
let response = await cache.match(cacheKey);
if (!response) {
  response = await fetchFromOrigin(hash, size);
  // Asynchronously write to R2 + Cache using waitUntil—does not block the response
  ctx.waitUntil(Promise.all([
    env.BUCKET.put(r2Key, response.clone().body),
    cache.put(cacheKey, response.clone())
  ]));
}
return response;

Enabling Tiered Cache helps mitigate cross-PoP duplicate origin fetches, but intra-PoP concurrency still requires handling via the Cache API.

3. KV Free Tier Quota May Be Insufficient—Recommend Deferring KV Integration

The KV free tier allows only 1,000 writes per day. If 1,000–5,000 new unique hashes are added daily, the quota will be exhausted on Day 1.

Two options exist:

  • Skip KV entirely—use R2 + Cache API directly: R2 read latency is typically <10 ms; combined with edge caching via the Cache API, performance is already sufficient. KV offers minimal benefit here while adding an extra stateful layer to maintain.
  • Upgrade to paid KV ($5/month): If absolutely required, this provides up to 10 million writes per month.

We recommend deferring KV integration for now—R2 + Cache API alone provide adequate coverage. Fewer layers mean fewer potential points of failure.

4. Cache Invalidation Strategy

When an avatar is updated, all size variants for that hash must be invalidated in R2. Recommended approach:

  • After the source avatar is updated, invoke a Worker API: POST /purge/{hash}
  • The Worker lists and deletes all keys under the avatar/{hash}/ prefix in R2
  • Simultaneously call cache.delete() to invalidate edge cache entries
  • This purge operation can be asynchronous—the update can take effect within seconds of the user changing their avatar

5. Integration with NSFW Moderation Pipeline

This architecture should be designed in conjunction with the NSFW moderation proposal. The optimal point to perform NSFW detection is immediately before the first write to R2:

First request → fetch avatar from origin → run NSFW check → passes → write to R2 (with 'safe' metadata) → return
                                                               → fails → write to blacklist → return default avatar
Subsequent requests → hit R2 → read metadata → return immediately

The nsfw_status is stored in the R2 object’s customMetadata, retrieved by the Worker in the same read operation—no additional database or KV lookup is needed.

Summary

  • Execute P0 items immediately.
  • R2 migration constitutes the core engineering effort (P1); defer KV integration for now.
  • Integrate the NSFW moderation pipeline into the R2 write path from the outset—build it right the first time.

Additional note from the VM perspective:

The Cloudflare R2 + Worker solution also aids localization. For multilingual sites sharing an avatar service, the Worker layer can sniff the Accept-Language header and return language-specific default avatars (e.g., the “mystery person” placeholder displays different text prompts in different languages). This does not affect the core architecture, but when generating size variants in R2, you can simultaneously consider adding a locale dimension to object keys.

We recommend enabling Tiered Cache and Cache Rules immediately—they deliver the highest ROI.