Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Redis Backplane İle SignalR’ı Ölçeklendirme


Merhaba,

Malumunuz, .NET ekosisteminde gerçek zamanlı (realtime) uygulamalar geliştirirken ilk akla gelen ve en çok tercih edilen çözüm SignalR‘dır. Uygulama küçükten orta seviyeye doğru seyrettikçe, SignalR tek bir sunucuda (single instance) oldukça konforlu, sorunsuz ve başarılı bir şekilde bizlere eşlik etmektedir. Ancak bu konfor, uygulamanın büyümesiyle ve horizontal scaling ihtiyaçlarının ortaya çıkmasıyla hızla kaybolmakta ve yerini ciddi mimari karmaşıklıklara ve zorluklara bırakmaktadır. Düşünün ki; SignalR uygulamasını birden fazla sunucuyla ölçeklendirdiğimiz vakit, bu sunucular arasında client’ların aynı Hub üzerinden haberleşmesi doğal olarak engellenmiş olacaktır. Ya da bir başka deyişle bu client’lar, aynı Hub üzerinden iletişim kuramaz hale gelecektir. Neden mi? Şundan ki; SignalR, varsayılan olarak in-memory bir mesajlaşma altyapısı kullanmaktadır… Ee haliyle ölçeklendirmenin yapıldığı bu mimaride bir kullanıcı X sunucusuna, diğeri ise Y sunucusuna bağlandığında iki sunucunun birbirinden haberi olmayacağı için aralarında gerçek zamanlı bir iletişim modelinin kurulması şu şartlarda pekte mümkün olmayacaktır. İşte tam da bu noktada farklı SignalR sunucuları arasında mesaj trafiğini koordine eden bir distributed mesajlaşma altyapısı sunan Backplane kavramı devreye girecektir. Eğer ki vaziyet SignalR uygulamasını production’da ölçeklendirmeyi gerektiriyorsa, evet, bu kavram ile çözüm rahatlıkla sunulabilmektedir. Bizler bu içeriğimizde, SignalR’ı ölçeklendirmenin en popüler ve başarılı yollarından biri olan Redis Backplane’i detaylıca ele alacak ve bir yandan da Redis’in yüksek performanslı yapısını nasıl SignalR ile entegre edebileceğimizi, kurulumundan konfigürasyonuna, performans ipuçlarından olası tuzaklara kadar tüm kritik noktaları inceliyor olacağız… Hazırsanız başlayalım…

Problem Nedir?

Diyelim ki 3 adet uygulama sunucumuz olsun…Redis Backplane İle SignalR'ı ÖlçeklendirmeVe sırasıyla ‘A’, ‘B’ ve ‘C’ client’ları bu sunuculara bağlanmış olsun.Redis Backplane İle SignalR'ı ÖlçeklendirmeŞimdi böyle bir vaziyette sunucu 1’e bağlı olan ‘A’ client’ı SignalR üzerinden aşağıdaki gibi bir mesaj gönderirse eğer;Redis Backplane İle SignalR'ı Ölçeklendirmesunucu 1 yalnızca kendi belleğindeki bağlantıları bileceği için bu mesaj diğer sunuculara bağlı olan client’lara iletilmeyecek, yani sadece ‘A’ client’ına iletilecektir.

İşte böyle, SignalR’ın ölçeklendirilmesi gereken durumlarda bir handikap söz konusu olmaktadır. Her ne kadar await Clients.All.SendAsync(...) metoduna bakıldığında ilgili mesajın her client’a gönderileceği sanılıyor olsa da gerçekte olan davranış ise SignalR’ın bildiği herkese göndereceğidir! Bunun nedeni yukarıdaki satırlarda ifade etmeye çalıştığımız gibi SignalR’ın bulunduğu sunucunun in-memory’si üzerinden mesajlaşma altyapısı kullanmasıdır.

SignalR, sunucu belleğinde oluşturduğu bir tablo üzerinde client’ları tutmakta ve await Clients.All.SendAsync(...) gibi bir talimat geldiği taktirde bu iletişime bu tablodaki client’ları muhattap kılmaktadır. Haliyle bu problem, SignalR’dan ziyade distributed sistemlerin realtime çalışmalarda yaşadığı temel bir problemdir. Bizler, mimariye performans kaygılarıyla ikinci bir sunucuyu ya da instance’ı eklediğimiz anda mevzu bahis handikap durumu meydana gelmekte ve artık her bir SignalR bulunduğu sunucu üzerinde diğer(ler)inden izole bir hale gelmektedir. Dolayısıyla bu izolasyon sebebiyle, bir sunucuya bağlı olan istemciler diğer sunuculardaki istemcilerle haberleşememektedirler.

