.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (下)
Posted 言00FFCC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (下)相关的知识,希望对你有一定的参考价值。
前言:
延续上一篇博客写的 数据库主从分离配置,本篇简单介绍一下代码层面的负载均衡策略。
在上篇文章中,已经实现了两个数据库间的实时同步,那么对于代码层面,就需要根据T-SQL语句的操作是读还是写,来链接不同的数据库。
1、创建一个枚举 LibraDbBehaviorEnum
/// <summary>
/// 数据库操作的行为
/// </summary>
public enum LibraDbBehaviorEnum
Read,
Write
2、创建模型 LibraConnectionStringModel
用来存储每个链接对象配置
/// <summary>
/// 每个数据库链接模型
/// </summary>
public class LibraConnectionStringModel
/// <summary>
/// 当前连接字符串
/// </summary>
public string ConnectionString get; set;
/// <summary>
/// 权重数值 Weighing模式可用
/// </summary>
public int WeighingNumber get; set;
/// <summary>
/// 请求次数
/// </summary>
internal int AskCount get; set; = 0;
/// <summary>
/// 最近10次耗时 供压力策略使用的
/// </summary>
internal double[] TimeConsume get; set; = new double[10];
3、创建枚举 LibraStrategyReaderEnum
用来标识负载均衡的读策略,提供四种策略供参考。
public enum LibraStrategyReaderEnum
/*
读取负载均衡实现方式:
1、轮询策略
2、随机策略
3、权重策略
4、压力策略
a) 可根据近百次响应时间的平均来分配
b) 根据服务器硬件实时监控来分配
c) 根据当前每台服务器的数据库链接数来分配
5 ...
*/
/// <summary>
/// 轮询平均策略
/// </summary>
[Description("轮询策略")]
RoundRobin,
/// <summary>
/// 随机平均策略
/// </summary>
[Description("随机策略")]
Random,
/// <summary>
/// 服务器权重策略
/// </summary>
[Description("权重策略")]
Weighing,
/// <summary>
/// 数据库压力策略
/// 使用响应平均分配策略
/// </summary>
[Description("压力策略")]
Pressure
4、创建数据库链接的管理类LibraConnectionStringPool
该类供操作读写数据库时,返回数据库的链接
internal class LibraConnectionStringPool
internal static LibraConnectionStringModel WriteConnection;
internal static List<LibraConnectionStringModel> ReadConnections;
internal static LibraStrategyReaderEnum Strategy;
/// <summary>
/// 初始化连接字符串
/// </summary>
/// <param name="writeConnection">写链接的实体</param>
/// <param name="strategy">读取策略</param>
/// <param name="readConnections">读链接的实体集</param>
internal static void PoolInitialization(LibraConnectionStringModel writeConnection, LibraStrategyReaderEnum strategy, LibraConnectionStringModel[] readConnections)
WriteConnection = writeConnection ?? throw new ArgumentNullException(nameof(writeConnection));
ReadConnections = new List<LibraConnectionStringModel>();
// 如果有配置读链接
if (readConnections != null && readConnections.Length > 0)
// 设置负载均衡策略
Strategy = strategy;
// 如果是权重策略,需要根据权重创建对应权重值的链接。
if (Strategy == LibraStrategyReaderEnum.Weighing)
foreach (var item in readConnections)
for (int i = 0; i < item.WeighingNumber; i++)
ReadConnections.Add(item);
else
ReadConnections = readConnections.ToList();
/// <summary>
/// 根据操作数据库的目的,返回链接字符串
/// </summary>
/// <param name="behavior"></param>
/// <param name="realtime">是否实时查询</param>
/// <returns></returns>
internal static LibraConnectionStringModel GetConnection(LibraDbBehaviorEnum behavior, bool realtime = false)
return behavior switch
LibraDbBehaviorEnum.Read => Dispatcher(realtime),
LibraDbBehaviorEnum.Write => WriteConnection,
_ => throw new Exception("错误的数据操作目的."),
;
private static int _nIndex = 0;
internal static LibraConnectionStringModel Dispatcher(bool realtime)
// 未配置读写分离,则自动返回主库.
// 或者需要实时查询,则返回主库
if (ReadConnections == null || ReadConnections.Count == 0 || realtime) return WriteConnection;
switch (Strategy)
case LibraStrategyReaderEnum.RoundRobin:
var readModel = ReadConnections[_nIndex++ % ReadConnections.Count];
if (_nIndex == ReadConnections.Count) _nIndex = 0;
return readModel;
case LibraStrategyReaderEnum.Random:
case LibraStrategyReaderEnum.Weighing:
var readModel = ReadConnections[new Random(_nIndex++).Next(0, ReadConnections.Count)];
if (_nIndex == ReadConnections.Count) _nIndex = 0;
return readModel;
case LibraStrategyReaderEnum.Pressure:
// 压力策略下,自动获取最小耗时的连接
var sumMaxTimeConsume = ReadConnections.Select(r => r.TimeConsume.Sum()).Min();
return ReadConnections.Where(r => r.TimeConsume.Sum() == sumMaxTimeConsume).First();
// 未配置策略则自动返回主库
default: return WriteConnection;
即使已经配置读写分离,但是也会出现需要查询实时状态下的数据,这时候提供了
realtime
用来返回写链接。
在上方代码中,权重策略与随机策略的逻辑是相同的。不同的是,在初始化配置中,权重策略下,会根据权重值新增了对应多个相同链接。目的在于随机Random
下出现的比值加大。
压力策略,需要根据每次使用链接操作查询的前后进行耗时记录。这里提供简单的实现:
/// <summary>
/// 执行SQL语句的操作
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sql"></param>
/// <param name="func"></param>
/// <param name="parameter"></param>
/// <returns></returns>
public static T Execute<T>(string sql, LibraDbBehaviorEnum behavior, Func<SqlCommand, T> func, bool realtime, params SqlParameter[] parameter)
// 去获取对应的链接字符串对象
var connectionModel = LibraConnectionStringPool.GetConnection(behavior, realtime);
using SqlConnection connection = new SqlConnection(connectionModel.ConnectionString);
SqlCommand command = new SqlCommand(sql, connection);
if (parameter != null && parameter.Length > 0)
command.Parameters.AddRange(parameter);
connection.Open();
// 执行前开启计时器
_watch.Restart();
var result = func.Invoke(command);
// 执行完结束计时器
_watch.Stop();
// 将计时器耗时结果记录到对应链接字符串对象中
connectionModel.TimeConsume[connectionModel.AskCount++ % connectionModel.TimeConsume.Length] = _watch.Elapsed.TotalMilliseconds;
connection.Close();
return result;
至此,数据库的读写分离负载均衡已完成。测试结果就不放上来了。
另外,根据所学知识以及网上教程,写了一个小小的ORM实现框架。 github地址:Libra.orm ,欢迎各位大佬多多指教。
最后,我尽可能详细的去解释介绍如何实现,如果在本文中有错漏之处,请各位大佬们多多指教。如果我的文章能帮到你,也请各位不吝点个赞点个收藏,如果对文中代码有疑问,也请下方评论。谢谢各位看官。
以上是关于.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (下)的主要内容,如果未能解决你的问题,请参考以下文章
.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (下)
.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (下)
.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (上)
.Net 下的数据库主从分离以及简单的几种负载均衡策略代码实现 (上)