Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

Implement Rate Limiting ใน Next.js ด้วย Vercel Edge และ Upstash Redis

ในบทความนี้ ผมจะแนะนำการ implement rate limiting ใน web application ใช้ Vercel Edge Middleware และ library @upstash/ratelimit ตัวหลังใช้ Redis ที่ backend สำหรับ storage และ management ของ rate limit data

ข้อดีของการใช้ Vercel Edge

Vercel Edge เป็น computing platform ที่คำนวณที่ locations ใกล้ user มากที่สุด ผมจะใช้ Vercel Edge Middleware ที่ intercept requests ก่อนถึง backend ผมเชื่อมัน ideal สำหรับ rate limiting implementation หลายเหตุผล:

  • Decoupled จาก backend บล็อก traffic ที่ edge location ก่อนถึง backend
  • เร็ว ไม่มี cold start issues ทำให้ overhead น้อยที่สุด
  • คุ้มค่ากว่า serverless functions

ทำไมถึง @upstash/ratelimit?

  • @upstash/ratelimit เป็น rate limiting library ที่ออกแบบและทดสอบมาเฉพาะสำหรับ edge functions
  • รองรับ multi-region Redis สำหรับ optimal latency จาก edge locations
  • Upstash Redis เป็น managed Redis เพียงตัวที่เข้าถึงได้จาก edge functions ขอบคุณ REST API

มาเริ่ม implementation กัน:

Step 1: Redis Setup

สร้าง Redis database บน Upstash Console หรือ Upstash CLI ต้องการ UPSTASH_REDIS_REST_URL และ UPSTASH_REDIS_REST_TOKEN สำหรับขั้นตอนต่อไป

Implement Rate Limiting ใน Next.js ด้วย Vercel Edge และ Upstash Redis

Step 2: Next.js Setup

สร้าง Next.js application (เช็ก ที่นี่ สำหรับ frameworks อื่น)

npx create-next-app@latest --typescript

ติดตั้ง @upstash/ratelimit:

npm i @upstash/ratelimit

สร้าง middleware.ts (top level ใน project folder):

import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

const redis = new Redis({
  url: "https://us1-merry-snake-32728.upstash.io",
  token: "AX_sAdsdfsgODM5ZjExZGEtMmmVjNmE345445kGVmZTk5MzQ=",
});

const ratelimit = new Ratelimit({
  redis: redis,
  limiter: Ratelimit.slidingWindow(5, "10 s"),
});

export default async function middleware(
  request: NextRequest,
  event: NextFetchEvent,
): Promise<Response | undefined> {
  const ip = request.ip ?? "127.0.0.1";
  const { success, pending, limit, reset, remaining } = await ratelimit.limit(ip);
  
  return success ? NextResponse.next() : NextResponse.redirect(new URL("/blocked", request.url));
}

export const config = {
  matcher: "/",
};

อย่าลืมแทนที่ redis url และ token ของคุณ โค้ดใช้ algorithm slidingWindow อนุญาต 5 requests จาก IP เดียวใน 10 วินาที ถ้ามี property unique ต่อ user (userid, email ฯลฯ) ใช้แทน IP ได้ หาก request ถูก rate limited middleware จะ redirect ไป blocked page

สร้าง pages/blocked.tsx:

import styles from "@/styles/Home.module.css";

export default function Blocked() {
  return (
    <div>
      <main className={styles.main}>
        <h3>Access blocked.</h3>
      </main>
    </div>
  );
}

แค่นี้! Deploy app ไป Vercel: vercel deploy

Refresh หน้า ควร redirect ไป blocked page หลัง 3 ครั้ง (หมายเหตุ: โค้ดตั้งไว้ 5 requests/10s แต่ข้อความบอก 3 ครั้ง อาจเป็น typo ในต้นฉบับ)

Less Remote Call ด้วย Caching

ไม่มีประสิทธิภาพถ้าทำ remote call ทุก request ฟีเจอร์ที่มีประโยชน์ของ @uptash/ratelimit package คือ cache data นานเท่าที่ edge function "hot" หมายถึง data ดึงจาก Redis เฉพาะตอน function "cold" ลด remote calls การ cache สร้างได้โดย declare ratelimit object นอก handler function middleware

Rate Limiting Algorithms

ตัวอย่างด้านบนใช้ sliding window algorithm ขึ้นอยู่กับความต้องการ ใช้ fixed window และ leaking bucket algorithms ได้ เช็ก ที่นี่

Multi Region Redis

สมเหตุสมผลที่จะมี multiple Redis databases ใน regions ต่างๆ เพื่อปรับปรุง performance จาก edge functions Config multiple region Redis ได้ตาม ที่อธิบายไว้

Links

Rate limiting with Next.js (non-edge)

Vercel Edge middleware

Ratelimiting SDK