← Back to list

Anka: Native AOT için Minimal HTTP Sunucusu Tasarlamak, Anka’nın Mimarisi ve Bilinçli Kısıtları

Modern backend sistemlerde “hızlı” olmak artık tek başına yeterli değil; ilk isteğe ne kadar hızlı cevap verdiğiniz, ne kadar az bellekle…

Selçuk Güral · 2026-04-17 08:11 · 0 claps · 5.4 min read
#anka #kestrel #httpframework #aot
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Anka: Native AOT için Minimal HTTP Sunucusu Tasarlamak, Anka’nın Mimarisi ve Bilinçli Kısıtları

Modern backend sistemlerde “hızlı” olmak artık tek başına yeterli değil; ilk isteğe ne kadar hızlı cevap verdiğiniz, ne kadar az bellekle ayağa kalktığınız ve bunu ne kadar öngörülebilir yaptığınız da en az throughput kadar önemli. Özellikle serverless, kısa ömürlü container, edge worker ve bursty internal servis senaryolarında problem genellikle steady-state throughput değil; cold start, startup allocation ve operasyonel sadelik oluyor.

Anka bu probleme alışılmış ASP.NET Core yaklaşımının tersinden yaklaşıyor: middleware pipeline yok, built-in routing yok, TLS yok, HTTP/2 yok. Bunun yerine .NET 8+ üzerinde, Native AOT dostu, HTTP/1.x odaklı, allocation-disiplinli bir HTTP sunucu çekirdeği sunuyor. Amaç açık: süreç ayağa kalktıktan sonra soketi milisaniyeler içinde dinlemeye almak ve connection/request yaşam döngüsünü mümkün olduğunca deterministik tutmak.

Problem Tanımı

Klasik .NET web stack’i çok güçlü; ama bu gücün bir maliyeti var. Middleware zinciri, reflection-heavy yüzey alanı, dinamik extensibility, geniş protokol desteği ve JIT warmup, cold start tarafında ciddi bir vergi yaratıyor. Uygulamanızın gerçekten ihtiyacı sadece “socket aç, HTTP/1.1 parse et, handler’ı çalıştır, cevabı yaz” ise bu genel amaçlı model gereğinden pahalı hale gelebiliyor.

Anka’nın odaklandığı soru şu

Tam teşekküllü web framework’ü değil, sadece hızlı açılan, düşük bellekli, Native AOT ile uyumlu bir HTTP listener istiyorsak minimum mimari ne olmalı?

Bu soruya verilen cevap performans sayılarında da kendini gösteriyor. Ölçülen bir ortamda Anka’nın time-to-ready süresi yaklaşık 2.3 ms, startup allocation’ı 124.5 KB, steady-state RSS’i ise yaklaşık 15 MB seviyesinde. Buna karşılık Kestrel benzer senaryoda daha geniş feature set’iyle geliyor ama cold start ve bellek tarafında daha ağır bir profil çiziyor. İlginç olan nokta şu: throughput tarafında fark dramatik değil; yani Anka’nın asıl avantajı “ham req/s” değil, başlangıç maliyeti ve footprint.

Mimari: Minimum Katman, Maksimum Kontrol

Anka’nın mimarisi bilinçli şekilde dar tutuldu:

Server.StartAsync() -> paralel accept loop’lar -> Connection.RunAsync() (her TCP bağlantısı için bir task) -> SocketReceiver.ReceiveAsync() -> HttpParser -> RequestHandler(request, response, ct) -> HttpResponseWriter.WriteAsync()

Bu akışın önemli tarafı şu: sistemde “fazla soyutlama” yok. İstek işleme zinciri doğrudan socket seviyesinden başlıyor ve doğrudan socket seviyesinde bitiyor.

Server: Kabul katmanı

Server, listening socket’i açıyor, backlog’u ayarlıyor ve tek accept loop yerine birden fazla paralel accept loop çalıştırıyor. Bu karar küçük görünebilir ama burst traffic altında tek accept döngüsünün bağlantı kabulünü serialize etmesini engelliyor.

Ek olarak thread pool minimumu yukarı çekilerek ilk yüklenme anındaki thread injection gecikmesi azaltılıyor. Bu, benchmark tuning gibi görünebilir; ama aslında cold path davranışını deterministik hale getiren operasyonel bir karar.

Connection: Gerçek çalışma birimi

Her TCP bağlantısı için bir Connection task’i oluşturuluyor. Bu nesne:

  • pooled receive buffer kiralıyor,
  • pooled HttpRequest alıyor,
  • connection-scoped HttpResponseWriter yaratıyor,
  • socket’ten veri okuyup parse ediyor,
  • handler’ı çağırıyor,
  • keep-alive ise aynı kaynaklarla bir sonraki isteğe geçiyor.

Buradaki kritik fikir şu: request bazlı değil, connection bazlı kaynak sahipliği. Böylece aynı keep-alive bağlantısında tekrar eden istekler için yeniden buffer kiralama/iadeleri minimize ediliyor.

