.Net 7.0’da Rate Limiting Nedir ?

Selamlar,

Bu makalede, .Net 7.0 ile hayatımıza giren Rate Limiting Middleware yapısı ile, yazdığımız bir Api’ye, belirli bir süre içinde yapılabilecek istek sayısını nasıl sınırlayabileceğimizi ya da bir başka deyiş ile, Api’nin aldığı trafik miktarını, nasıl kontrol edebileceğimizi hep beraber tartışacağız. Tabi ki esas amacımız, performans ve sitenin her zaman yanıt verebilmesini sağlamak.

Tam Olarak Bu Rate Limiting Nedir ?

Çalıştırılan her uygulama, çalıştığı makina üzerinden belli bir kaynak tüketir. Bu kaynaklar CPU, Memory ve Disk I/O olarak, karşımıza çıkar. Son kullanıclardan biri, kötü amaçlı bu kaynakları zorlamak isteyebilir. DDoS Attack dediğimiz, sn’ler içinde küçük botlar ile binlerce request çekilebilir. Hatta bu requestler, farklı IPli makinalardan yapılabilir. Bu durumda istekler, veri tabanımız zorlayıp hatta DB’nin cevap verememesine neden olabilir. Bunun yerine, herbir client’ın kaynakları eşit şekilde kullanmasını sağlayabilir ayrıca DB’nin sadece örneğin 1000 isteğe izin verecek bir şekilde bir sınırlandırma getirmesini sağlayabiliriz. Ya da genel bir sınırlandırma yerine kullanıcı başı 100 istek şeklinde de, client bazlı durumu özele indirgeme yapabiliriz. Ayrıca aynı işlemi, request için de client bazlı 100 ya da 1000 istek gibi kısıtlıyabiliriz. Böylece belki bazı durumlarda hızda bir yavaşlama olsa da, sistemin her zaman cevap veren stabil yapısını korumuş oluruz.

.Net Core WebApi Projemize indirmemiz gereken kütüphane yukarıdaki gibidir.

Rate Limiting Tipleri:

1-) Fixed Window Limit: Aynı bir sinema salonunda olduğu gibi bir filime başlandığı zaman 2 saat boyunca 100 kişiye izin veriyorsunuz. Bir sonraki seans’ın ne zaman başlıyacağı belli. Belirlenen limit sayısına kadar, örneğin 100’e kadar insanların sıraya girmesini izin veriyorsunuz. 100’den sonraki gelen kişiye başka bir zaman gelmesini söylüyorsunuz. 2 saatin sonunda sıradaki 100 kişi içeri alınıp, tekrar bir 100 kişilik kontejyan açıyorsunuz. İşte buna Fixed Window Limit diyoruz.

2-) Sliding Window Limit: Sliding Window Limit, aslında birçok alanda kullanılan bir algoritmadır. Gelin biraz daha detaylıca inceleyelim. Fixed Window’a çok benzer. Burada tek fark, segmentlerin eklenmesidir. Örneğin 2 saatlik filmi 4 tane 30 dakikalık segment’e ayıralım. Her 30 dakikayı, özerk bir 1 segment sayacağız. Her 30 dakikayıda 10 dakikalık segmentlere ayıracağız. Her 10 dakikada bir segment, pencereyi sağ kaydıracağız. Kısaca pencereyi 10 dakika ara ile öteleyeceğiz. Ve hangi 30 dakikalık segment içindeyiz ona bakacağız. Pencerenin geçtiği sırada bir istek var ise, bunuda yeni segment limitine ekliyeceğiz. Yoksa yeni segment’i ilk belirlenen limitde bırakacağız. Şekiller ile konuyu daha iyi anlatmaya çalışalım.

  • 1. 30 dakikalık segment =>  [10],[20],[30] = İlk 30 dakikayı da, 10 dakikalık segmentlere bölelim. Toplam Limitimiz 100 olsun. İlk 3, 10 dakikalık segment’de, diyelim ki ilk 2 index’de hiçbir istek gelmedi ve 0 request oldu. Şu anda 3. index’de ve halen 30 dakikamız olan ilk segment sınrıları içinde olalım.

  • 3. Indexde ilk 10 dakikalık sürede 50 request alalım. Ve bir sonraki 10 dakikaya geçip Slide’ı bir kaydıralım. Artık hem 1. 30 dakikalık segment hem de 2. 30 dakikalık segment sınırları içerisindeyiz. Aşağıda görüldüğü gibi 50 request isteği 3. Indexden gelmiş ve ilk 30 dakikalık segment’den halen tam dışarı çıkmadığımız için 50 request 2. 30 dakikalık segment’e akatarılmış ve kalan limit 100 – 50 = 50 olmuştur.

  • Sonraki 10 dakikada, diyelim ki bir 20 request daha aldık. Ve 5. index’e geldik. Halen 2.Segment’deyiz ve ilk 30 dakikalık 1.Segment’den daha tam çıkamadık. Doğal olarak 50 + 20 yani 70 request doldu. Boşta 30 request kaldı.

  • 10 dakika sonra pencereyi tekrar sağ kaydırıyoruz. Ve 6. Index’e geliyoruz. Artık ilk segment olan ilk 30 dakikadan kurtuluyoruz. İlk 3 index ilk Segment’e ait idi. Artık sadece 2.Segment’in içindeki 30 dakikadayız. Ve önceki segmentden kalan 50 Request’i siliyoruz. 2. 30 dakikalık Segment’den kalan 20 Request halen duruyor. Boşta Request 80 (100 – 20).