Peki Bu Durum Neden Tehlikelidir?

Bu durumun, farklı sunuculardaki client’lar arasında mesajlaşmayı imkansız hale getirdiğinin zaten farkındayız. Bunun dışında esas bahsedilmesi gereken daha kritik bir tehlike söz konusu olabilir. O da sistemin bazen çalışıyor gibi görünmesidir… Diyelim ki, ‘A’ ile ‘B’ client’ları aynı sunucuda olsun. Bu iki client arasındaki haberleşme sürecinde herhangi bir problem meydana gelmeyeceği için kimsenin gerçek riske dair bir farkındalığı olmayacak ve durum anlaşılmayacaktır. Ancak bir zaman sonra bu iki client farklı sunuculara gittiği taktirde client’lar realtime’da haberleşemeyecek ve kullanıcılar gözünde mesajlar kaybolacaktır. Hatta kimi kullanıcılar, durumu gir çık vs. gibi küçük testlerde tekrar edecek ve bazen diğer client ile aynı sunucuya denk gelecekleri için mesajların ara ara iletildiğini düşünecektirler. Vee böylece günün sonunda son kullanıcı açısından en bahtsız kanaate varılacak ve “bazen çalışıyor, bazen çalışmıyor” şeklinde uygulamanın adı bir daha 8’e inmemek üzere 9’a çıkacaktır.

Düşünsenize, 2 sunucuyla ölçeklendirmenin yapıldığı senaryolarda 50%, 4 sunucuyla 75%, 10 ve fazlası sunucuyla yapılanlarda ise 90% client’ların farklı sunucularda olma ihtimali söz konusudur. Yani SignalR’ın kullanıldığı projelerde, scaling ile performans kazanmak isterken doğruluğu kaybetmek oldukça yüksek ihtimaldir.

Peki Çözüm Ne Olabilir?

Belki ilk etapta sticky sessions akla geliyor olabilir ve evet, belki bir nebze işe yarayabilir. Ama sunuculardan biri çöktüğü taktirde client farklı bir sunucuya bağlanacak ve bu seferde iletişimde olduğu diğer client’larla yine haberleşmesi kesilecek ve aynı problem meydana gelecektir.

Ayrıca, sticky session’da sunucular arasında X sunucusunda 5000 kullanıcı, Y sunucusunda 200 kullanıcı gibi tutarsız yığınlaşmalar söz konusu olabilir. Haliyle ölçeklendirme gibi performans niyetiyle tercih edilen bir yaklaşımdan kaynaklı, ortaya çıkan problemlere daha farklı ve tuhaf problemlerle çözüm getirmek külliyen yanlış bir yaklaşım olacaktır.

Ee peki çözümü nasıl getireceğiz hoca la? diye sorarsanız öncelikle şudur budur demekten ziyade nasıl bir yaklaşım sergilememiz gerektiğini konuşmalıyız. Yani bir teknolojiden yahut teknikten ziyade, farkında olunması gereken asıl şey distributed mantıkta düşünme biçimimizi geliştirmektir. Bu düşünme biçiminde ideal safhaya gelirsek zaten aklın yolu bir olan yöntem ya da yaklaşım her neyse o anki probleme çözüm olarak kendiliğinden tezahür etmiş olacaktır. Çünkü, bu gün SignalR’ı konuşuyor olabiliriz ancak yarın; cache, session, authentication, AI Agent vs. gibi durumlarda da benzer problemler mevzu bahis olacak ve yine karşımıza çıkacaktır.

Şimdi düşünmemiz gereken mantığa gelirsek; distributed sistemlerde ne kadar sunucu ya da container söz konusuysa olayı o kadar gerçeklik olarak yorumlayabiliriz. Tek sunucuda, tek bir gerçeklik vardır. Dolayısıyla tüm sistemin aklı tek bir bellekten işlenmektedir. Ancak, distributed sisteme geçildiğinde artık birden fazla gerçeklik söz konusu olacaktır. Dolayısıyla burada hiçbir sunucunun tüm gerçeği bilemeyeceğinin farkında olmamız gerekmektedir. Haliyle bu farkındalık üzerinden şöyle bir mantığa doğru evrilmemiz gerekmektedir. Bilgiyi üretildiği yerde değil, paylaşılması gereken yerde tutmalıyız. Yani ortak bir evrende… Bir başka deyişle mutlak bir gerçeklikte…

