基于原来的 读写分离实践简单记录 发现有一个问题, 就是数据同步延迟的问题, 一半会延迟800毫秒左右, 目前的改造解决方案是 :
1. 基于线程
记录上一次执行更新操作(包括添加和删除)的时间到线程, 5秒之内的读操作,都从读写库中读取。 发现如果是ajax 请求会有问题。
2. 基于session (目前采用的方案)
记录上一次执行更新操作(包括添加和删除)的时间到Session, 5秒之内的读操作,都从读写库中读取。
3. 基于log(还没有实施)
想法是比较两个库的事务log(sys.dm_hadr_database_replica_states表中的 end_of_log_lsn)是否一致,如果一致说明就是已经同步了 这个方案的问题就是如果主库一直在写, 那么 log就是一直不一致, 那么读库一直不会被命中。
最后上 基于session 方案的 代码:
/// <summary>
///
/// </summary>
/// <param name="sql"></param>
/// <param name="connectstring"></param>
/// <param name="isRead">0 unknow, 1 读写, 2 只读,</param>
/// <returns></returns>
private static string GetReadConnectstring(string sql, string connectstring, int isRead = 0)
{
if (!SqlConnectionString.CheckIsSuportReadonly(connectstring))
{
return connectstring;
}
bool isquery = false;
if (isRead == 0)
{
isquery = IsSelect(sql);
}
if (isRead == 1)
{
isquery = false;
}
var result = SqlConnectionString.GetReadonlyConnectionstring(connectstring);
if (isRead == 2)
{
return result;
}
if (isquery && (DateTime.Now.Subtract(PreExecTime).TotalMilliseconds > DELAY_TIME))
{
//result = ;
}
else
{
result = connectstring;
}
if (!isquery)
{
PreExecTime = DateTime.Now;
}
return result;
}
private const int DELAY_TIME = 5000;
// 上一次执行 更新操作的时间
//private static DateTime _preExecTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
private const string PREEXECTIME_SESSION_KEY = "PreExecTime";
/// <summary>
/// 上一次执行 更新操作的时间
/// </summary>
private static DateTime PreExecTime
{
get
{
if (HttpContext.Current == null || HttpContext.Current.Session == null)
{
return DateTime.Now;
}
else
{
return ConvertHelper.ToDateTime(HttpContext.Current.Session[PREEXECTIME_SESSION_KEY], new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day));
}
}
set
{
if (HttpContext.Current != null && HttpContext.Current.Session != null)
{
HttpContext.Current.Session[PREEXECTIME_SESSION_KEY] = value;
}
}
}