Đ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

Edge Computing SSR: Tối Ưu Latency Web App Việt Với Next.js 2026

Ếch Trendy
Ếch Trendy

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

Edge computing là gì và tại sao app Việt cần nó?

Mình đã từng nhìn DevTools và thấy TTFB 800ms trên mạng Viettel. Không phải code chậm - mà request đang bay từ Hà Nội sang Singapore rồi mới quay về. Đó là vấn đề của mô hình server truyền thống: bạn deploy ở 1 nơi, người dùng ở khắp nơi.

Edge computing giải quyết đúng chỗ đau này. Thay vì chạy SSR trên origin server ở một region cố định, code của bạn được deploy ra hàng chục - hàng trăm điểm hiện diện (PoP - Point of Presence) rải khắp thế giới. Request từ TP.HCM sẽ được xử lý tại node gần nhất, không cần vòng vèo qua Mỹ hay châu Âu.

342449 Request từ Hà Nội không cần bay sang Singapore nữa - edge node xử lý tại chỗ

Với Next.js, điều này có nghĩa SSR chạy ngay tại edge, không phải origin. Kết quả? TTFB giảm mạnh, đặc biệt trên mobile 4G/5G của Viettel hay VNPT - nơi mỗi mili-giây đều có giá.

Con số 94.3% (DataReportal) người dùng internet Việt Nam truy cập web chủ yếu qua mobile. Nếu app bạn build chạy chậm trên điện thoại, bạn đang mất người dùng ngay từ lần đầu tiên họ mở trang.


Vercel vs Netlify Edge: Chọn cái nào cho Next.js?

Hai nền tảng này đều support Next.js edge deployment tốt, nhưng trade-off khác nhau rõ ràng.

Vercel Netlify
Edge Runtime V8 Isolates Deno
TTFB trung bình ~70ms ~90ms
Next.js SSR/ISR First-class (cùng team) Feature parity
Syntax env var process.env.X Netlify.env.get('X')
Function timeout 10s (free), 5 phút (Pro) 10s (free), 15 phút (background)
Cold start Gần zero (V8 isolates) Thấp (Deno precompile)
Điểm mạnh Realtime SSR, middleware Async tasks, background jobs

342450 Vercel nhanh hơn cho SSR thuần, Netlify linh hoạt hơn cho background tasks

Nếu bạn build realtime app - chat, live feed, personalized content - chọn Vercel. V8 isolates có cold start gần bằng không, TTFB ~70ms là con số ổn định cho production. Vercel cũng tự sinh ra Next.js nên mọi feature mới (App Router, Partial Prerendering, Server Actions) đều được support đầu tiên.

Nếu app cần background processing - gửi email, xử lý hàng đợi, webhook có timeout dài - Netlify xử lý tốt hơn với background functions lên đến 15 phút. Netlify cũng dùng Deno nên TypeScript native, không cần config thêm.

Một điểm thực tế: nếu bạn đang dùng Vercel và muốn migrate sang Netlify, có tool tự động convert Edge Functions. Nhưng lưu ý syntax khác nhau, đặc biệt cách đọc env vars và geolocation API.

Với app Việt nhắm vào mobile users trên Viettel/VNPT/Mobifone, cả hai platform đều có hơn 100 PoP global với coverage ở Đông Nam Á. Vercel có edge node tại Singapore (gần VN nhất), Netlify dùng shared enterprise network tương tự.


Thiết lập Edge Functions trên Vercel với Next.js

Bắt đầu với Vercel - đây là path ít friction nhất nếu bạn đang dùng Next.js App Router.

1. Khai báo Edge Runtime cho Route

Thêm runtime export vào bất kỳ Route Handler hoặc Server Component nào:

// app/api/feed/route.ts
export const runtime = 'edge';

export async function GET(request: Request) {
  // Đọc geolocation từ header Vercel inject tự động
  const country = request.headers.get('x-vercel-ip-country') ?? 'VN';
  const city = request.headers.get('x-vercel-ip-city') ?? 'Ho Chi Minh City';

  // Trả nội dung personalized theo vị trí
  const feed = await fetchLocalizedFeed(country, city);

  return Response.json({ feed, location: { country, city } });
}

2. Middleware chạy 100% ở edge