SocketReceiver: Async I/O ama allocation disipliniyle

Anka, Socket.ReceiveAsync(Memory) gibi daha rahat yüzeyler yerine SocketAsyncEventArgs + IValueTaskSource kullanıyor. Bunun sebebi mikro-optimizasyon merakı değil; senkron tamamlanan socket okumalarında state machine ve ek allocation’lardan kaçınmak.

Özellikle loopback/LAN senaryolarında veri çoğu zaman kernel buffer’da zaten hazır oluyor. Bu durumda receive çağrısı senkron tamamlanıyor ve sistem neredeyse düz fonksiyon çağrısı maliyetinde ilerliyor. Veri hazır değilse OS I/O completion thread işi tamamlıyor; continuation ise RunContinuationsAsynchronously = true ile thread pool’a post ediliyor. Sonuç: I/O thread’i request işleme yükü altında bloke olmuyor.

HttpParser: Tek geçişte parse

Parser’ın asıl değeri “HTTP parse ediyor olması” değil; bunu tek geçişte ve pooled buffer mantığıyla yapması.

  • request line parse ediliyor,
  • path/query ayrıştırılıyor,
  • header isimleri ingest sırasında lowercase normalize ediliyor,
  • Content-Length inline takip ediliyor,
  • gerekiyorsa body okunuyor,
  • chunked request body varsa decode edilip req.Body içine reassemble ediliyor,
  • keep-alive kararı parse aşamasında hesaplanıyor.

Bu yaklaşım iki önemli kazanım getiriyor:

  1. İkinci bir header taraması gerekmiyor.
  2. Handler’a geçen HttpRequest, zaten kullanıma hazır ve mümkün olduğunca kopyasız bir model oluyor.
  3. HttpResponseWriter: framework değil, doğrudan wire format

Response katmanı da aynı felsefeyi izliyor. HttpResponseWriter, HTTP response header block’unu pooled buffer üzerinde kuruyor, küçük body’leri mümkünse aynı buffer içine inline ediyor ve doğrudan Socket.SendAsync() ile yazıyor.

Burada da önemli bir karar var: chunked response encoding yok. Tüm response’lar Content-Length ile gidiyor. Bu kısıt, response pipeline’ını sadeleştiriyor; özellikle AOT ve düşük allocation hedefi için kod yolunu daraltıyor.

Temel Tasarım Kararları

Tek RequestHandler delegesi

Anka’da middleware zinciri yok. Tek bir RequestHandler var. Bu bilinçli bir radikallik.

Kazancı

  • çağrı zinciri kısalıyor,
  • soyutlama katmanları azalıyor,
  • handler dispatch maliyeti düşüyor,
  • Native AOT için daha sade bir yüzey oluşuyor.

Bedeli

  • çapraz kesen concern’leri sizin kurmanız gerekiyor,
  • routing, auth, logging, metrics gibi konular framework tarafından organize edilmiyor.

Bu karar “eksik framework” değil; çekirdek primitive sağlama yaklaşımı.

Built-in routing yok

Path dispatch kullanıcı koduna bırakılıyor. Basit bir switch çoğu senaryo için yeterli kabul ediliyor. Bu ilk bakışta ilkel gelebilir; ama routing’nin gerçek maliyeti sadece path eşleştirme değildir. Yanında metadata sistemi, endpoint graph’i, convention set’i ve geniş bir API yüzeyi gelir. Anka bu maliyeti baştan reddediyor.

Header isimlerini ingest sırasında lowercase’e çekmek

Case-insensitive header lookup’ı her sorguda yapmak yerine, isimler parse sırasında normalize ediliyor. Böylece lookup tarafında düz SequenceEqual yeterli oluyor. Bu küçük bir tasarım tercihi gibi görünür ama hot path’te branch ve iş yükünü azaltır.

HttpRequest ve buffer’ları connection boyunca tekrar kullanmak

HttpRequest.ResetForReuse() yaklaşımı, request nesnesini her istekten sonra çöpe atmıyor. Aynı bağlantıda yeniden kullanıyor. Bu model özellikle keep-alive altında etkili; çünkü steady-state allocation’ı düşüren şey çoğu zaman büyük optimizasyonlar değil, küçük ama sistematik yeniden kullanım kararlarıdır.

CAS tabanlı küçük request pool

HttpRequestPool lock-free ve küçük tutulmuş. Amaç teorik “sınırsız pooling” değil; düşük overhead’li, cache-friendly ve pratik bir reuse mekanizması. Tüm slotlar doluysa nesne discard ediliyor. Bu da önemli bir mühendislik kararı: bazen her şeyi pool’lamaya çalışmak, hiç pool’lamamaktan daha pahalıdır.

Trade-off’lar: Bu Mimari Neyi Kazandırıyor, Neyi Bilerek Vermiyor?