Bu şeklide süreç akıp gidiyor. Amaç 2 saat uzun bir süre farklı zamanlarda gelecek istekleri küçük zaman dilimleri içinde cevaplamaya çalışmak. Ve sürekli bellekten, segment segment yer açmak.

3-) Token bucket limit: Akış hızını kontrol etmenizi sağlar. Bu Token Kovası olarak bilinen bir algoritmadır. Jetonla ağzına kadar dolu bir kovamızın olduğunu, hayal edelim. Bir istek gelince, bir jeton alır ve onu saklarız. Tanımlanan süre sonunda, belirlenmiş miktar kadar jetonu tekrar kovaya koyarız. Asla kovanın tutabileceğinden fazlasını eklemeyiz. Kova boş ise istek geldiğinde bunu reddederiz. Örnek olarak, kovaya 10 jeton koyalım ve her dakika, 2 jeton kovaya eklendiğini varsayalım. Diyelim 1 istek gelisin, geriye 9 (10 -1)Jeton kalsın. Sonra 3 istek daha gelsin geriye 6 (9 – 3) Jeton kalsın. Diyelim 1 dakika geçti ve kovaya 2 Jeton daha geldi. Kovamızda 8 (6 + 2) jeton oldu. Bir anda 8 istek geldi ve kovada hiç jeton (0) (8 -8) kalmadı. Yeni bir istek geldiğinde, kaynağa erişime izin verilmedi. Diyelim ki 5 dakika boyunca hiçbir istek gelmedi ve böylece kovamızda 10 (2*5) jeton birikti. İstek almamaya devam etesek bile, her 1 dakikada bir 2 yeni jeton artık kovaya konmayacak çünkü kovanın limitine gelinmiş olacaktır.

4-) Concurrency limit: En basit sınırlama yoludur. Eş zamanlı kaç isteğin, kaynağa erişebileceğini belirler. Limit 10 ise, aynı anda en fazla 10 istek kaynağa erişebilir. 11. isteğe izin verilmez. 1 istek tamamlandığında, izin verilen istek sayısı 1’e çıkar. 2 istek daha biter ise, izin verilen istek sayısı 3’e çıkar.

Örnek Asp .Net Core Rate Limiting :