Bir diğer farkındalığımız ise bir sunucunun ölmesi sonucunda sistemin gerçeğini yok etmeyecek şekilde bir yaklaşım sergilenmesi gerekliliğidir. Eğer ki, sunucunun ölmesi neticesinde tüm bilgiler kayboluyorsa bilgi yanlış yere koyulmuş demektir.

Dolayısıyla bu mantıktan çıkaracağımız çözüm yolu, gerçeklik boyutunu geçici olan sunucu seviyesinden kalıcı hale getirebilmekten geçmektedir. Evet, gerçeklik boyutu sunucudan bağımsız bir şekilde daha evrensel hale getirilirse tüm sunucular ve instance’lar aralarında durumları değil, artık olayları paylaşır hale gelecektir. İşte bu durum da distributed sistemler için oldukça ideal bir zemindir. Zaten yazılım mimarilerinde adı konulmamış bir ilke vardır 🙂 Muhtemelen ilk benden duymuş olacaksınız: Sunuculara Güvenmeme İlkesi🤣Belki de adını artık koymuş olduğumuz bu ilke, başta garip gelse de özellikle büyük ve ticari hassasiyete sahip yazılımlarda oldukça kritik arz etmektedir. Bundan kaynaklı modern yazılım mimarilerinde sunucuların ölmesi beklenen bir durum olduğu için tüm tasarımlar (genellikle) baştan Kubernetes gibi altyapılara göre şekillenmektedir. Ki bu, SignalR gibi realtime durumları ilgilendiren hassasiyet olan yazılımlar için daha da baştan düşünülmesi gereken bir mimaridir.

Bir uygulama tek bir sunucudan distributed sisteme dönüşüyorsa eğer, artık sunucu(ların) belleğine güvenilemez…

Velhasıl, anlayacağınız veri akış sürecinde gerçekliği tek bir makinenin belleğinden ziyade, merkezi bir hale getirerek yürütebilirsek işte o taktirde içerik boyunca konuştuğumuz probleme ideal bir çözüm sağlanmış olacaktır.

Peki bunu neyle yapacağız?
Merkezi bir gerçeklik deyince tabi ki de akla direkt message broker yapılanmalarının bizlere sunduğu imkanlar gelebilmektedir. Evet… Doğrudur, haklı olabilirsiniz. Anlattığım mantığı ince işçiliğiyle uygulamamızı sağlayacak teknik altyapıyı bu yapılanmalar bizlere sunmaktadır. RabbitMQ, Kafka, SQL Server Backplane, Service Bus mimarisi, NATS vs. gibi teknolojiler ve yaklaşımlarla bu probleme çözüm getirebiliriz. Yani anlayacağınız, yazımızın başlığında özellikle vurguladığımız Redis Backplane aslında bu problemin tek çözümü değildir. Ama, en yaygın ve en pratik çözümlerden biridir diyebiliriz. İşte bu yüzden bu içeriğimizde Redis Backplane ile bu probleme ideal çözümün nasıl getirilebileceğini pratik olarak hep birlikte tecrübe edeceğiz.

Microsoft, özellikle cloud ortamları için Redis yerine Azure SignalR Service‘in kullanılmasını önermektedir.

Redis Backplane Nedir?

Redis Backplane, birden fazla uygulama sunucusunun birbirine haber gönderebilmesi için kullanılan bir mesajlaşma köprüsüdür. Yukarıdaki satırlarda message broker olarak tanıttım belki ama backplane bir message broker’dan ziyade bir mimarisel pattern’dır ve bir sunucuda oluşan olayları diğer sunuculara ileten katman görevi görmektedir. Message broker ise bu işlemi yapan teknolojilerin ta kendisidir… Haliyle burada Redis, backplane görevi gören message broker’ımızdır… Umarım anlaşılmıştır 😉

