FreeSql 连接池深度剖析:断熔机制与读写分离切换背后的设计思想

FreeSql 连接池深度剖析:断熔机制与读写分离切换背后的设计思想 FreeSql 连接池深度剖析断熔机制与读写分离切换背后的设计思想【免费下载链接】FreeSql功能强大的对象关系映射O/RM组件支持 .NET Core 2.1、.NET Framework 4.0、Xamarin 以及 AOT。项目地址: https://gitcode.com/dotnetcore/FreeSqlFreeSql 连接池比 ADO.NET 原生连接池多做三件事数据库宕机时自动断熔止血、后台探测自动恢复、读写分离下从库故障自动切换。本文通过源码剖析 FreeSql 连接池断熔机制与读写分离切换背后的设计思想帮你理解这个 .NET ORM 最容易被忽视的能力。 连接池是 ORM 的心脏它决定了并发上限、故障时会不会雪崩、读写分离时敢不敢高枕无忧。连接池之心FreeSql 为什么要自研池ADO.NET 自带连接池为什么 FreeSql 还要在上一层再造一个答案写在 FreeSqlBuilder.cs 的源码注释里。使用UseConnectionString时FreeSql 连接池默认具备三个特点断熔机制数据库状态不可用时切断访问由后台线程检测直到恢复读写分离从库不可用时自动切换其他可用从库池监控通过fsql.Ado.Statistics实时监测连接池使用情况对比一下原生池的行为如果你的应用直连原生池数据库宕机 30 秒就会有成百上千个请求在数据库上排队每个请求挂起 10~30 秒后才抛异常Web 线程池都会被拖垮。这就是断熔机制要解决的雪崩问题。断熔机制熔断等待恢复是怎么实现的熔断的触发先 Ping 再熔断核心逻辑在 ObjectPool.cs。SQL 执行出错、连接归还池时以 MySQL 为例MySqlConnectionPool.cs 会先对连接执行Ping()确认数据库确实不通才调用SetUnavailable熔断。SetUnavailable做了三件事记录异常与时间点让IsAvailable变为 false触发策略回调OnUnavailable()——每个从库池在创建时注入回调把共享计数器slaveUnavailables加一启动后台线程周期性检查可用性熔断之后请求再来取连接时ObjectPool.cs 的GetFree会立即抛出 Status unavailable, waiting for recovery 异常。快速失败不让请求继续挂起。这是断熔的本质——把几百个请求挂起 30 秒变成立刻抛异常交给上层重试或降级。后台恢复2 秒一次的心跳探测熔断后ObjectPool.cs 的CheckAvailable开启一个后台线程每隔CheckAvailableInterval秒默认 2 秒从池中取一条连接执行探测 SQL如select 1成功则归还并恢复。恢复时RestoreToAvailable会重置池中所有连接的获取时间防止立刻复用早已陈旧的连接并回调OnAvailable()——对从库来说就是把slaveUnavailables减一重新参与读写分离。 设计细节熔断与恢复都是带锁的幂等状态迁移只有第一个触发的调用真正执行回调并发异常风暴下通知只触发一次不会把业务回调打成风暴。读写分离一条查询如何选中从库判定规则哪些 SQL 能走从库规则在 AdoProviderUtils.cs非常简单存储过程或以SELECT/WITH开头的语句 → 读可走从库其他语句 → 写必须走主库事务内、或用户显式传入DbConnection时 → 强制主库这个看 SQL 首词的规则零解析成本是典型的工程权衡不如完整解析 SQL 精确但 99% 场景够用、且永远不会误判写操作。权重随机多个从库如何分流AdoProvider.cs 中多个可用从库时按Policy.Weight做加权随机总权重决定随机区间权重越大被命中概率越高。你可以用UseSlaveWeight(1, 5, 2)配置实现一强多弱的灰度分流见 FreeSqlBuilder.cs。从库故障三级降级整个设计里最优雅的是slaveUnavailables不可用从库数驱动的三级降级slaveUnavailables行为0直接随机查从库0 n 从库总数只查可用从库 从库总数读流量整体回退主库这就是读写分离自动切换。并且如果选中从库后实际执行仍失败还有第二道保险AdoProvider.cs 会记录该失败并在必要时递归地在主库重放同一条查询——业务方完全无感。可以关掉断熔UseAdoConnectionPool构建器的注释非常坦诚FreeSqlBuilder.cs有部分使用者不喜欢【断熔机制】可使用此设置。UseAdoConnectionPool(true)会切换到 ADO.NET 原生池放弃断熔与监控。顺带一提对 MySQL、SqlServer、PostgreSQL、达梦、神通等数据库构建器默认就是true见 FreeSqlBuilder.cs 的分支判断因为这些驱动自带成熟的内置池。值得学习的是这种设计态度默认给出最优选择但绝不绑架你的选择。可观测性随时查看连接池心率fsql.Ado.Statistics会为每个池输出一行可用/总连接数、同步等待数、异步等待数见 ObjectPool.cs。配合fsql.Aop.CommandAfter的耗时日志一眼就能看出瓶颈出在主库、从库还是等待队列。关键池参数速查参数默认值含义PoolSize100MySQL/ 1000ADO 池连接数上限SyncGetTimeout10 秒同步等待连接的超时时间IdleTimeout20 秒空闲超时超时连接被销毁重建AsyncGetCapacity10000异步等待队列长度上限CheckAvailableInterval2 秒熔断后后台恢复探测间隔Weight1读写分离权重默认值见 DbConnectionPool.cs。总结FreeSql 连接池在做一件事把慢失败变成快速失败 自动恢复。断熔机制出错即快速失败 → 后台 2 秒一次心跳探测 → 恢复后自动放回流量读写分离按 SQL 首词判定 → 权重随机分流 → 从库故障三级降级回主库全程可观测且断熔可一键关闭这套设计与微服务框架里的 Circuit Breaker 如出一辙只是 FreeSql 把它落到了数据库连接层——代价很小换来的却是线上故障时的从容。【免费下载链接】FreeSql功能强大的对象关系映射O/RM组件支持 .NET Core 2.1、.NET Framework 4.0、Xamarin 以及 AOT。项目地址: https://gitcode.com/dotnetcore/FreeSql创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考