Đang tải...

Ếch Trendy

Cùng chú ếch nhỏ khám phá thế giới Web đầy biến động. Cập nhật trending nhanh như cách ếch đớp mồi! ⌨️🌿


0

Serverless và Edge Computing cho web app: Deploy nhanh, scale tốt, giảm latency

Ếch Trendy
Ếch Trendy

2 tháng trước · 6 phút đọc

Mình từng deploy sai cách suốt 2 năm

Hồi mới làm web, mình cứ nghĩ deploy là thuê một cái VPS, cài Nginx, chạy Node.js, xong. App có vài trăm người dùng thì ổn. Nhưng khi traffic tăng đột biến - ví dụ chạy campaign marketing - server cứng đờ, latency nhảy lên 2-3 giây, và mình ngồi scale tay lúc 2 giờ sáng.

Vấn đề không phải ở code. Vấn đề ở kiến trúc.

Serverless và edge computing ra đời để giải quyết đúng cái pain point này: bạn không cần quản lý server, không cần lo scale, và request được xử lý ở vị trí gần người dùng nhất. Nghe hay - nhưng không phải lúc nào cũng là silver bullet. Bài này mình sẽ breakdown từng kiến trúc, so sánh thẳng vào trade-off, rồi hướng dẫn deploy thực tế trên các platform phổ biến nhất.

346701 Ba hướng tiếp cận - mỗi cái phù hợp một bài toán khác nhau

Bạn sẽ biết khi nào nên dùng cái gì, không phải cứ hype là theo.


Serverless, edge, và server truyền thống - khác nhau ở đâu?

Để chọn đúng công cụ, cần hiểu rõ cách mỗi kiến trúc hoạt động.

Server truyền thống (VPS/dedicated): Bạn thuê một máy chủ, cài OS, cài runtime, deploy app. App chạy liên tục 24/7 dù có request hay không. Scale bằng cách thêm instance thủ công hoặc auto-scaling group. Chi phí cố định theo tháng, dù traffic thấp vẫn trả đủ.

Serverless: Function được đóng gói và chỉ chạy khi có request. Platform (AWS Lambda, Vercel, Supabase Edge) lo toàn bộ infrastructure. Bạn trả tiền theo số lần gọi và thời gian thực thi - không có request, không mất tiền. Trade-off lớn nhất là cold start: lần đầu gọi function sau thời gian idle, platform cần khởi động container, thêm 100-500ms latency.

Edge computing: Function chạy trên mạng lưới CDN toàn cầu, tại node gần người dùng nhất. Thay vì request bay từ Hà Nội về server ở Singapore (50-80ms), nó xử lý ngay tại node ở Hà Nội (<10ms). Giới hạn: runtime thường là V8 isolates (không phải Node.js đầy đủ), không có file system, giới hạn bundle size.

346702 Latency giảm đáng kể khi request được xử lý gần người dùng hơn

Bảng so sánh nhanh:

Server truyền thống Serverless Edge
Cold start Không 100-500ms <5ms
Latency Phụ thuộc vị trí Phụ thuộc vị trí Thấp nhất
Chi phí Cố định Theo request Theo request
Scale Thủ công/cấu hình Tự động Tự động
Runtime Đầy đủ Đầy đủ Giới hạn
Truy cập DB Dễ Cần connection pool Khó (cần adapter)

Không có kiến trúc nào "tốt nhất" - chỉ có kiến trúc phù hợp nhất với use case của bạn.


Deploy thực tế: Vercel Edge Functions và Cloudflare Workers

Mình bắt đầu với 2 platform phổ biến nhất cho edge - vì setup nhanh, free tier rộng, và phù hợp cho hầu hết web app.

Vercel Edge Functions

Vercel Edge Functions chạy trên V8 isolates, deploy tự động khi push code. Phù hợp nhất khi bạn đã dùng Next.js.

// app/api/hello/route.ts (Next.js App Router)
export const runtime = 'edge'; // Khai báo dùng Edge runtime

export async function GET(request: Request) {
  // Lấy vị trí người dùng từ header Vercel tự inject
  const country = request.headers.get('x-vercel-ip-country') || 'VN';
  
  return new Response(
    JSON.stringify({ message: `Xin chào từ ${country}!` }),
    {
      headers: {
        'Content-Type': 'application/json',
        // Cache 60s tại edge node
        'Cache-Control': 's-maxage=60, stale-while-revalidate'
      }
    }
  );
}

Lưu ý quan trọng: Edge runtime không hỗ trợ Node.js built-ins như fs, path, hay nhiều npm packages dùng native modules. Kiểm tra compatibility trước khi migrate.

Cloudflare Workers

Cloudflare Workers mạnh hơn ở chỗ có thêm KV Store (key-value storage tại edge), Durable Objects (stateful), và R2 (object storage). Phù hợp khi cần state nhẹ tại edge.