Redis Backplane İle SignalR'ı ÖlçeklendirmeVelhasıl, davranışı oldukça basittir. Normalde, SignalR bağlamında düşünürsek eğer bir client’tan gönderilen mesaj sunucu üzerindeki tüm client’lara eriştirilecektir. Ancak diğer sunuculara eriştirilemeyecektir. Redis Backplane’de ise sunucular önce Redis’e mesajlarını iletecek, Redis ise kendisine bağlı olan tüm sunuculara bu mesajları iletmiş olacaktır. Böylece esasında olay önce Redis’e yayınlanmış olacak, Redis’te bu mesajı tüm uygulama sunucularına iletecek ve sunucularda kendilerine bağlı client’lara mesajları gönderecektir…

Bu mimaride, ne client Redis’i bilecektir, ne de sunucular Redis’in detaylarıyla ilgilenecektir. Sunucular arasındaki koordinasyon süreç aksamaksızın oldukça hızlı bir şekilde gerçeklecektir.

Redis bu davranışı Pub/Sub özelliğini kullanarak gerçekleştirmektedir.

Artıları & Eksileri Nelerdir?

✓ Avantajlar
  • Hızlı değil, çok hızlıdır… Çünkü Redis verileri RAM üzerinde tuttuğu için oldukça yüksek performans sunmaktadır.
  • Kod tarafında neredeyse hiçbir değişiklik yapılmaya gerek kalmaksızın kurulumu oldukça kolaydır. Çünkü, sunucuların birbirlerini bulma kaygısı, yeni bir sunucu geldiğinde sisteme nasıl işleneceği, mesajların hangi sırasıyla gideceği ve hata durumlarında ne olacağı gibi mühendislik problemleri Redis tarafından üstlenilmiş ve çoktan halledilmiştir.
  • Aynı durum SignalR için de geçerlidir… Malum, iyi mimarilerde iş kuralları altyapıdan bağımsız olmalıdır. Yani kod yalnızca mesaj gönder talimatını vermeli, şu sunucuya gönder, şuna bildir tarzı gibi altyapı sorunlarıyla ilgilenmemeli. Redis, bu tarz ayrıntıları da süreçten soyutlayarak bizlere kolaylık sağlamaktadır.

⚠ Dikkat Edilmesi Gerekenler
  • Büyük ölçeklerde darboğaz söz konusu olabilir. Özellikle 100bin 500bin gibi connection’ın söz konusu olduğu durumlarda Redis tek başına baskı altında kalabilir. Çünkü tüm mesajlaşmalar Redis üzerinden geçecektir. Bu taktirde artık sorun, SignalR + realtime yapılanmasının distributed koşullarda ortaya çıkan problemi değil, Redis’in kaldırabileceği yük olacaktır. Haliyle bu seviyede artık Redis Cluster yapısı planlanarak daha ileri çözümlerle süreç desteklenmelidir.
  • Redis Pub/Sub mesajı iletir ve siler. Haliyle bir mesaj kalıcılığı durumu söz konusu değildir. Bu durum çözmeye çalıştığımız problemin davranışsal yapısı açısından da normaldir de! Çünkü, SignalR gerçek zamanlı iletişim için tasarlanmıştır. Haliyle bir mesaj gönderilirken sunucu kapalıysa ister istemez o sunucudan connection olan tüm client’lar o mesajı kaçıracaktır. Eğer ki, mesajların kaybolmaması isteniyorsa burada en doğru çözüm olarak RabbitMQ yahut Kafka gibi daha gelişmiş ve ince ayarlanabilir message broker’lara yönelinmelidir.

Peki client’lar arası haberleşmede user odaklı bir mesajlaşma durumu varsa nasıl davranış sergilemektedir?

Redis Backplane İle SignalR'ı Ölçeklendirme

SignalR Backplane’de kullanıcı odaklı mesajlaşma durumunun zihinsel modeli…