File middleware.ts ở root luôn chạy trên edge runtime:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const country = request.geo?.country ?? 'VN';

  // A/B testing: 50% user VN xem variant B
  if (country === 'VN') {
    const isVariantB = Math.random() < 0.5;
    const response = NextResponse.next();
    response.cookies.set('ab-variant', isVariantB ? 'B' : 'A');
    return response;
  }

  return NextResponse.next();
}

export const config = {
  // Chỉ chạy middleware cho các route này
  matcher: ['/home', '/products/:path*'],
};

342451 Middleware chạy trước mọi request - logic nhẹ ở đây, không xử lý nặng

3. Cache response để giảm compute

Edge function chạy nhanh nhưng vẫn tốn compute. Với nội dung semi-dynamic, dùng Cache-Control hoặc next/cache:

export async function GET() {
  const data = await fetchTrendingProducts();

  return Response.json(data, {
    headers: {
      // Cache tại edge 60s, revalidate background sau 30s
      'Cache-Control': 's-maxage=60, stale-while-revalidate=30',
    },
  });
}

Một lưu ý quan trọng: Edge Runtime không hỗ trợ toàn bộ Node.js API. Không có fs, không có child_process, không có native addons. Nếu code đang dùng những thứ này, bạn cần refactor hoặc chuyển sang Serverless Functions thông thường.


Thiết lập Edge Functions trên Netlify

Netlify dùng Deno runtime, nên syntax hơi khác. Không khó, nhưng cần biết trước để tránh debug mất thời gian.

Tạo edge function cơ bản:

// netlify/edge-functions/personalize.ts
import type { Context } from '@netlify/edge-functions';

export default async function handler(
  request: Request,
  context: Context
) {
  // Netlify inject geo data qua context, không phải header
  const country = context.geo?.country?.code ?? 'VN';
  const city = context.geo?.city ?? 'Ho Chi Minh City';

  // Đọc env var theo kiểu Deno, không phải process.env
  const apiKey = Netlify.env.get('API_KEY');

  const response = await context.next();
  response.headers.set('x-user-country', country);
  return response;
}

// Khai báo route nào dùng function này
export const config = {
  path: '/api/personalize',
};

Routing qua netlify.toml:

[[edge_functions]]
function = "personalize"
path = "/api/*"

342452 Netlify Edge dùng Deno - đọc kỹ docs API vì syntax khác Node.js

Điểm mạnh của Netlify là background functions - chạy async sau khi response đã trả về user:

// netlify/functions/send-notification.mts
import type { BackgroundHandler } from '@netlify/functions';

// Handler này chạy background, timeout 15 phút
export const handler: BackgroundHandler = async (event) => {
  const { userId, message } = JSON.parse(event.body ?? '{}');

  // Gửi push notification, email, update DB...
  // User không phải chờ response
  await sendPushNotification(userId, message);
  await logToAnalytics({ userId, event: 'notification_sent' });
};

Khi người dùng Việt submit form đăng ký, response trả về ngay (202 Accepted), còn email confirmation chạy ở background. Đây là pattern phù hợp với realtime apps - không block UI vì server đang xử lý.

Nếu project bạn đang dùng Next.js trên Vercel và muốn thử Netlify, có thể tham khảo Hướng dẫn migrate Next.js từ Vercel sang Netlify để biết cách migrate.


Benchmark thực tế và chiến lược đo latency app Việt

Con số 70% giảm latency không phải magic - nó xuất phát từ việc loại bỏ hàng trăm ms round-trip không cần thiết. Nhưng để đạt được, bạn cần đo đúng.

Các metrics quan trọng cần theo dõi:

  • TTFB (Time to First Byte): Thời gian từ lúc browser gửi request đến byte đầu tiên nhận được. Đây là metric bị ảnh hưởng nhiều nhất bởi edge deployment.
  • FCP (First Contentful Paint): Người dùng thấy nội dung đầu tiên. Liên quan đến TTFB nhưng còn phụ thuộc render path.
  • LCP (Largest Contentful Paint): Core Web Vital quan trọng nhất với SEO Google.

Tool đo từ Việt Nam:

Thay vì chỉ dùng Lighthouse local, bạn cần đo từ các điểm thực tế tại VN:

