9.4.16.1 توضیحات #
الگوی Rate Limiting یا “محدودسازی نرخ درخواست” یکی از الگوهای پرکاربرد برای کنترل ترافیک ورودی یا پردازش عملیات در سیستمهای نرمافزاری است. هدف اصلی این الگو، جلوگیری از اجرای بیش از حد عملیات در یک بازهی زمانی مشخص است تا از بارگذاری بیش از حد سیستم، نقض محدودیتهای منابع خارجی (مثل APIها)، یا سوءاستفاده از سرویس جلوگیری شود. این الگو در سرویسهایی که به منابع محدود یا خارجی متصلاند—مثل وبسرویسها، میکروسرویسها، API گیتویها یا سیستمهای صف پردازش—بهشدت حیاتی است.
در زبان Go، یکی از سادهترین روشهای پیادهسازی این الگو استفاده از time.Ticker
است. این نوعی تایمر است که در فواصل زمانی منظم سیگنالی را از طریق کانال ارسال میکند. با قرار دادن منطق پردازش درون حلقهای که روی این کانال میچرخد، میتوان کاری کرد که اجرای هر عملیات فقط هنگام دریافت سیگنال مجاز باشد. مثلاً اگر یک ticker
هر ۲۰۰ میلیثانیه سیگنال بفرستد، در نتیجه فقط ۵ بار در ثانیه عملیات اجرا خواهد شد. به این ترتیب نرخ اجرا به شکل دقیق و منظم کنترل میشود.
مزیت این روش در سادگی و کارآمدی آن است، بهخصوص برای سناریوهای سبک تا متوسط. اما در شرایط پیچیدهتر، ممکن است نیاز به الگوهای پیشرفتهتری مانند Token Bucket یا Leaky Bucket باشد که انعطافپذیری بیشتری برای burstهای ناگهانی، اولویتبندی یا بازتوزیع ظرفیت فراهم میکنند. همچنین در سیستمهای توزیعشده، برای اعمال محدودیت به صورت مرکزی یا سراسری (distributed rate limiting)، باید از ابزارهایی مثل Redis، Nginx، یا سرویسهای ابری (مثل Cloudflare یا AWS API Gateway) استفاده کرد.
در نهایت، الگوی Rate Limiting به عنوان یک تکنیک دفاعی و پایدارسازی سیستم، باید بخشی جدانشدنی از معماری سیستمهای تولیدی باشد—چه در قالب محدودسازی ساده در سطح goroutineها، و چه بهصورت سیاستهای سازمانیافته در کل سیستم.
9.4.16.2 دیاگرام #
9.4.16.3 نمونه کد #
1package main
2
3import (
4 "fmt"
5 "time"
6)
7
8func processRequest(id int) {
9 fmt.Printf("✅ Processed request %d at %s\n", id, time.Now().Format("15:04:05"))
10}
11
12func main() {
13 const maxRequests = 10
14 const rateLimit = time.Second // یک درخواست در هر ثانیه
15
16 ticker := time.NewTicker(rateLimit)
17 defer ticker.Stop()
18
19 requests := make(chan int)
20
21 // Producer: ارسال درخواستها با فاصله زمانی (مثلاً هر 300ms)
22 go func() {
23 for i := 1; i <= maxRequests; i++ {
24 requests <- i
25 time.Sleep(300 * time.Millisecond) // simulate incoming traffic
26 }
27 close(requests)
28 }()
29
30 // Consumer با Rate Limiting
31 for req := range requests {
32 <-ticker.C // اجازه پردازش فقط هر یک ثانیه یکبار
33 processRequest(req)
34 }
35}
1$ go run main.go
2✅ Processed request 1 at 23:00:01
3✅ Processed request 2 at 23:00:02
4✅ Processed request 3 at 23:00:03
5✅ Processed request 4 at 23:00:04
6✅ Processed request 5 at 23:00:05
7✅ Processed request 6 at 23:00:06
8✅ Processed request 7 at 23:00:07
9✅ Processed request 8 at 23:00:08
10✅ Processed request 9 at 23:00:09
11✅ Processed request 10 at 23:00:10
در این مثال، پیادهسازی سادهای از الگوی Rate Limiting در زبان Go با استفاده از time.Ticker
نمایش داده شده است. هدف این کد آن است که اجازه دهد درخواستها (در اینجا اعداد ۱ تا ۱۰) تنها با نرخ یک درخواست در هر ثانیه پردازش شوند. این کار برای جلوگیری از فشار زیاد بر روی سیستم یا رعایت محدودیتهای خارجی بسیار رایج است.
ابتدا یک ticker
با بازهی زمانی یک ثانیه ساخته میشود. این ticker
در هر ثانیه یک سیگنال روی کانال C
خودش ارسال میکند. در همین حال، یک goroutine به عنوان تولیدکننده (Producer) تعریف شده که اعداد ۱ تا ۱۰ را بدون تأخیر وارد یک کانال requests
میکند و سپس آن را میبندد. این کانال مانند یک صف عمل میکند.
در بخش مصرفکننده (Consumer)، که در main
اجرا میشود، یک حلقه از روی requests
میچرخد. قبل از پردازش هر درخواست، برنامه منتظر سیگنال از ticker.C
میماند. به این معنی که هر درخواست دقیقاً با فاصلهی زمانی یک ثانیه پردازش میشود. این مکانیزم باعث میشود اگر درخواستها خیلی سریع وارد صف شوند، باز هم فقط با سرعت مجاز (در این مثال ۱ بر ثانیه) اجرا شوند.
در نهایت، تابع processRequest
تنها مسئول چاپ شمارهی درخواست همراه با زمان اجرای آن است. این پیادهسازی اگرچه ساده است، اما پایهای بسیار مناسب برای توسعهی نسخههای پیشرفتهتر مانند کنترل burst، توقف سریع با context، یا پیادهسازی توزیعشده فراهم میکند.
9.4.16.4 کاربردها #
- Throttling API Calls: در زمانی که شما نیاز دارید درخواستهای API را محدود کنید تا از محدودیتهای تعیینشده توسط ارائهدهنده API تجاوز نکنید.
- کنترل بار سیستم: برای جلوگیری از استفاده بیش از حد از منابع سیستم، مانند پردازنده یا پایگاه داده.
- پردازش دادههای ورودی: زمانی که دادههای ورودی بسیار سریعتر از ظرفیت پردازش وارد میشوند، این الگو میتواند سرعت پردازش را مدیریت کند.
- زمانبندی رویدادها: برای انجام عملیات در فواصل زمانی معین مانند ارسال ایمیلهای گروهی.