// worker.js - Cloudflare Worker
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    
    // Đọc cache từ KV Store
    const cached = await env.MY_KV.get(url.pathname);
    if (cached) {
      return new Response(cached, {
        headers: { 'X-Cache': 'HIT', 'Content-Type': 'application/json' }
      });
    }
    
    // Fetch từ origin nếu không có cache
    const data = await fetch('https://api.example.com' + url.pathname);
    const json = await data.text();
    
    // Lưu cache 5 phút, không block response
    ctx.waitUntil(env.MY_KV.put(url.pathname, json, { expirationTtl: 300 }));
    
    return new Response(json, {
      headers: { 'X-Cache': 'MISS', 'Content-Type': 'application/json' }
    });
  }
};

346703 ctx.waitUntil() giúp cache không làm chậm response - một pattern quan trọng ở edge

Deploy Cloudflare Worker:

# Cài Wrangler CLI
npm install -g wrangler

# Đăng nhập
wrangler login

# Tạo project mới
wrangler init my-worker

# Deploy
wrangler deploy

Free tier của Cloudflare Workers cho phép 100,000 requests per day (Cloudflare Workers Documentation) request/ngày - đủ để chạy side project hoặc MVP thoải mái.


AWS Lambda và Supabase Edge Functions

AWS Lambda - Serverless cho backend phức tạp

Lambda phù hợp khi bạn cần runtime đầy đủ (Python, Java, Go, Node.js), truy cập database phức tạp, hoặc tích hợp sâu với AWS ecosystem (RDS, DynamoDB, SQS).

Vấn đề lớn nhất với Lambda + database là connection exhaustion: mỗi Lambda instance mở một connection riêng tới DB. Khi scale lên hàng trăm concurrent request, bạn sẽ thấy lỗi "too many connections".

Giải pháp: dùng RDS Proxy hoặc PgBouncer để pool connections.

// lambda/handler.js - Kết nối DB qua connection pool
import { Pool } from 'pg';

// Khởi tạo pool ngoài handler để tái sử dụng giữa các invocation
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 1, // Lambda nên giữ max 1 connection/instance
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 5000,
});

export const handler = async (event) => {
  const client = await pool.connect();
  
  try {
    const result = await client.query(
      'SELECT id, name FROM users WHERE active = $1 LIMIT 10',
      [true]
    );
    
    return {
      statusCode: 200,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(result.rows)
    };
  } finally {
    // Trả connection về pool, không đóng hẳn
    client.release();
  }
};

Tối ưu cold start Lambda:

  • Giảm bundle size: dùng esbuild thay vì webpack, tree-shake aggressively
  • Dùng Provisioned Concurrency nếu latency nhất quán là ưu tiên (tốn thêm chi phí)
  • Giữ Lambda warm bằng scheduled ping (EventBridge rule mỗi 5 phút)
  • Tránh import toàn bộ AWS SDK - chỉ import module cần thiết
// Tệ - import toàn bộ SDK, tăng bundle size đáng kể
import AWS from 'aws-sdk';

// Tốt - chỉ import DynamoDB
import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb';

346704 Bundle size nhỏ = cold start nhanh hơn - đây là trade-off dễ bị bỏ qua

Supabase Edge Functions

Supabase Edge Functions chạy trên Deno runtime, tích hợp trực tiếp với Supabase database và auth. Lý tưởng cho backend của app có Supabase làm nền tảng.

// supabase/functions/send-notification/index.ts
import { serve } from 'https://deno.land/[email protected]/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

serve(async (req) => {
  const supabase = createClient(
    // Env vars tự inject từ Supabase dashboard
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
  );
  
  const { userId, message } = await req.json();
  
  // Insert notification vào DB
  const { error } = await supabase
    .from('notifications')
    .insert({ user_id: userId, message, created_at: new Date() });
  
  if (error) throw error;
  
  return new Response(JSON.stringify({ success: true }), {
    headers: { 'Content-Type': 'application/json' }
  });
});

Deploy:

supabase functions deploy send-notification

Nếu bạn đang xây dựng backend phức tạp hơn với Node.js, khóa Node & ExpressJS có thể giúp củng cố nền tảng trước khi bước vào serverless.


Use case thực tế: chọn kiến trúc nào cho từng loại app?

Đây là phần mình nghĩ quan trọng nhất - vì lý thuyết hay nhưng áp dụng sai vẫn là sai.

Blog / Content site

Kiến trúc: Static Generation + Edge CDN

Build HTML tĩnh lúc deploy (Next.js generateStaticParams, Astro, Hugo), đẩy lên CDN. Khi cần dynamic content (comments, view count), dùng Edge Functions để fetch từ edge cache.

Latency: dưới 50ms toàn cầu. Chi phí: gần như 0 (Vercel/Netlify free tier đủ dùng cho hầu hết blog cá nhân).

SaaS app

Kiến trúc: Serverless Functions + Managed Database

API routes là serverless functions (Vercel API Routes hoặc AWS Lambda). Database dùng PlanetScale, Neon, hoặc Supabase - các dịch vụ này có connection pooling built-in, giải quyết vấn đề cold start + DB connection.

