การเลือกแพลตฟอร์มสำหรับการปรับใช้ (deployment) มักเป็นเรื่องยากที่จะเปรียบเทียบประสิทธิภาพในโลกจริงระหว่างแต่ละตัว โดยเฉพาะแพลตฟอร์มแบบ Serverless ที่โฆษณาเรื่อง Latency ต่ำมากจากการปรับใช้แบบ Edge ทั่วโลก แต่ Latency ต่ำนั้นมีประโยชน์อย่างไร หากการดึงข้อมูลยังคงช้าอยู่ดี? หาก API ของคุณทำงานอยู่ใกล้ผู้ใช้ แต่ต้องเดินทางผ่านเครือข่ายไปอีกด้านโลกเพื่อดึงข้อมูล คุณก็จะไม่ได้ประสบการณ์ที่ดี
โดยปกติแล้ว Compute และ Storage จะถูกวางร่วมกันในเซิร์ฟเวอร์เดียว หรืออย่างน้อยก็ใน Data Center เดียวกัน แต่ด้วยการพัฒนาของ Serverless และ Edge Functions เราได้เห็นการแยก Compute และ Storage ออกจากกัน ซึ่งดีต่อการ Scale และความพร้อมใช้งาน แต่ก็สร้างปัญหาใหม่ขึ้นมาคือ Latency ปัจจุบันการปรับใช้ API ไปยังเครือข่าย Edge ทั่วโลกง่ายมาก แต่ข้อมูลนั้นล่ะ? ข้อมูลยังตามหลังอยู่ แต่อยู่ในขั้นตอนที่กำลังตามทัน
ในบทความนี้เราจะเปรียบเทียบประสิทธิภาพของ Datastore แบบ Serverless สองตัว ได้แก่ Cloudflare KV และ Upstash Redis ทั้งคู่เป็น Serverless และกระจายตัวทั่วโลก แต่วิธีการทำงานต่างกันอย่างสิ้นเชิง Cloudflare KV เป็น Key-Value Store แบบ Pull-based ในขณะที่ Upstash เป็นบริการที่เข้ากันได้กับ Redis พร้อม Active Replication
Pull-based vs Active Replication
Pull-based: ข้อมูลจะถูกเก็บไว้ที่ศูนย์กลาง และย้ายไปยัง Edge Nodes ก็ต่อเมื่อมีผู้ใช้ร้องขอเท่านั้น นี่คือวิธีการของ Cloudflare KV
Active Replication: ข้อมูลจะถูกเก็บไว้ในทุก Edge Location และซิงค์ให้สม่ำเสมอโดย Datastore เอง การอัปเดตข้อมูลจะถูก Replicate ไปยังทุก Region ทันที นี่คือวิธีการของ Upstash และผลพวงก็คือ Vercel
Caching ก็คือการเก็บ Key-Value ไว้หลายๆ ตัว แนวคิดง่าย แต่เป็นที่ใช้กันอย่างแพร่หลาย และเป็นวิธีที่ดีในการเปรียบเทียบประสิทธิภาพของ Datastore สองตัวนี้ เราจะใช้สถานการณ์ Caching เรียบง่ายในการเปรียบเทียบ
The Benchmark - รายละเอียดการทดสอบ
เราจะวัด Latency ที่ Cloudflare Worker ประสบเมื่ออ่านค่าเดี่ยวจาก Cloudflare KV และ Upstash Redis
- 1 Cloudflare Worker
- 1,000 Keys
- ขนาดข้อมูล 4KB - 64KB (สุ่ม)
- TTL 60 วินาที สำหรับทุก Key
- 20 Regions เรียก Worker
- ประมาณ 10 Requests ต่อวินาที
เราเลือก Keyspace ขนาดเล็ก เพื่อให้แน่ใจว่าได้ Cache Hits โดยไม่ต้องเพิ่ม RPS มากเกินไป
Worker Code
Worker เองมีโค้ดเรียบง่าย เพียงแค่อ่านจาก Redis อ่านจาก KV แล้วคืนค่า Latency กลับไปประเมิน
app.get("/test", async (c) => {
const redis = Redis.fromEnv(c.env);
const key = Math.floor(Math.random() * 1_000).toString();
const minValueSize = 4 * 1024;
const maxValueSize = 64 * 1024;
const ttlSeconds = 60;
const randomValue = new TextDecoder().decode(
crypto.getRandomValues(
new Uint8Array(
Math.floor(Math.random() * (maxValueSize - minValueSize)) + minValueSize,
),
),
);
const beforeRedis = performance.now();
const redisResponse = await redis.get(key);
const redisLatency = performance.now() - beforeRedis;
if (!redisResponse) {
await redis.set(key, randomValue, { ex: ttlSeconds });
}
const beforeKV = performance.now();
const kvResponse = await c.env.ANDREAS_KV_BENCHMARK.get(key);
const kvLatency = performance.now() - beforeKV;
if (!kvResponse) {
await c.env.ANDREAS_KV_BENCHMARK.put(key, randomValue, {
expirationTtl: ttlSeconds,
});
}
return c.json({ kvLatency, redisLatency });
});
ผลลัพธ์ - Global Latency
หลังจากรัน Benchmark ประมาณ 30 นาที เราสังเกตเห็นความแตกต่างที่มีนัยสำคัญระหว่างสอง Datastore

