blog.dopana

Back

Trước đây, để xây dựng một hệ thống API phân tán toàn cầu, chúng ta thường phải thiết lập cụm server đa vùng (multi-region), cấu hình load balancer, quản lý các bản sao cơ sở dữ liệu (read-replicas) và đối mặt với độ trễ mạng lớn.

Với nền tảng Cloudflare Edge và công cụ Wrangler CLI, bạn hoàn toàn có thể xây dựng, kiểm thử cục bộ và triển khai một REST API chuẩn production kết hợp cơ sở dữ liệu quan hệ (D1) cùng bộ nhớ đệm tốc độ cao (KV) chỉ trong vài phút — vận hành tức thì trên hơn 300 trung tâm dữ liệu toàn cầu mà không lo cold start.

1. Mô hình hoạt động (ELI5: Giải thích đơn giản)#

Hãy tưởng tượng hệ thống như một nhà hàng cao cấp:

  • Cloudflare Worker (Người phục vụ / Đầu bếp): Tiếp nhận yêu cầu từ thực khách, xử lý logic và phục vụ món ăn ngay tại bàn ở chi nhánh gần khách nhất.
  • Cloudflare KV (Quầy đồ ăn nhanh / Bộ nhớ đệm): Lưu sẵn các món ăn phổ biến vừa chế biến. Khi khách gọi món quen thuộc, người phục vụ lấy ngay lập tức mà không cần vào bếp (đọc siêu nhanh, độ trễ < 1ms).
  • Cloudflare D1 (Kho nguyên liệu & Sổ công thức / Cơ sở dữ liệu SQL): Cơ sở dữ liệu SQLite serverless lưu trữ bền vững tất cả dữ liệu gốc và thực hiện các truy vấn SQL chính xác, toàn vẹn.
graph TD
    Client["📱 Khách hàng (Client Request)"] -->|HTTP GET/POST| Worker["⚡ Cloudflare Worker (Edge API)"]
    Worker -->|1. Kiểm tra Cache| KV["⚡ Cloudflare KV (Đọc Cache siêu nhanh)"]
    KV -.->|Cache Hit - Trả lời ngay| Worker
    KV -.->|Cache Miss| D1
    Worker -->|2. Truy vấn/Ghi dữ liệu| D1["🗄️ Cloudflare D1 (Serverless SQLite)"]
    D1 -->|3. Cập nhật Cache| KV
    Worker -->|HTTP JSON Response| Client

2. Khởi tạo Dự án với Wrangler CLI#

Đảm bảo bạn đã cài đặt Node.js hoặc Bun và có tài khoản Cloudflare miễn phí.

Bước 1: Khởi tạo Project Worker#

Sử dụng bộ công cụ C3 (create-cloudflare) hoặc khởi tạo trực tiếp với TypeScript:

# Khởi tạo project TypeScript
npm create cloudflare@latest edge-api -- --type=hello-world-typescript --ts --git --deploy=false
cd edge-api
bash

Cài đặt Wrangler CLI mới nhất vào dependencies nếu chưa có:

npm install -D wrangler
bash

Đăng nhập tài khoản Cloudflare qua trình duyệt:

npx wrangler login
bash

3. Khởi tạo Cơ sở Dữ liệu Cloudflare D1 (SQL)#

Cloudflare D1 là cơ sở dữ liệu quan hệ serverless chạy trên nền tảng SQLite được phân tán toàn cầu.

Bước 1: Tạo Database D1#

Chạy lệnh sau để tạo một database mang tên ecommerce-db:

npx wrangler d1 create ecommerce-db
bash

Wrangler sẽ trả về đoạn cấu hình tương tự như sau:

[[d1_databases]]
binding = "DB"
database_name = "ecommerce-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
text

Bước 2: Tạo Schema và Chạy Migration#

Tạo tệp schema.sql trong thư mục gốc của dự án:

schema.sql
DROP TABLE IF EXISTS products;