Anka’nın iyi yanı, ne olmadığını açıkça söylemesi.

En kritik trade-off şu: Anka, Kestrel’in yerini almak için değil, farklı bir optimizasyon noktasını sahiplenmek için var. Eğer ihtiyacınız HTTP/2, TLS termination, middleware ekosistemi, gelişmiş hosting entegrasyonu, observability plug-in yüzeyi ise cevap zaten büyük ihtimalle Kestrel. Ama ihtiyacınız düşük footprint, hızlı readiness ve son derece kontrollü bir request path ise Anka mantıklı hale geliyor.

Bu Tasarımın En Güçlü Tarafı: Performans Değil, Öngörülebilirlik

Burada bence asıl değer yalnızca “0 B allocation” ya da “2.3 ms ready” değil. Asıl değer, sistemin davranışını zihinde kolayca modelleyebilmek:

  • her bağlantı için bir task,
  • connection-scoped buffer’lar,
  • parse → handle → write hattı,
  • az sayıda hata durumu,
  • sınırlı protocol yüzeyi.

Mimari seviyede baktığımızda bu tür sistemlerin değeri benchmark sunumundan çok operasyonel açıklık tarafında ortaya çıkar. Sistem ne yapıyor, ne yapmıyor, yük altında nerede davranış değiştiriyor, hangi noktalarda maliyet ödüyor bunlar nettir.

Örnek Kullanım Senaryoları

Serverless veya kısa ömürlü container API’leri

Cold start kritikse ve endpoint set’i küçükse, Anka’nın minimal açılış maliyeti ciddi avantaj sağlar.

Sidecar / internal control-plane endpoint’leri

Health, readiness, metrics gateway veya basit control API’leri için tam framework çoğu zaman gereksizdir.

Edge compute ve appliance tarzı dağıtımlar

Düşük RSS ve Native AOT uyumu, sınırlı kaynaklı ortamlarda önemli fark yaratır.

Benchmarking ve protokol araştırması

HTTP pipeline davranışını framework gürültüsü olmadan gözlemek isteyen ekipler için iyi bir araştırma yüzeyi sunar.

Çok dar kapsamlı yüksek kontrol gerektiren servisler

Tek amaçlı webhook receiver, internal callback endpoint’i veya lightweight ingestion servisleri için uygundur.

Ne Zaman Kullanmazdım?

Ben bu mimariyi şu durumlarda seçmezdim:

  • geniş ekiplerin üzerinde geliştirdiği genel amaçlı product API’si,
  • zengin middleware ekosistemi gereken uygulamalar,
  • streaming/TLS/HTTP/2’nin birinci sınıf ihtiyaç olduğu sistemler,
  • framework entegrasyonlarının geliştirici verimliliğinden daha değerli olduğu organizasyonlar.

Çünkü burada kazandığınız şey “özgürlük” değil; kontrol. Kontrol ise her zaman daha fazla mühendislik sorumluluğu demektir.

Sonuç

Anka’nın teknik olarak en doğru özeti şu olur: özellik çıkararak performans kazanan değil, kapsamı daraltarak davranışı sadeleştiren bir HTTP sunucu çekirdeği. Native AOT, düşük startup allocation, connection-scoped kaynak yönetimi, tek geçişli parser ve doğrudan socket yazımı aynı hedefe hizmet ediyor: küçük, hızlı açılan, anlaşılır bir request path.

Bu yaklaşım herkese uygun değil. Zaten olmaya da çalışmıyor. Ama deneyimli backend mühendisliği perspektifinden bakınca, bence en olgun tarafı tam olarak bu: problemi dar tanımlıyor, çözümü o problem için optimize ediyor ve bunun dışındaki alanları bilinçli şekilde dışarıda bırakıyor. Bu da çoğu zaman “her şeyi yapan” sistemlerden daha değerli bir mühendislik kararıdır.

Farkındayım Anka için herhangi bir kod örneği paylaşmadım. Projenin teknik detaylarına GitHub sayfasından ulaşabilirsiniz.


메타데이터
post_id
6f3bbdd23f8f
slug
anka-native-aot-için-minimal-http-sunucusu-tasarlamak-ankanın-mimarisi-ve-bilinçli-kısıtları-6f3bbdd23f8f
url
https://medium.com/@selcukgural/anka-native-aot-i%C3%A7in-minimal-http-sunucusu-tasarlamak-ankan%C4%B1n-mimarisi-ve-bilin%C3%A7li-k%C4%B1s%C4%B1tlar%C4%B1-6f3bbdd23f8f
canonical_url
https://medium.com/@selcukgural/anka-native-aot-i%C3%A7in-minimal-http-sunucusu-tasarlamak-ankan%C4%B1n-mimarisi-ve-bilin%C3%A7li-k%C4%B1s%C4%B1tlar%C4%B1-6f3bbdd23f8f
author_url
https://medium.com/@selcukgural
status
ok
fetched_at
2026-06-10 08:34:46