คลิกภาพเพื่อดูขนาดเต็ม
ตามที่เห็น Cloudflare KV ช้ากว่า Upstash Redis อย่างต่อเนื่อง ผมไม่คาดหวังเรื่องนี้ เพราะ Cloudflare โฆษณา KV ว่า Low-latency และรันบนแพลตฟอร์มเดียวกับ Workers แม้จะไม่เก็บข้อมูลในทุก Region โดยค่าเริ่มต้น แต่หลังจากไม่กี่นาที ควรจะมีข้อมูล Cached ใน Region ที่ Worker รันอยู่แล้ว
อาจเป็นเพราะ Load ไม่พอที่จะให้ระบบของ Cloudflare วางข้อมูลใกล้ Worker? มาลองแยก Region และเพิ่ม Load ให้มากขึ้นดูว่าเปลี่ยนแปลงไหม
Single Region - ทดสอบใน Region เดียว
มาดูผลลัพธ์ของ Region เดียวกับ RPS สูงกว่ามาก ทฤษฎีแล้ว Cloudflare ควร Warm Cache ทั้งหมดใน Region นี้ และได้ Latency ต่ำมากตามที่โฆษณา
การทดสอบนี้เหมือนครั้งแรก แต่เรียก Worker จาก Region เดียวที่ ~400 RPS

คลิกภาพเพื่อดูขนาดเต็ม
Latency ของ KV ดีขึ้นมาก:
- P90: 742ms → 115ms
- P99: 1,336ms → 560ms
นี่แสดงว่าต้องการ Load ค่อนข้างสูงก่อนที่ Cloudflare จะ Replicate ข้อมูลไปใกล้ Worker จริงๆ แม้ P90 115ms จะไม่แย่ แต่ P99 เกินครึ่งวินาที ก็สังเกตได้ชัดเจน จะต้องจำได้ว่าเราทดสอบที่ ~400 RPS เพื่อให้ข้อมูล Replicate จริง ซึ่ง Load สูงกว่า API ขนาดเล็กถึงกลางทั่วไป
น่าสนใจคือเห็นจุดที่ Cloudflare ย้ายข้อมูลเข้าใกล้หรือออกไกลจาก Worker ได้จากภาพนี้:

คลิกภาพเพื่อดูขนาดเต็ม
Pricing - เปรียบเทียบราคา
การเปรียบเทียบจะไม่สมบูรณ์หากไม่พูดถึงต้นทุน
ปัจจัยหลักคือต้นทุนต่อ Request ในการเข้าถึง Datastore แต่ละตัว
Cloudflare คิด $0.50 ต่อ 1 ล้าน KV Reads ในขณะที่ Upstash คิด $1 ต่อ 1 ล้าน Redis Commands มีความแตกต่างอื่นๆ เช่น Cloudflare แพงกว่าด้าน Storage ส่วน Upstash แพงกว่าด้าน Bandwidth แต่ไม่ใช่ Cost Driver หลักในสถานการณ์นี้
Upstash เหมาะกับคุณไหม?
คำตอบอยู่ที่คุณเอง
เรามี Bias และเชื่อในผลิตภัณฑ์ของตัวเอง จึงขอให้พิจารณาด้วย
หากคุณรัน API ขนาดเล็กถึงกลาง คุณควรพิจารณา Latency เพราะต้นทุนจะน้อยมาก เมื่อ API มี Traffic มาก Upstash มี Fixed Pricing ที่ถูกกว่า Cloudflare KV
หากคุณต้องการแค่ set, get, list อยู่บน Workers Platform และรับ Latency สูงได้ Cloudflare KV อาจเหมาะสม ทุกอย่างจัดการที่เดียว ไม่ต้องกังวล
หากตอบ "ไม่" กับข้อไหนข้อหนึ่ง ขอแนะนำให้ลอง Upstash Redis มี Features มากกว่า Cloudflare KV อย่าง Pub/Sub, Sorted Sets, Hashes และ Upstash รองรับหมด หากใช้ Redis อยู่แล้ว แค่เปลี่ยน Endpoint ไป Upstash ก็ใช้งานได้เลย ไม่ต้องแก้โค้ด
Conclusion - สรุป
Cloudflare KV เป็นผลิตภัณฑ์ที่ดี แต่ไม่ใช่แทนที่ Database เต็มรูปแบบอย่าง Redis เหมาะกับ Use-case เรียบง่ายที่ Latency ไม่ใช่ปัญหา
มาคุยและถามคำถามได้ที่ Discord หรือ X ของเรานะครับ