Kimliği doğrulanmış kullanıcı adı  veya kimliği doğrulanmamış ise ana bilgisayar başı adına, global dakikada 5 istekle sınırlayan bir RateLimit yazalım.

  • “builder.Services.AddRateLimiter(options =>” : builder’a “AddRateLimiter()” methodu ile sınırlayıcı eklenir.
  • “options.GlobalLimiter”: Middleware’de başka biryerde tanımlama yapmaya gerek kalmadan global bir limitleme tanımlanmıştır.
  • “PartitionedRateLimiter”: Yukarıda anlatılan Rate Limitlerden “GetFixedWindowLimiter()” örnek olarak kullanılmıştır.
  • “PermitLimit = 5”: 5 request’e izin verilmiştir.
  • “Window = TimeSpan.FromMinutes(1)”: 1 Dakika için geçerli bir limitlemedir. Yani 1 dakika içinde 5 request’e izin verilir. Her 1 dakikada bir, yeni bir 5 request’e izin verilir.
  • “app.UseRateLimiter()”: Tüm Actionlar için geçerli Limiter, aktif hale getirilir.

Program.cs(1):

Program.cs(2) Queue Limit: Aşağıdaki örnekde, “QueueLimit” = 2 olarak atanmıştır. Ve “QueueProcessingOrder” sıraya alınış şekli, eskiden yeniye doğrudur. Yani örneğin ilk 1 dakika içinde 5 requestden sonraki 2 kişi red cevabı almıyacak bir sonraki 1 dakikaya kadar, sırada bekletilecektir. 1 dakika dolduktan sonra, request’e cevap dönülecektir.

Program.cs(3) Custom Red Cevabı Dönme: Aşağıdaki örnekde, limit aşıldıktan sonra dönülecek olan, custom response 429 hata kodu ile “options.OnRejected =” Event’i tanımlanmıştır.

Aşağıdaki Queue örneğinde, 3. Request’den sonraki ilgili kişiye “429” hatasını dönmek yerine, nasıl sıraya sokulup 10sn beklettikten sonra request’e cevap dönüldüğü görülmektedir

Program.cs(4) Rate  limit için Policy Yazmak: Aşağıdaki örnekde, Web ve Api adında 2 policy yazılmıştır. Örnek amaçlı Global Rate Limiter yerine, bir endpoint’e “Api“, ve diğer endpoint’e “Web” Rate Limiterları atanabilir.

WeatherController.cs/GetCurrentTime: Aşağıdaki örnekde, “[EnableRateLimiting(“Web”)]” Web ortamı için, bir limitleme getirilmiş ve 1 dakika içinde 2 Request’e izin verilmiştir.

WeatherController/GetWeatherForecast(): Aşağıdaki örnekte, “[EnableRateLimiting(“Api”)]” komutu ile Api ortamı için, bir limitleme getirilmiştir. 1 dakika içinde 5 Request’e izin verilmiştir. 6. kişi Custom tanımlanan “429” hatasını alacaktır.

Aşağıdaki örnekde GetWeatherForecast() method için “Api” ve TestRateLimitWeb() için “Web” policyleri uygulanmıştır. Sonuçlar, video’nun devamında görülmektedir.

Program.cs(5): Aşağıdaki örnekde, Controller tepesinde “Api” policy’si tanımlanmıştır. Bu durumda tüm Actionlara aynı Policy uygulanır. Ama GetWeatherForecast() methoduna “[DisableRateLimiting]” attribute’ü atanarak ilgili “Api” policy’sinin uygulanmaması sağlanmıştır.

Bu makalede, bir sunucuya yapılabilecek DDoS ataklarına, bot saldırılarına ya da gerçekten yoğunluktan dolayı sistemin çökmesine neden olabilecek durumlara çeşitli tiplerde sınırlamalar getirdik. Böylece, sunucu kaynaklarını clientlar arasında adil bir şekilde dağıtmış olduk. Normalde sunucuların önünde bulunun Routerlar, Firewallar ya da Cloudflare gibi bulut çözümleri, sunuculara yapılabilecek bu atakları önlemektedir. Biz .Net ile kendi custom kurallarımızı tanımlayıp ara bir katmanda müdahale etme şansı bulduk.

Geldik bir makalenin daha sonuna. Yeni bir makalede görüşmek üzere hepinize hoşçakalın.

Kaynaklar:

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

8 Cevaplar

  1. Fahrettin dedi ki:

    bora bey “dakka” değil dakika yazsanız olmaz mı?

  2. Barış Can YILMAZ dedi ki:

    Bora Bey Merhaba,

    Yine mükemmelsiniz. “Yazılım şekliniz. Hitap edişiniz. Konuyu açıklayışınız. ” Makale okurken keyif alıyorum.

    Bugüne kadar bize kattığınız her türlü bilgi için şükranlarımı sunuyorum.

  3. --- dedi ki:

    Client ların ip adresi sabit değil herbir ip adresinden gelen istek 10 dakikada maksimum 100 istek atabilir. Bu kural ile birlikte bütün clientlar maksimum 10 dakikada 1000 istek atabilir. Bu şekilde bir rate limit yapmak istediğimde sizce en uygun nasıl yapabilirim. Teşekkürler

  4. --- dedi ki:

    Biraz düşününce şu şekilde aklıma geldi ne kadar doğru olur suan emin değilim. Yazmışken bunuda yaziyim. “bütün clientlar maksimum 10 dakikada 1000 istek atabilir.” kuralını video da gösterilen metodlardan birisini uygulayarak yapabiliriz. “Client ların ip adresi sabit değil herbir ip adresinden gelen istek 10 dakikada maksimum 100 istek atabilir.” bunun içinde ekstra bir tane middleware yazacağız. Bu middleware de httpcontext ile requesttin ip adresini bulup redis e ekleyeceğiz ve attığı istek sayısı sınırı aşmadıysa 1 artıracağız ve next diyip devam edecek. Sorun varsa diğer işlemlere girmeden direk response döneriz. Hangfire ile da bir tane backgroundservice yazarız. Buda her 10 dakikada redisi temizler. Bu işin best practice nedir bilmiyorum ama acaba bu şekilde nasıl olur ?

  5. Emre Gulistan dedi ki:

    load balancer kullanılan projelerde rate limit davranışı nasıl olur hocam? permit limit’in 50 olduğunu farz edelim load balancer tarafından oluşturulmuş 3 kopyaya 3×50 limit ayırması yerine toplamına 50 limit ayırmasını nasıl sağlarız?

  6. Faydalı Paylaşım İçin Teşekkürler

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.