xiangyixiangqin/server/SignalR生产环境配置.md
2026-01-14 20:23:13 +08:00

12 KiB
Raw Blame History

SignalR 生产环境配置指南

文档版本: 1.0
创建日期: 2026-01-14
适用环境: 生产环境


一、Nginx 配置

1.1 WebSocket 支持配置

SignalR 使用 WebSocket 协议,需要在 Nginx 中配置 WebSocket 支持。

配置文件: /etc/nginx/sites-available/xiangyi

# 上游服务器配置
upstream xiangyi_app_api {
    server localhost:5000;
    keepalive 32;
}

server {
    listen 80;
    listen 443 ssl http2;
    server_name app.zpc-xy.com;

    # SSL 证书配置
    ssl_certificate /etc/nginx/ssl/app.zpc-xy.com.crt;
    ssl_certificate_key /etc/nginx/ssl/app.zpc-xy.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # 普通 HTTP API 请求
    location /xyqj/api/ {
        proxy_pass http://xiangyi_app_api/api/app/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 超时配置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # SignalR WebSocket 配置(关键配置)
    location /hubs/chat {
        proxy_pass http://xiangyi_app_api/hubs/chat;
        proxy_http_version 1.1;
        
        # WebSocket 必需配置
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # 基础代理头
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 禁用缓存
        proxy_cache_bypass $http_upgrade;
        proxy_buffering off;
        
        # 超时配置WebSocket 需要长连接)
        proxy_connect_timeout 7d;
        proxy_send_timeout 7d;
        proxy_read_timeout 7d;
        
        # 心跳配置
        proxy_socket_keepalive on;
    }

    # 静态文件
    location /uploads/ {
        alias /var/www/xiangyi/uploads/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

1.2 配置说明

关键配置项:

  1. proxy_http_version 1.1

    • WebSocket 需要 HTTP/1.1 协议
  2. Upgrade 和 Connection 头

    • 必须配置,用于协议升级
  3. 超时时间

    • proxy_read_timeout 7d - 设置为 7 天,支持长连接
    • 可根据实际需求调整
  4. proxy_buffering off

    • 禁用缓冲,确保消息实时传输
  5. proxy_socket_keepalive on

    • 启用 TCP keepalive保持连接活跃

二、ASP.NET Core 配置

2.1 Program.cs 配置

// SignalR 配置
builder.Services.AddSignalR(options =>
{
    // 启用详细错误(生产环境建议关闭)
    options.EnableDetailedErrors = false;
    
    // 客户端超时时间30秒
    options.ClientTimeoutInterval = TimeSpan.FromSeconds(30);
    
    // 心跳间隔15秒
    options.KeepAliveInterval = TimeSpan.FromSeconds(15);
    
    // 最大消息大小32KB
    options.MaximumReceiveMessageSize = 32 * 1024;
    
    // 流式传输缓冲区大小
    options.StreamBufferCapacity = 10;
});

// 如果使用 Redis 作为 SignalR 后端(多服务器部署)
builder.Services.AddSignalR()
    .AddStackExchangeRedis(builder.Configuration.GetConnectionString("Redis"), options =>
    {
        options.Configuration.ChannelPrefix = "SignalR";
    });

2.2 appsettings.Production.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore.SignalR": "Warning",
      "Microsoft.AspNetCore.Http.Connections": "Warning"
    }
  },
  "ConnectionStrings": {
    "Redis": "localhost:6379,password=your_redis_password"
  },
  "SignalR": {
    "EnableDetailedErrors": false,
    "ClientTimeoutInterval": 30,
    "KeepAliveInterval": 15,
    "MaximumReceiveMessageSize": 32768
  }
}

三、Redis 配置(多服务器部署)

3.1 为什么需要 Redis

当部署多个应用服务器实例时SignalR 需要使用 Redis 作为后端存储,以实现:

  • 跨服务器消息推送
  • 连接状态共享
  • 负载均衡支持

3.2 安装 Redis NuGet 包

cd server/src/XiangYi.AppApi
dotnet add package Microsoft.AspNetCore.SignalR.StackExchangeRedis

3.3 配置 Redis

// Program.cs
builder.Services.AddSignalR()
    .AddStackExchangeRedis(options =>
    {
        options.Configuration.EndPoints.Add("localhost", 6379);
        options.Configuration.Password = "your_redis_password";
        options.Configuration.ChannelPrefix = "SignalR";
        options.Configuration.AbortOnConnectFail = false;
    });

3.4 Redis 配置文件

# /etc/redis/redis.conf

# 绑定地址
bind 127.0.0.1

# 端口
port 6379

# 密码
requirepass your_redis_password

# 最大内存
maxmemory 256mb

# 内存淘汰策略
maxmemory-policy allkeys-lru

# 持久化
save 900 1
save 300 10
save 60 10000

四、防火墙配置

4.1 开放端口

# 开放 HTTP/HTTPS 端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# 如果 Redis 需要外部访问
sudo ufw allow 6379/tcp

4.2 安全组规则(云服务器)

入站规则:

  • HTTP: 80
  • HTTPS: 443
  • Redis: 6379仅内网

五、SSL/TLS 配置

5.1 获取 SSL 证书

使用 Let's Encrypt:

sudo apt-get install certbot python3-certbot-nginx
sudo certbot --nginx -d app.zpc-xy.com

5.2 自动续期

# 添加定时任务
sudo crontab -e

# 每天凌晨 2 点检查并续期
0 2 * * * certbot renew --quiet

5.3 强制 HTTPS

server {
    listen 80;
    server_name app.zpc-xy.com;
    return 301 https://$server_name$request_uri;
}

六、监控与日志

6.1 SignalR 连接监控

创建监控端点:

// Controllers/MonitorController.cs
[ApiController]
[Route("api/monitor")]
public class MonitorController : ControllerBase
{
    [HttpGet("signalr/stats")]
    public IActionResult GetSignalRStats()
    {
        return Ok(new
        {
            OnlineUsers = ChatHub.GetOnlineUserCount(),
            Timestamp = DateTime.Now
        });
    }
}

6.2 日志配置

Serilog 配置:

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft.AspNetCore.SignalR": "Warning",
        "Microsoft.AspNetCore.Http.Connections": "Warning"
      }
    },
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "/var/log/xiangyi/signalr-.log",
          "rollingInterval": "Day",
          "retainedFileCountLimit": 30
        }
      }
    ]
  }
}

6.3 性能监控

关键指标:

  • 在线用户数
  • 消息推送成功率
  • 平均消息延迟
  • 连接建立/断开频率
  • 内存使用情况

监控工具:

  • Application Insights
  • Prometheus + Grafana
  • ELK Stack

七、性能优化

7.1 连接池配置

builder.Services.AddSignalR(options =>
{
    // 限制并发连接数
    options.MaximumParallelInvocationsPerClient = 1;
    
    // 启用消息压缩
    options.EnableDetailedErrors = false;
});

7.2 消息压缩

builder.Services.AddSignalR()
    .AddMessagePackProtocol(); // 使用 MessagePack 协议(更高效)

7.3 数据库优化

-- 为聊天表添加索引
CREATE INDEX IX_ChatMessage_SessionId_CreateTime 
ON Chat_Message(SessionId, CreateTime DESC);

CREATE INDEX IX_ChatMessage_ReceiverId_IsRead 
ON Chat_Message(ReceiverId, IsRead);

CREATE INDEX IX_ChatSession_User1Id_User2Id 
ON Chat_Session(User1Id, User2Id);

八、故障排查

8.1 连接失败

检查清单:

  1. Nginx 配置是否正确
  2. WebSocket 是否被防火墙阻止
  3. SSL 证书是否有效
  4. 后端服务是否运行

诊断命令:

# 检查 Nginx 配置
sudo nginx -t

# 查看 Nginx 日志
sudo tail -f /var/log/nginx/error.log