await Clients.User("userId").SendAsync(...) şeklindeki kullanıcı odaklı mesaj gönderim süreçlerinde ise işler biraz daha ilginç hale gelmektedir. Distributed mimaride hedef kullanıcının hangi sunucuya bağlı olduğu bilinmediğinden, ilk akla gelen çözüm bu bilginin merkezi bir yerde yani Redis’te sorgulanması olabilir. Ancak SignalR Redis Backplane mimarisinde temel yaklaşım bu değildir! Bunun yerine SignalR, ilgili kullanıcıya gönderilmek istenen mesajları Redis üzerinden tüm SignalR sunucularına duyuracak, mesajı alan her sunucu, hedef kullanıcının kendine bağlı client’ları arasında bulunup bulunmadığını yerel olarak kontrol edecektir. Hedef kullanıcıya sahip olan sunucu mesajı iletirken, diğer sunucular mesajı görmezden gelecektir. Böylece merkezi bir bağlantı sorgulama mekanizması yerine, olayın tüm sunuculara yayınlanması ve yerel doğrulama yaklaşımı tercih edilmiş olacaktır.

Esasında bu modelin altında yatan distributed sistem prensibi fark ettiyseniz şudur;

Verinin nerede olduğunu merkezi olarak sorgulamak yerine, olayı herkese duyur ve ilgili tarafın kendini tanımasını sağla…

Nasıl Kurulur & Kullanılır?

Redis ile SignalR’ı ölçeklendirebilmek için tek yapılması gereken ilgili projeye Microsoft.AspNetCore.SignalR.StackExchangeRedis kütüphanesinin yüklenmesi ve ardından aşağıdaki gibi SignalR servisi üzerinden AddStackExchangeRedis servisinin çağrılmasıdır:

builder.Services.AddSignalR()
    .AddStackExchangeRedis(builder.Configuration.GetConnectionString("redisCache")!);

Evet, uygulama kodu açısından yapılması gereken çalışma büyük ölçüde bundan ibarettir 🙂 Hele hele Hub tarafında hiçbir şeyin değiştirilmesine gerek duyulmaması da cabasıdır… Tabi kod tarafında olay bu yapılandırmayla bitiyor olsa da mimari seviyesinde sorumluluklarımız devam etmektedir. Redis Backplane’in çalışabilmesi için Redis sunucusunun ayakta olması gerekmekte ve tüm uygulama instance’larının aynı Redis sunucusuna bağlanması gerekmektedir. Ağ erişimleri, firewall izinleri vs. gibi uğraşların yanında Redis bağlantısının kopması süreçlerinde nasıl davranışların benimseneceği ekstradan düşünülüp, hesap edilmelidir.

Ayrıca, Redis Backplane ekleyince uygulamanın tamamı otomatik olarak distributed sisteme dönüşmeyecektir. Yani, Redis Backplane sadece SignalR’ın distributed çalışmasını sağlayacak, uygulamanın geri kalanında distributed sistem problemlerini çözmeyecektir. Şöyle ki; örnek vermemiz gerekirse eğer uygulama belleğinde public static List OnlineUsers = []; ile tüm kullanıcıları tutuyorsanız sadece ilgili sunucuda bu geçerli olacak, tüm sunucuları kümülatif olarak ilgilendirmeyecektir. Yani hala bu tarz durumalar da sunucular ayrı dünyalar olacağı için meydana gelebilecek problemleri Redis çözmeyecektir.

Buradan anlaşılması gereken şudur ki; distributed bir sistemde bir state (durum/veri) tutuluyorsa eğer onun da ortak yerde olması elzemdir. Ancak bu tarz dokunuşlarla distributed sistem tam oturaklı olacaktır. “Redis Backplane ekledim, artık tüm uygulamam distributed sisteme uygun oldu…” demek hiçte doğru bir kabul olmayacaktır!


Bir Redis sunucusunun birden fazla SignalR uygulaması tarafından kullanılması durumu…

Burada küçükte olsa bir yapılandırma durumunu kritize etmek istiyorum. Eğer ki, aynı Redis sunucusunu birden fazla SignalR uygulaması kullanıyorsa mesajların birbirine karışmaması için bir kanal öneki (channel prefix) tanımlanması gerekmektedir.

Bunu daha net anlayabilmeniz için hafiften problemi görselleştirmeye çalışalım: Diyelim ki aynı Redis sunucusunu kullanan iki uygulamanız var;

E-Ticaret Uygulaması
└─ SignalR

CRM Uygulaması
└─ SignalR

Redis

Burada her iki uygulamada .AddStackExchangeRedis("localhost:6379") ile bağlanacaktır. Uygulamanın çalışması sürecinde SignalR, node’lar arasında mesaj taşımak için Redis üzerinde SignalR.SomeChannel, SignalR.GroupUpdates, SignalR.Broadcast vs. gibi pub/sub channel’ları oluşturacaktır. Eğer ki her iki uygulamada aynı kanallar kullanılıyorsa, birinde SignalR’da paylaşılan mesaj diğerine de yansıtılacaktır. Bu istenmeyen bir durumdur.