Tiền: tốn hơn server truyền thống ở low traffic, nhưng scale tốt hơn ở high traffic mà không cần ops.

Realtime app (chat, live dashboard)

Kiến trúc: Edge + WebSocket hoặc SSE

Edge Functions không giữ được long-lived connections tốt. Giải pháp: dùng Cloudflare Durable Objects cho WebSocket state, hoặc Supabase Realtime (built on PostgreSQL LISTEN/NOTIFY).

// Cloudflare Durable Object cho WebSocket
export class ChatRoom {
  constructor(state, env) {
    this.state = state;
    this.sessions = []; // Danh sách WebSocket sessions
  }

  async fetch(request) {
    if (request.headers.get('Upgrade') === 'websocket') {
      const pair = new WebSocketPair();
      const [client, server] = Object.values(pair);
      
      server.accept();
      this.sessions.push(server);
      
      server.addEventListener('message', (event) => {
        // Broadcast tới tất cả sessions trong room
        this.sessions.forEach(s => s.send(event.data));
      });
      
      return new Response(null, { status: 101, webSocket: client });
    }
  }
}

E-commerce

Kiến trúc: Hybrid - Static + Serverless + Edge

Trang sản phẩm: static generation với ISR (Incremental Static Regeneration) - rebuild khi giá/stock thay đổi. Giỏ hàng + checkout: serverless functions với database. Personalization (gợi ý sản phẩm theo region): Edge Middleware.

// middleware.ts (Next.js) - chạy tại edge, redirect theo region
import { NextResponse } from 'next/server';

export function middleware(request) {
  const country = request.geo?.country || 'VN';
  const url = request.nextUrl.clone();
  
  // Redirect về trang giá theo currency phù hợp
  if (country === 'US' && !url.pathname.startsWith('/en')) {
    url.pathname = '/en' + url.pathname;
    return NextResponse.redirect(url);
  }
  
  return NextResponse.next();
}

export const config = {
  matcher: ['/products/:path*', '/checkout/:path*']
};

346705 Hybrid architecture giúp e-commerce vừa load nhanh vừa personalized


Monitoring, environment variables, và deployment checklist

Deploy lên production mà thiếu phần này thì sớm muộn cũng có sự cố.

Environment variables

Khác với server truyền thống, mỗi platform có cách inject env vars khác nhau. Quy tắc chung:

  • Không bao giờ hardcode secret vào code
  • Vercel: quản lý qua dashboard > Settings > Environment Variables, hoặc vercel env add
  • Cloudflare Workers: dùng wrangler secret put SECRET_NAME cho secrets, wrangler.toml cho config thông thường
  • AWS Lambda: Environment Variables trong function configuration, hoặc AWS Systems Manager Parameter Store cho secrets nhạy cảm hơn
# Cloudflare - thêm secret (không lưu vào wrangler.toml)
wrangler secret put DATABASE_URL
# Nhập giá trị và Enter

# Vercel CLI
vercel env add DATABASE_URL production

Monitoring

Serverless khó debug hơn server truyền thống vì không có persistent log file. Dùng:

  • Vercel Analytics + Logs: built-in, xem real-time từ dashboard
  • Cloudflare Workers Analytics: request count, error rate, CPU time
  • AWS CloudWatch: logs, metrics, alerts - cần cấu hình thêm
  • Sentry: error tracking cross-platform, free tier hào phóng
// Thêm Sentry vào Edge Function (Cloudflare Workers)
import * as Sentry from '@sentry/cloudflare';

export default Sentry.withSentry(
  (env) => ({
    dsn: env.SENTRY_DSN,
    tracesSampleRate: 0.1, // 10% requests để tránh tốn quota
  }),
  {
    async fetch(request, env, ctx) {
      // Code xử lý request của bạn
      return new Response('OK');
    }
  }
);

346706 Monitoring từ đầu giúp phát hiện vấn đề trước khi user complain

Deployment checklist

Mình tổng hợp checklist này từ kinh nghiệm deploy thực tế. Tải về để dùng:

Tải Serverless Deployment Checklist

Các điểm quan trọng nhất:

  • [ ] Kiểm tra bundle size (edge functions thường giới hạn 1-5MB)
  • [ ] Test cold start time trên staging
  • [ ] Cấu hình timeout phù hợp (Vercel Edge: 30s, Lambda: tối đa 15 phút)
  • [ ] Set up alerts khi error rate vượt ngưỡng
  • [ ] Verify environment variables đã set đủ cho môi trường production
  • [ ] Kiểm tra CORS headers nếu API được gọi từ domain khác
  • [ ] Enable compression (gzip/brotli) cho response
  • [ ] Test rollback procedure - biết cách revert nhanh nếu có sự cố

Trang web dùng cookie để hoạt động và đo hiệu quả quảng cáo. Xem chính sách bảo mật