1. 高可用架构的基础认知

当我们的电商系统在双十一突然宕机,当医院的HIS系统在急救时失去响应,这些场景都在提醒我们数据库高可用(HA)和灾难恢复(DR)的重要性。作为C#开发者,我们手中的System.Data.SqlClient就像手术刀,需要精准地对接SQL Server的高可用架构。

SQL Server常见的HA方案包括:

  • Always On可用性组(主流选择)
  • 数据库镜像(已逐渐淘汰)
  • 故障转移集群(适合传统架构)
  • 日志传送(辅助DR方案)

这些架构的共同特点是:当主节点故障时,备用节点能快速接管服务。而我们的代码,需要像经验丰富的导航员,在故障发生时自动切换航道。

2. 连接字符串的智能配置

// 基础连接字符串配置示例
var connectionString = @"Server=NodeA,1433; 
    Failover Partner=NodeB,1433;
    Database=OrderDB;
    User ID=sa;
    Password=YourStrongPassword!;
    Connect Timeout=30;
    Application Name=MyHAApp;";

// 多子网轮询配置(SQL Server 2016+)
var multiSubnetString = @"Server=NodeA,NodeB,NodeC;
    Database=InventoryDB;
    Integrated Security=True;
    MultiSubnetFailover=True;
    Connect Timeout=15;";

关键参数说明:

  • Failover Partner:指定故障转移伙伴节点
  • MultiSubnetFailover:加速多子网环境下的故障检测
  • Connect Timeout:建议设置在15-30秒之间
  • Application Name:方便DBA进行会话追踪

3. 客户端故障转移实战

3.1 自动重连机制

public class SqlHAHelper
{
    private static readonly string[] servers = 
    {
        "PrimaryNode", 
        "SecondaryNode",
        "DRSiteNode"
    };

    public static SqlConnection GetHAConnection()
    {
        foreach (var server in servers)
        {
            try
            {
                var conn = new SqlConnection(
                    $"Server={server}; Database=CRM; Integrated Security=True;");
                conn.Open();
                conn.StateChange += (sender, e) => 
                {
                    if (e.CurrentState == ConnectionState.Broken)
                        RetryPolicy();
                };
                return conn;
            }
            catch (SqlException ex)
            {
                LogError($"连接 {server} 失败: {ex.Number}");
                if (ex.Number == 4060) // 数据库不可用
                    continue;
            }
        }
        throw new Exception("所有节点均不可用");
    }
}

3.2 读写分离策略

// 读写分离执行器示例
public class SqlExecutor
{
    private static SqlConnection _writeConn;
    private static SqlConnection _readConn;

    public void ExecuteNonQueryHA(string sql)
    {
        using (var conn = GetWriteConnection())
        using (var cmd = new SqlCommand(sql, conn))
        {
            cmd.CommandTimeout = 60; // 写操作超时延长
            cmd.ExecuteNonQuery();
        }
    }

    public DataTable ExecuteQueryHA(string sql)
    {
        using (var conn = GetReadConnection())
        using (var cmd = new SqlCommand(sql, conn))
        {
            cmd.CommandTimeout = 30;
            using (var da = new SqlDataAdapter(cmd))
            {
                var dt = new DataTable();
                da.Fill(dt);
                return dt;
            }
        }
    }

    private SqlConnection GetWriteConnection() => 
        new SqlConnection(ConfigurationManager.ConnectionStrings["WriteDB"].ConnectionString);

    private SqlConnection GetReadConnection() =>
        new SqlConnection(ConfigurationManager.ConnectionStrings["ReadDB"].ConnectionString);
}

4. 异常处理的艺术

try
{
    using (var conn = new SqlConnection(haConnectionString))
    {
        conn.Open();
        // 业务操作...
    }
}
catch (SqlException ex) when (ex.Number == 121)  // 连接超时
{
    Thread.Sleep(5000);
    RetryOperation();
}
catch (SqlException ex) when (ex.Number == 64)  // 连接被重置
{
    SwitchToDRSite();
}
catch (SqlException ex) when (ex.Number == 18456)  // 登录失败
{
    RefreshCredentials();
}
catch (Exception ex)
{
    LogToCentral(ex);
    throw;
}

5. 性能优化要点

  • 连接池调优
    // 连接字符串参数优化
    "Max Pool Size=200; Min Pool Size=50; Connection Lifetime=300;"
    
  • 异步操作规范
    public async Task<DataTable> QueryAsync(string sql)
    {
        using (var conn = new SqlConnection(connectionString))
        {
            await conn.OpenAsync();
            using (var cmd = new SqlCommand(sql, conn))
            {
                using (var reader = await cmd.ExecuteReaderAsync())
                {
                    var dt = new DataTable();
                    dt.Load(reader);
                    return dt;
                }
            }
        }
    }
    

6. 应用场景分析

典型应用案例:

  1. 金融交易系统:要求99.99%可用性
  2. 物联网数据平台:处理突发流量高峰
  3. 跨国电商系统:多地域部署需求
  4. 政府政务系统:数据零丢失要求

7. 技术方案优缺点

优势:

  • 原生支持SQL Server特性
  • 配置灵活,可适配多种HA架构
  • 完善的错误代码体系
  • 与.NET生态完美集成

局限:

  • 对非微软数据库支持有限
  • 多活架构实现复杂度高
  • 客户端负载均衡需自行实现

8. 实施注意事项

  1. 定期测试故障转移流程(建议季度演练)
  2. 监控连接池使用率(推荐使用PerfMon计数器)
  3. 避免在事务中切换连接
  4. 加密Always On流量(证书或Windows集成验证)
  5. 版本兼容性验证(不同SQL Server版本行为差异)

9. 关联技术扩展

PolyBase集成示例:

// 跨数据库查询
var sql = @"
SELECT o.OrderID, c.CustomerName 
FROM OrderDB.dbo.Orders AS o
JOIN CustomerDB.dbo.Customers AS c
    ON o.CustomerID = c.CustomerID";

// 跨实例查询(需要Linked Server配置)
var crossInstanceSql = @"
SELECT * 
FROM [DRSite].InventoryDB.dbo.Products
WHERE StockQty > 100";

10. 方案总结

通过System.Data.SqlClient实现高可用,就像为数据库连接装上智能导航系统。从连接字符串的精心设计到异常处理的层层防御,每个环节都需要开发者对SQL Server的HA特性有深刻理解。记住,真正的灾难恢复不是配置几个参数,而是建立完整的监控-报警-切换-验证闭环。