Burada çözüm olarak aşağıdaki gibi ChannelPrefix yapılandırmasıyla SignalR uygulamasının kullanacağı tüm Redis channel’larının başına bu prefix eklenecektir:

builder.Services.AddSignalR()
    .AddStackExchangeRedis(builder.Configuration.GetConnectionString("redisCache")!, configure =>
    {
        configure.Configuration.ChannelPrefix = RedisChannel.Literal("MyApp");
    });

Böylece tek bir Redis sunucusunda olunsa dahi uygulama seviyesinde mesaj akışları birbirlerinden ayrılmış olacaktır.

Sticky Sessions Hala Gerekli!

Yukarıdaki satırlarda sticky sessions’a dair ilk etapta gelen fikre karşı durmuş olsak da, hala sticky sessions’a ihtiyacımız olduğunu itiraf etmeliyiz! Evet, Redis Backplane distributed bir altyapıda mesaj yönlendirme sorununu çözüyor çözmesine ancak, sticky session’lara olan ihtiyacı ortadan kaldırmıyor. Neden mi? Şundan dolayı… Bir client’ın SignalR’a bağlantısı temelde müzakere aşamasına dayanmaktadır. Bu aşamada;

  • 1. Adımda
    Client, connection token’ı alabilmek için /hub/negotiate endpoint’ine bir POST isteği gönderir.
  • 2. Adımda
    Client, elde ettiği connection token aracılığıyla WebSocket bağlantısını sağlar.

Bu süreçte her iki isteğin de aynı sunucuda olduğunun garantisinin sağlanması gerekmektedir. Load balancer, müzakere isteğini server 1’e yönlendirirken, WebSocket bağlantı isteği server 2’ye yönlendirilirse bekleneceği üzere bağlantı başarısız olacaktır.

Bundan kaynaklı load balancer’da sticky sessions yapılandırmasının etkinleştirilmesine özen gösterilmelidir.

Peki Redis Çöktüğünde Ne Olacak?

Bu yaklaşımda Redis çökerse eğer, kesinti sırasında gönderilen tüm mesajlar kaybolacaktır. Belki Redis’ten kaynaklı SignalR uygulaması exception fırlatabilir ancak WebSocket bağlantıları bundan etkilenmeyecek ve client’ların bağlantısı devam edecektir. Haliyle Redis es kaza bu süreçte tekrar çalışmaya başlarsa eğer SignalR otomatik olarak yeniden bağlanacak ve uygulamalar arası haberleşme akışı hiç problem yokmuşcasına devam ediyor olacaktır.

Sipariş güncellemeleri yahut canlı gösterge panoları gibi çoğu kullanıcı eylemleri açısından pasif olan realtime senaryolar için bu durum pek sorun teşkil etmeyecektir. Ancak finansal veriler gibi kritik değerlerin söz konusu olduğu akışlarda yahut kullanıcı eylemlerinin mevzu bahis olduğu süreçlerde Redis’in çöküp yeniden ayağa kalkması neticesinde client ile server arasında tekrar bir mutabakat sürecine ihtiyaç olacak ve senkron çalışan kalıcı (durable) bir kuyruğa (queue) gereksinim duyulacaktır.

Nihai olarak;

Anlıyoruz ki, distributed bir dünyada gerçek zamanlılığı korumak, sunuculara güvenmekten değil, onların arasındaki koordinasyonu doğru kurmaktan geçmektedir. Redis Backplane de tam olarak bu noktada, SignalR’ın ölçeklenebilirliği ile performansı arasındaki köprüyü sağlam bir şekilde inşa etmemize olanak tanımaktadır.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Örnek çalışmaya aşağıdaki GitHub reposundan erişebilirsiniz.
https://github.com/gncyyldz/SignalRScalingWithRedis

Bu repository, ilgili konuya dair örnek çalışmanın kaynak kodlarını ve mimari yapısını içermektedir. Detaylar için GitHub üzerinden incelemede bulunabilirsiniz.


GitHub’da Görüntüle →

Bunlar da hoşunuza gidebilir...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir