System Design

Ölçeklenebilir Sistem Tasarımı İçin Hız Sınırlamayı Uzmanlık Seviyesine Getirmek

Dağıtık sistemlerin modern manzarasında, altyapınızı kötüye kullanımdan korurken yasal istemciler arasında adil kullanım sağlamak hayati önem taşır. Hız sınırlama, sadece bir güvenlik özelliği değil; kullanılabilirlik ve kararlılık için kritik bir bileşendir. Bu yazı, performans düşüşüne neden olmadan milyonlarca isteği işleyebilen sağlam hız sınırlama sistemleri oluşturmak için gerekli olan mimari kalıpları, algoritmaları ve uygulama stratejilerini incelemektedir.

Throttling İçin Temel Algoritmalar

Bir çözüm uygulamadan önce, isteklerin nasıl sayıldığını ve kısıtlandığını yöneten temel algoritmaları anlamak kritik öneme sahiptir. Her algoritma; karmaşıklık, doğruluk ve kullanıcı deneyimi açısından farklı ödünleşimler sunar. En yaygın yaklaşım Sabit Pencere Sayacıdır. Zamanı sabit aralıklara (örneğin bir dakika) böler ve bu pencere içindeki istekleri sayar. Uygulaması basit olsa da, "sınır problemi"nden muzdariptir; bu sorun, bir pencere sıfırlamasından hemen önce ve sonra gelen trafik patlamasının etkili veri aktarım hızını iki katına çıkarabilmesidir. Bunu ele almak için Kaydırmalı Pencere Günlüğü algoritması, her isteğin zaman damgasını kaydeder. Ardından, günlüğü filtreleyerek son N saniye içindeki istek sayısını hesaplar. Bu yöntem daha doğrudur ancak ölçeklendirme sırasında eski girdileri filtrelemek ve temizlemek için daha fazla bellek ve işlem gücü gerektirir. Yüksek performanslı sistemler için Token Havuzu veya Sızan Havuz algoritmaları tercih edilir. Token Havuzu, maksimum sayıda token saklayarak trafik patlamalarına izin verir. Her istek bir token tüketir ve tokenlar sabit bir hızla yenilenir. Bu yöntem, ortalama bir hız sınırlamasını korurken trafik dalgalanmalarını yumuşatır; bu da ara sıra patlamaların kabul edilebildiği API'ler için idealdir.

Dağıtık Uygulama Stratejileri

Monolitik bir uygulamada, bellek içi sayaçlar yeterlidir. Ancak dağıtık bir mikro hizmet mimarisinde, hız sınırlamaları birden fazla hizmet örneği arasında koordine etmek için merkezi ve tutarlı bir durum deposuna ihtiyacınız vardır. Redis, hızı ve atomik işlemleri nedeniyle bu amaç için endüstri standardıdır. Aşağıda, atomikliği sağlamak için Redis ve Lua betikleri kullanılarak bir Token Havuzu algoritmasının uygulanmasına yönelik pratik bir örnek bulunmaktadır. Atomiklik burada, birden fazla isteğin aynı anda aynı bakiyeyi görebileceği yarış durumlarını önlemek için kritiktir.
-- Token Havuzu için Redis Lua Betiği
local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local refill_rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local requested = tonumber(ARGV[4])

local function get_bucket()
    local data = redis.call('HMGET', key, 'tokens', 'last_refill')
    local tokens = tonumber(data[1])
    local last_refill = tonumber(data[2])
    
    if tokens == nil then
        return capacity, now
    end
    
    local elapsed = math.max(0, now - last_refill)
    local new_tokens = math.min(capacity, tokens + (elapsed * refill_rate))
    return new_tokens, now
end

local tokens, last_refill = get_bucket()

if tokens >= requested then
    tokens = tokens - requested
    redis.call('HMSET', key, 'tokens', tokens, 'last_refill', last_refill)
    redis.call('EXPIRE', key, 60)
    return 1
else
    return 0
end
Bu betik, mevcut token sayısını kontrol eder, geçen süreye dayalı olarak yenileme miktarını hesaplar ve istenen miktarı düşer. Yeterli token mevcutsa 1 (izin verildi) döndürür; aksi takdirde 0 (reddedildi) döndürür. Bu yaklaşım, mantığı Redis örneği içinde sunucu tarafında çalıştırarak ağ gecikmesini en aza indirir.

Kenar Durumları ve Kullanıcı Deneyiminin Yönetimi

Hız sınırlama uygulamak savaşın sadece yarısıdır; sınırlamaları istemcilere iletmek de aynı derecede önemlidir. Bir istek reddedildiğinde sunucu, 429 Çok Fazla İstek durum kodunu döndürmelidir. Kritik olarak, istemcinin ne kadar beklemesi gerektiğini bildirmek için `Retry-After` gibi başlıklar ve şeffaflık sağlamak için `X-RateLimit-Limit`, `X-RateLimit-Remaining` ve `X-RateLimit-Reset` başlıklarını eklemelisiniz. Ayrıca, sınırlamalarınızın granülerliğini (inceliğini) düşünün. Sınırlamayı IP adresine, API anahtarına mı yoksa kullanıcı kimliğine mi dayandırmalısınız? Birden fazla kullanıcının NAT ağ geçidini paylaşması durumunda IP'ye dayalı sınırlama, yanlış pozitiflere karşı hassastır. API anahtarına veya kullanıcı kimliğine dayalı sınırlama daha doğru olsa da sağlam kimlik doğrulama sistemleri gerektirir. Genellikle en iyi yaklaşım hibrit bir yaklaşımdır: anonim trafik için (IP tabanlı) sıkı sınırlamalar ve kimliği doğrulanmış kullanıcılar için daha yüksek, daha cömert sınırlamalar.

Sonuç

Hız sınırlama, kaynak tahsisini, güvenliği ve kullanıcı deneyimini dengeleyen sistem tasarımının temel bir yönüdür. Trafik desenleriniz için doğru algoritmayı seçerek ve dağıtık tutarlılık için Redis gibi araçlardan yararlanarak, arka uç altyapınızı koruyan dayanıklı API'ler oluşturabilirsiniz. En iyi hız sınırlayıcının, şeffaf, yapılandırılabilir ve uygulamanız büyüdükçe kullanımı izleyebilen ve politikaları dinamik olarak ayarlayabilmenizi sağlayan daha geniş gözlemlenebilirlik yığınınıza sorunsuz bir şekilde entegre edilmiş olan olduğunu unutmayın.
Share: