12 KiB
12 KiB
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 配置说明
关键配置项:
-
proxy_http_version 1.1
- WebSocket 需要 HTTP/1.1 协议
-
Upgrade 和 Connection 头
- 必须配置,用于协议升级
-
超时时间
proxy_read_timeout 7d- 设置为 7 天,支持长连接- 可根据实际需求调整
-
proxy_buffering off
- 禁用缓冲,确保消息实时传输
-
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 连接失败
检查清单:
- Nginx 配置是否正确
- WebSocket 是否被防火墙阻止
- SSL 证书是否有效
- 后端服务是否运行
诊断命令:
# 检查 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 连接断开
- 消息队列满
- 客户端未正确监听事件
解决方案:
- 检查 Redis 连接状态
- 增加消息队列大小
- 实现消息持久化和重试机制
8.3 性能问题
优化建议:
- 启用 Redis 集群
- 使用 MessagePack 协议
- 实现消息批量推送
- 优化数据库查询
- 使用 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 生产环境配置要点:
- Nginx 配置 - 正确配置 WebSocket 支持
- SSL/TLS - 使用 wss:// 协议
- Redis - 多服务器部署必需
- 监控 - 实时监控连接状态和性能
- 安全 - 认证、授权、速率限制
- 优化 - 连接池、消息压缩、数据库索引
完成以上配置后,SignalR 即可在生产环境稳定运行。