CREATE TABLE products (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  price REAL NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO products (id, name, price) VALUES
  ('prod_1', 'Bàn phím cơ không dây', 129.99),
  ('prod_2', 'Màn hình Gaming Ultra-Wide', 499.99),
  ('prod_3', 'Bàn nâng hạ Ergonomic', 349.50);
sql

Chạy schema trên môi trường cục bộ (Local Development):

npx wrangler d1 execute ecommerce-db --local --file=./schema.sql
bash

Chạy schema trên cơ sở dữ liệu đám mây Production:

npx wrangler d1 execute ecommerce-db --remote --file=./schema.sql
bash

4. Khởi tạo Bộ nhớ đệm Cloudflare KV#

Cloudflare KV là kho lưu trữ Key-Value toàn cầu, tối ưu hóa cho các thao tác đọc tần suất cao với độ trễ cực thấp.

Bước 1: Tạo KV Namespace#

Tạo 2 namespace cho môi trường Production và Preview:

# Tạo namespace Production
npx wrangler kv namespace create CACHE_KV

# Tạo namespace Preview (cho testing)
npx wrangler kv namespace create CACHE_KV --preview
bash

Wrangler sẽ xuất ra các ID tương ứng:

[[kv_namespaces]]
binding = "CACHE_KV"
id = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
preview_id = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
text

5. Cấu hình tệp wrangler.toml#

Thêm cấu hình binding của D1 và KV vào tệp wrangler.toml:

wrangler.toml
name = "edge-api"
main = "src/index.ts"
compatibility_date = "2026-08-01"

# Binding D1 Database
[[d1_databases]]
binding = "DB"
database_name = "ecommerce-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# Binding KV Cache
[[kv_namespaces]]
binding = "CACHE_KV"
id = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
preview_id = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
toml

Tự động sinh TypeScript Types cho các bindings:

npx wrangler types
bash

6. Viết mã nguồn API theo mô hình Cache-Aside#

Mở tệp src/index.ts và triển khai chiến lược Cache-Aside Pattern:

  1. Tiếp nhận request GET /api/products/:id, kiểm tra dữ liệu trong KV Cache trước.
  2. Nếu có (Cache HIT): Trả về dữ liệu ngay lập tức.
  3. Nếu không có (Cache MISS): Truy vấn D1 Database, lưu kết quả vào KV với thời gian sống (TTL), sau đó trả về.
  4. Khi có request POST /api/products: Thêm bản ghi mới vào D1 và cập nhật cache trong KV.

[!TIP] Sử dụng ctx.waitUntil(...) khi cập nhật KV Cache để API phản hồi ngay lập tức cho client mà không bị chặn lại bởi tiến trình ghi cache ngầm.

7. Chạy thử Cục bộ và Triển khai lên Production#

Chạy Local Development#

Chạy server giả lập D1 và KV trên máy cá nhân:

npx wrangler dev
bash

Kiểm tra API bằng lệnh curl:

# Lần gọi đầu tiên (MISS - đọc từ D1)
curl http://localhost:8787/api/products/prod_1

# Lần gọi thứ hai (HIT - đọc từ KV Cache)
curl http://localhost:8787/api/products/prod_1
bash

Triển khai lên Mạng Toàn Cầu (Production)#

Deploy mã nguồn lên toàn bộ mạng lưới Edge của Cloudflare chỉ bằng 1 câu lệnh:

npx wrangler deploy
bash

Hệ thống sẽ cung cấp ngay một đường dẫn trực tiếp dạng https://edge-api.<subdomain>.workers.dev hoạt động tại hơn 300 thành phố trên thế giới!

8. Nếu viết bằng Rust và Axum thì khác biệt thế nào?#

Nếu bạn yêu thích sự an toàn tuyệt đối về bộ nhớ và hiệu năng tối đa của Rust, Cloudflare Workers hoàn toàn hỗ trợ biên dịch Rust sang WebAssembly (wasm32-unknown-unknown) và tích hợp mượt mà với framework Axum thông qua worker-rs.

So sánh Kiến trúc: TypeScript vs Rust (Axum)#

graph LR
    subgraph TS["TypeScript Worker"]
        direction TB
        TS_Code["src/index.ts"] --> V8["Engine V8 Isolate<br/>(Native JS bindings)"]
        V8 --> DB_TS["env.DB / env.CACHE_KV"]
    end

    subgraph RS["Rust + Axum Worker"]
        direction TB
        RS_Code["src/lib.rs (Axum Router)"] --> WASM["Module WebAssembly<br/>(wasm32-unknown-unknown)"]
        WASM --> WRS["Cầu nối FFI worker-rs"]
        WRS --> DB_RS["env.d1('DB') / env.kv('CACHE_KV')"]
    end
Tiêu chíTypeScriptRust (Axum + worker-rs)
Môi trường thực thiJavaScript chạy trực tiếp trên V8 IsolateWebAssembly (.wasm) được biên dịch qua worker-build
Mô hình định tuyến (Routing)Hàm fetch(request, env, ctx) tiêu chuẩnaxum::Router mạnh mẽ với các extractor (State, Path, Json)
Truy cập Binding (D1, KV)Đối tượng có sẵn: env.DB, env.CACHE_KVThông qua worker::Env FFI: env.d1("DB")?, env.kv("CACHE_KV")?
Hiệu năng & An toànPhát triển nhanh, kiểm tra kiểu ở build timeAn toàn bộ nhớ tuyệt đối, zero-cost abstractions, mã máy WASM
Cấu hình wrangler.tomlmain = "src/index.ts"main = "build/worker/shim.mjs" kèm lệnh build: [build] command = "worker-build --release"

Code mẫu Rust Axum kết hợp D1 và KV#

Trong Rust, ta khởi tạo axum::Router ngay trong hàm bắt sự kiện fetch của worker, chia sẻ worker::Env thông qua Axum State:

9. Bảng Tổng hợp Lệnh Wrangler Thường Dùng#

Lệnh WranglerCông dụng
wrangler loginĐăng nhập tài khoản Cloudflare vào CLI
wrangler devKhởi động môi trường giả lập local với D1 & KV
wrangler d1 create <name>Khởi tạo cơ sở dữ liệu D1 mới
wrangler d1 execute <name> --file=./schema.sqlChạy file SQL tạo bảng dữ liệu (--local hoặc --remote)
wrangler kv namespace create <name>Tạo kho lưu trữ KV mới
wrangler typesTự động sinh kiểu dữ liệu TypeScript cho Env
wrangler deployBuild và deploy Worker lên Production toàn cầu
wrangler tailXem log trực tiếp thời gian thực từ Production

Tài liệu tham khảo#