# WebPageTest với location Hà Nội hoặc TP.HCM
# Dùng API để automate benchmark
curl "https://www.webpagetest.org/runtest.php?url=https://yourapp.com&location=HaNoi:Chrome&runs=3&f=json&k=YOUR_API_KEY"

Hoặc dùng WebPageTest - Đo tốc độ từ Việt Nam để test trực tiếp từ nhiều điểm tại Việt Nam.

342453 So sánh TTFB trước và sau khi chuyển sang edge - số liệu tự đo mới tin được

Benchmark thực tế Vercel Edge vs Origin:

Vercel ghi nhận 70 ms (Clarifai Blog: Vercel vs Netlify in 2026) TTFB trung bình cho edge functions, so với 200-400ms với serverless functions thông thường. Tuy nhiên, con số này đo từ các region phương Tây. Với Việt Nam, kết quả phụ thuộc vào:

  • ISP: Viettel có peering tốt hơn VNPT với một số CDN
  • Thời điểm trong ngày: giờ cao điểm tối (8-10pm) thường chậm hơn
  • Network type: WiFi vs 4G vs 5G cho kết quả khác nhau

Checklist tối ưu trước khi benchmark:

  1. Xác nhận route đang thật sự chạy edge (export const runtime = 'edge')
  2. Kiểm tra không có import nào dùng Node.js-only API
  3. Bật cache headers phù hợp cho semi-static content
  4. Dùng streaming response cho large payloads thay vì chờ toàn bộ data
  5. Prefetch DNS và preconnect đến external APIs bạn gọi từ edge function

Một pattern mình thấy hiệu quả: dùng Streaming SSR thay vì chờ full render. React 18 + Next.js App Router support Suspense boundaries, cho phép browser bắt đầu render HTML shell ngay trong khi data vẫn đang fetch.


Realtime app pattern với Edge SSR: Chat và live feed

Đây là use case mình thấy nhiều nhất khi người ta hỏi "edge có cần thiết không?". Câu trả lời: với realtime, có, rõ ràng.

Vấn đề của realtime app trên centralized server: mỗi poll hoặc WebSocket handshake đều phải đi về origin. Với 10.000 concurrent users tại VN, mỗi request bay qua 2-3 hop trước khi chạm server.

Streaming response từ Edge:

// app/api/stream/route.ts
export const runtime = 'edge';

export async function GET() {
  const stream = new ReadableStream({
    async start(controller) {
      const encoder = new TextEncoder();

      // Gửi chunks dữ liệu ngay khi có, không đợi full response
      for await (const chunk of fetchLiveFeed()) {
        controller.enqueue(
          encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`)
        );
      }

      controller.close();
    },
  });

  return new Response(stream, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
    },
  });
}

342454 Server-Sent Events từ edge - browser nhận data ngay khi có, không cần polling

Client-side nhận stream:

// components/LiveFeed.tsx
'use client';
import { useEffect, useState } from 'react';

export function LiveFeed() {
  const [items, setItems] = useState<FeedItem[]>([]);

  useEffect(() => {
    // EventSource tự reconnect nếu mất kết nối
    const source = new EventSource('/api/stream');

    source.onmessage = (event) => {
      const newItem = JSON.parse(event.data);
      setItems(prev => [newItem, ...prev].slice(0, 50)); // Giữ 50 items
    };

    return () => source.close();
  }, []);

  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.content}</li>
      ))}
    </ul>
  );
}

Pattern này dùng Server-Sent Events (SSE) thay vì WebSocket vì SSE hoạt động qua HTTP/2, dễ đi qua proxy và firewall hơn, phù hợp với hạ tầng mạng Việt Nam. WebSocket thỉnh thoảng bị một số ISP throttle.

Còn nếu bạn muốn nền tảng vững chắc để build app fullstack với Next.js từ đầu, khóa Frontend NextJS tại F8 cover App Router, SSR, và các patterns thực tế như thế này theo từng bước.

Giờ bạn đã có đủ để bắt tay vào:

  1. Thêm export const runtime = 'edge' vào các route cần tốc độ
  2. Deploy lên Vercel (realtime/SSR) hoặc Netlify (background tasks) tùy use case
  3. Đo TTFB từ Việt Nam với WebPageTest - không đoán mò
  4. Implement SSE thay vì polling cho realtime features

Gặp vấn đề gì trong quá trình setup, drop comment. Mình hay lướt qua.