RRedis Handbook

UZMAN

SignalR Redis Backplane

Multi-instance SignalR uygulamalarını Redis Pub/Sub ile scale-out.

Kod örneği görünümü Bu sayfadaki eşleşen örnekleri seçilen istemciye göre gösterir.
# SignalR otomatik channel'lar oluşturur:
PUBSUB CHANNELS "SignalR:*"
# SignalR:MyHub:All
# SignalR:MyHub:Group:admins
# SignalR:MyHub:User:user123
# SignalR:MyHub:Connection:conn-id
// NuGet: dotnet add package Microsoft.AspNetCore.SignalR.StackExchangeRedis

builder.Services.AddSignalR()
    .AddStackExchangeRedis(builder.Configuration.GetConnectionString("Redis")!, options =>
    {
        options.Configuration.ChannelPrefix = RedisChannel.Literal("SignalR");
    });

// Hub (değişiklik yok — Redis backplane şeffaf çalışır)
public class NotificationHub : Hub
{
    public async Task SendToUser(string userId, string message)
    {
        await Clients.User(userId).SendAsync("ReceiveNotification", message);
    }

    public async Task SendToGroup(string group, string message)
    {
        await Clients.Group(group).SendAsync("ReceiveMessage", message);
    }

    public override async Task OnConnectedAsync()
    {
        var userId = Context.UserIdentifier;
        if (userId is not null)
            await Groups.AddToGroupAsync(Context.ConnectionId, $"user:{userId}");

        await base.OnConnectedAsync();
    }
}

// Controller'dan hub'a mesaj gönderme (herhangi bir instance'dan)
[ApiController]
[Route("api/[controller]")]
public class NotificationsController : ControllerBase
{
    private readonly IHubContext<NotificationHub> _hubContext;

    public NotificationsController(IHubContext<NotificationHub> hubContext)
        => _hubContext = hubContext;

    [HttpPost("broadcast")]
    public async Task<IActionResult> Broadcast([FromBody] string message)
    {
        // Bu mesaj Redis üzerinden TÜM instance'lardaki client'lara ulaşır
        await _hubContext.Clients.All.SendAsync("ReceiveNotification", message);
        return Ok();
    }

    [HttpPost("user/{userId}")]
    public async Task<IActionResult> SendToUser(string userId, [FromBody] string message)
    {
        await _hubContext.Clients.User(userId).SendAsync("ReceiveNotification", message);
        return Ok();
    }
}
# docker-compose.yml — 3 instance SignalR + Redis + nginx
services:
  redis:
    image: redis:8-alpine
    ports: ["6379:6379"]

  api-1:
    build: .
    environment:
      - ConnectionStrings__Redis=redis:6379
      - ASPNETCORE_URLS=http://+:5000

  api-2:
    build: .
    environment:
      - ConnectionStrings__Redis=redis:6379
      - ASPNETCORE_URLS=http://+:5000

  api-3:
    build: .
    environment:
      - ConnectionStrings__Redis=redis:6379
      - ASPNETCORE_URLS=http://+:5000

  nginx:
    image: nginx:alpine
    ports: ["80:80"]
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf

Redis backplane şeffaf çalışır. Hub kodunda hiçbir değişiklik yok. Tek instance'dan multi-instance'a geçiş = sadece AddStackExchangeRedis ekle. Client hangi instance'a bağlı olursa olsun mesaj ulaşır.

SignalR yoğun kullanımda Redis Pub/Sub message volume yüksek olabilir. Çok fazla group/user varsa → Redis Streams bazlı custom çözüm düşün.