c# StackExchange.Redis 的连接管理和并发策略
技术百科
星降
发布时间:2026-01-24
浏览: 次 ConnectionMultiplexer 必须全局单例复用,严禁每次新建或Scoped注入;IDatabase可随时获取无需缓存;异步操作必须await,禁用.Result/.Wait();读多写少时可用CommandFlags.DemandSlave分流至从节点。
ConnectionMultiplexer 是单例,不是每次 new
StackExchange.Redis 的核心是 ConnectionMultiplexer,它本身线程安全、内置连接池和自动重连,**必须全局复用一个实例**。多次 new ConnectionMultiplexer 会导致 socket 耗尽、TIME_WAIT 暴涨、CPU 升高,甚至 Redis 服务端拒绝新连接。
常见错误是把 ConnectionMultiplexer 塞进 using 或注入为 Scoped 服务——这等于每请求建一次连接,完全违背设计初衷。
- ASP.NET Core 中应注册为
Singleton:用services.AddSingleton(sp => ConnectionMultiplexer.Connect(configuration)) - 连接字符串里加
abortConnect=false,避免启动失败直接崩掉进程;加connectTimeout=5000和syncTimeout=5000防止阻塞过久 - 监听
ConnectionFailed和InternalError事件,但别在里面做重连逻辑(multiplexer 自己会重试),适合打日志或触发告警
Database 实例可随意获取,无需缓存
IDatabase 是轻量级句柄,不持有连接,每次调用 connecti 都是 O(1) 开销。没必要把它存成字段或缓存起来——反而容易在多库(如 db0/db1)场景下搞混上下文。
注意:如果用了 defaultDatabase 参数(比如 GetDatabase(1)),它只影响后续命令的默认 db 编号,不会改变底层 multiplexer 行为。
- 并发读写时,多个线程共用同一个
IDatabase实例完全安全 - 若需事务(
ITransaction)或管道(IBatch),才需要显式创建新上下文,且必须在同一线程内完成提交 - 避免在异步方法中把
IDatabase当闭包变量长期持有——没坏处,但无意义
异步 API 必须用 async/await,别用 .Result 或 .Wait()
StackExchange.Redis 的所有 *Async 方法(如 StringGetAsync、HashSetAsync)底层基于 ValueTask,**同步等待(.Result / .Wait())极易引发死锁**,尤其在 ASP.NET Core 同步上下文受限环境里。
典型现象:接口偶尔卡住、线程池饥饿、请求堆积。这不是 Redis 慢,是线程被自己锁死了。
- Controller 或 Service 方法标记
async Task,调用链全程await - 不要用
Task.Run(() => db.StringGetAsync(...)).Result—— 这只是把死锁换个地方发生 - 极少数无法改 async 的旧代码(如某些 Filter),可用
db.StringGet(key)同步版本,但它会阻塞线程,仅限低频、超短耗时场景
高并发*意 CommandFlags 和连接负载均衡
默认情况下,所有命令都走主节点(即使你配了哨兵或集群)。遇到读多写少场景,可以利用 CommandFlags 把只读命令发到从节点,减轻主节点压力:
await db.StringGetAsync("key", CommandFlags.DemandSlave);
但这有前提:Redis 配置了 slave-read-only yes,且 multiplexer 连接字符串里启用了 allowAdmin=true(仅开发/测试环境建议开启,生产慎用)。
- 集群模式(Cluster)下,
DemandSlave不生效,路由由 key hash 决定,无法手动指定节点 - 连接数瓶颈时,优先检查是否误用了
SyncTimeout过小(导致频繁超时重试)或AbortOnConnectFail=false未设(启动失败静默) - 用
IServer.ClientList()在 Redis CLI 查当前连接数,确认是否真由客户端连接爆炸引起,而非服务端配置限制
ConnectionMultiplexer 的健康状态感知和故障转移延迟——它不会主动通知你“这个节点已永久失联”,得靠你结合 IsConnected、GetStatus() 和业务超时做兜底。
# ai
# 都是
# 多个
# 里加
# 复用
# redis
# 路由
# 并发
# 堆
# c#
# 字符串
# 接口
# .net
# 线程
# 异步
# 死锁
# 事件
# red
# 重试
# 闭包
# 负载均衡
# Filter
# database
# using
# 服务端
# 分布式
# 连接数
# 多写
# 超短
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- 如何在Golang中处理URL参数_Golang
- Win11怎么查看硬盘型号_Windows 11检
- MySQL 中使用 IF 和 CASE 实现查询字
- c++中的可变参数模板(variadic temp
- 如何在Golang中处理数据库事务错误_回滚和日志
- GML (Geography Markup Lan
- Win11怎么开启专注模式_Windows11时钟
- Win11麦克风没声音怎么设置_Win11麦克风权
- Win10怎么更改用户名 Win10修改账户名称操
- Win11系统更新后黑屏怎么办 Win11更新黑屏
- c++如何连接Redis c++ hiredis库
- Mac如何创建和管理多个桌面空间_Mac高效多任务
- 如何使用Golang匿名函数_快速定义临时函数逻辑
- Python对象生命周期管理_创建销毁解析【教程】
- Win11怎么更改默认打开方式_Win11关联文件
- Win11怎么设置系统还原_Windows11系统
- PHP 中如何在函数内持久化修改引用变量的指向
- Win11怎么关闭自动更新 Win11永久关闭系统
- c++ namespace命名空间用法_c++避免
- php订单日志怎么导出excel_php导出订单日
- 如何使用Golang实现容器安全扫描_Golang
- php下载安装后memory_limit怎么设置_
- c++ unordered_map怎么用 c++哈
- 如何使用Golang实现路由参数绑定_使用Mux和
- Linux怎么设置磁盘配额_Linux系统Quot
- 如何在 Go 中正确反序列化多个同级 XML 元素
- php错误怎么开启_display_errors与
- c++中的CRTP是什么 c++奇异递归模板模式【
- Win11怎么关闭开机声音_Win11系统启动提示
- 如何在Golang中捕获HTTP服务器错误_Gol
- Windows10蓝屏代码DPC_WATCHDOG
- 短链接怎么用php还原_从基础原理到代码实现教学【
- windows 10专注助手怎么关闭_window
- Windows系统时间服务错误_W32Time服务
- 短链接还原php提示内存不足_调整PHP内存限制设
- 如何在Golang中使用replace替换模块_指
- 如何诊断并终止卡死的 multiprocessin
- Win10怎样卸载DockerDesktop_Wi
- 如何在 Django 中安全修改用户密码而不使会话
- Win11无法安装软件怎么办_Win11解除应用安
- Python 中将 ISO 8601 时间戳转换为
- Win11怎么关闭搜索历史_Win11清除任务栏搜
- Win11如何设置ipv6 Win11开启IPv6
- 如何用正则与预处理结合精准拦截拼接式垃圾域名
- 如何关闭Win10自动更新更新_Win10系统自动
- Linux怎么实现内网穿透_Linux安装Frp客
- Windows 11怎么更改锁屏超时时间_Wind
- Win11怎么关闭粘滞键_彻底禁用Windows
- Drupal 中 HTML 链接被重复转义导致渲染
- 小程序里php怎么变mp4_小程序调用php生成m

QQ客服