如何使用Nginx实现Blazor Server负载均衡及会话持久化
Blazor Server集群Nginx负载均衡+无中断会话配置
Blazor Server默认通过WebSocket/长轮询维持Circuit(会话电路),状态默认存在单节点内存,仅配置普通负载均衡会出现会话漂移断连,只做简单会话粘滞也无法解决节点下线导致的用户被强制踢出问题,需要Nginx层和应用层配合配置,具体步骤如下:
Nginx层配置
Nginx侧采用Cookie注入方式实现会话粘滞,比IP_hash适配性更强(不会因为用户网络切换、IP变动导致粘滞失效),同时配置主动健康检查和故障重试,自动剔除异常节点。
注意:配置中用到的
sticky指令依赖sticky模块,若你的Nginx未加载该模块,可替换为一致性哈希粘滞配置hash $cookie.AspNetCore.Session consistent;,基于Blazor自带的会话Cookie做路由哈希,不需要额外模块,只是故障转移时的会话迁移效率略低于sticky cookie方案。
完整配置示例如下:
http { # 定义Blazor后端节点池,替换为实际的服务器内网地址+端口 upstream blazor_cluster { # 会话粘滞配置:Nginx给客户端种专用Cookie绑定后端节点,过期时间和应用会话超时对齐即可 sticky cookie blazor_route_id expires=8h domain=你的站点域名 path=/ HttpOnly Secure SameSite=Lax; # 节点配置:max_fails和fail_timeout用于健康检查,连续3次失败则标记节点不可用,30秒后重新探测 server 192.168.1.10:5000 weight=1 max_fails=3 fail_timeout=30s; server 192.168.1.11:5000 weight=1 max_fails=3 fail_timeout=30s; server 192.168.1.12:5000 weight=1 max_fails=3 fail_timeout=30s; # 长连接池配置,适配Blazor WebSocket长连接需求 keepalive 128; } server { listen 443 ssl http2; server_name 你的站点域名; # 此处补全你的SSL证书配置即可 # ssl_certificate /path/to/cert.pem; # ssl_certificate_key /path/to/key.pem; location / { proxy_pass http://blazor_cluster; # 基础代理头传递 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; # WebSocket支持必备配置 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # 超时配置,需大于Blazor侧配置的Circuit空闲超时时间,避免Nginx主动断开长连接 proxy_read_timeout 3600s; proxy_send_timeout 3600s; # 故障自动转移:后端节点报错、超时、不可用时,自动转发请求到其他可用节点 proxy_next_upstream error timeout http_502 http_503 http_504; proxy_next_upstream_tries 3; proxy_next_upstream_timeout 10s; } } }
应用层配套配置(节点下线无中断核心)
单靠Nginx配置无法解决节点下线后的会话接管问题,必须对Blazor应用做集群适配:
- 共享DataProtection密钥
所有集群节点必须共用同一套DataProtection密钥,否则登录Cookie、会话加密数据跨节点无法解密,会直接导致会话失效。在Program.cs中添加如下配置,将密钥存在共享Redis中:// 注册共享DataProtection,所有节点配置完全一致 builder.Services.AddDataProtection() .PersistKeysToStackExchangeRedis( ConnectionMultiplexer.Connect("你的Redis连接字符串"), "blazor-dataprotection-keys" ) .SetApplicationName("你的Blazor应用固定名称"); - 分布式存储Circuit会话状态
默认Circuit存在单节点内存,节点下线后其他节点无法读取会话状态,需要替换为共享Redis存储:- 所有集群节点安装Nuget包
Microsoft.AspNetCore.Components.Server.StackExchangeRedis - 修改Program.cs中的Blazor服务注册:
builder.Services.AddServerSideBlazor() .AddCircuitOptions(options => { // 断开的Circuit保留3分钟,给故障转移、节点切换留足够缓冲时间 options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(3); options.DetailedErrors = false; }) // 注册Redis作为Circuit持久化存储,所有节点共用同一个Redis实例 .AddStackExchangeRedisCircuitPersistence("你的Redis连接字符串"); - 所有集群节点安装Nuget包
- 规范节点下线操作
主动运维下线节点(比如发版、扩缩容)时,先在Nginx的upstream配置中给对应节点加down标记,重载Nginx配置后等待至少3分钟(和DisconnectedCircuitRetentionPeriod配置对齐),待节点上残留的活跃会话全部迁移完成后,再关闭应用进程,避免直接杀进程导致的瞬时断连。
配置校验规则
- 正常访问站点时,打开浏览器开发者工具查看Cookie列表,能看到Nginx注入的粘滞Cookie(示例配置中名为
blazor_route_id),多次刷新页面请求固定路由到同一后端节点,说明会话粘滞生效 - 手动停止某一台后端节点的Blazor进程,对应节点上的已登录用户操作无感知、不会被踢出系统,刷新页面也能正常访问,说明故障转移生效
- 切换客户端网络(比如WiFi切移动热点),会话保持登录状态、操作不中断,说明粘滞策略适配正常
内容的提问来源于stack exchange,提问作者foryura
相关产品推荐
相关产品推荐