# 检查端口监听
sudo netstat -tlnp | grep 5000

# 测试 WebSocket 连接
wscat -c wss://app.zpc-xy.com/hubs/chat

8.2 消息丢失

可能原因:

  • Redis 连接断开
  • 消息队列满
  • 客户端未正确监听事件

解决方案:

  1. 检查 Redis 连接状态
  2. 增加消息队列大小
  3. 实现消息持久化和重试机制

8.3 性能问题

优化建议:

  1. 启用 Redis 集群
  2. 使用 MessagePack 协议
  3. 实现消息批量推送
  4. 优化数据库查询
  5. 使用 CDN 加速静态资源

九、安全配置

9.1 认证授权

// ChatHub.cs
[Authorize] // 必须登录才能连接
public class ChatHub : Hub
{
    // 验证用户权限
    public override async Task OnConnectedAsync()
    {
        var userId = GetCurrentUserId();
        if (userId <= 0)
        {
            Context.Abort();
            return;
        }
        await base.OnConnectedAsync();
    }
}

9.2 速率限制

// 限制消息发送频率
public class RateLimitAttribute : ActionFilterAttribute
{
    private static readonly ConcurrentDictionary<long, DateTime> LastMessageTime = new();
    
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var userId = GetUserId(context);
        var now = DateTime.Now;
        
        if (LastMessageTime.TryGetValue(userId, out var lastTime))
        {
            if ((now - lastTime).TotalSeconds < 1) // 1秒内只能发送1条
            {
                context.Result = new StatusCodeResult(429); // Too Many Requests
                return;
            }
        }
        
        LastMessageTime[userId] = now;
        base.OnActionExecuting(context);
    }
}

9.3 消息过滤

// 敏感词过滤
public async Task<string> FilterSensitiveWords(string content)
{
    // 实现敏感词过滤逻辑
    return content;
}

十、部署检查清单

10.1 部署前检查

  • Nginx 配置已更新
  • SSL 证书已配置
  • Redis 已安装并配置
  • 防火墙规则已配置
  • 日志目录已创建
  • 监控已配置

10.2 部署后验证

  • WebSocket 连接成功
  • 消息实时推送正常
  • 断线重连正常
  • 多设备同时在线正常
  • 性能指标正常
  • 日志记录正常

10.3 压力测试

# 使用 Artillery 进行压力测试
npm install -g artillery

# 创建测试脚本 signalr-test.yml
artillery run signalr-test.yml

测试脚本示例:

config:
  target: "wss://app.zpc-xy.com"
  phases:
    - duration: 60
      arrivalRate: 10
  engines:
    ws:
      timeout: 30000

scenarios:
  - name: "SignalR Connection Test"
    engine: ws
    flow:
      - connect:
          url: "/hubs/chat?access_token={{token}}"
      - think: 5
      - send: '{"type":1,"target":"SendMessage","arguments":["Hello"]}'
      - think: 10

十一、回滚方案

11.1 快速回滚

如果部署后出现问题,可以快速回滚:

# 回滚到上一个版本
cd /var/www/xiangyi/app-api
git checkout previous-version
dotnet publish -c Release -o /var/www/xiangyi/app-api/publish
sudo systemctl restart xiangyi-app-api

11.2 降级方案

如果 SignalR 出现问题,可以临时禁用实时推送:

// Program.cs
if (!builder.Configuration.GetValue<bool>("SignalR:Enabled"))
{
    // 不注册 SignalR
}
else
{
    builder.Services.AddSignalR();
    app.MapHub<ChatHub>("/hubs/chat");
}

十二、总结

SignalR 生产环境配置要点:

  1. Nginx 配置 - 正确配置 WebSocket 支持
  2. SSL/TLS - 使用 wss:// 协议
  3. Redis - 多服务器部署必需
  4. 监控 - 实时监控连接状态和性能
  5. 安全 - 认证、授权、速率限制
  6. 优化 - 连接池、消息压缩、数据库索引

完成以上配置后SignalR 即可在生产环境稳定运行。