0
点赞
收藏
分享

微信扫一扫

系统架构~高并发日志系统设计

最后的执着 2022-08-25 阅读 65

对于一个项目来说,日志是必须的,一般日志的持久化方式有文件和数据库,而在多数情况下,我们都采用文件系统来实现,而对于高并发的情况下,频繁进行I/O操作,对系统的性能肯定是有影响的,这个毋庸置疑!针对这种高并发的场合,我们采用一种缓存队列的方式来处理这个Case是比较明智的,本文主要是向各位展现一下,我所设计的《高并发日志系统设计》,如在功能上有什么需要改进的地方,欢迎各位来回复。

一 项目结构图

系统架构~高并发日志系统设计_mvc

二 项目实现代码

/// <summary>
/// 工作任务基类
/// </summary>
public abstract class JobBase
{
/// <summary>
/// log4日志对象
/// </summary>
protected log4net.ILog Logger
{
get
{
return log4net.LogManager.GetLogger(this.GetType());//得到当前类类型(当前实实例化的类为具体子类)
}
}
}

public class ActionTimeJob : JobBase, IJob
{

#region Fields & Properties
/// <summary>
/// 锁对象
/// </summary>
private static object lockObj = new object();
#endregion

#region IJob 成员

public void Execute(IJobExecutionContext context)
{
lock (lockObj)
{
try
{
if ((System.Web.HttpRuntime.Cache["RunTime"] as Queue<Tuple<int, string>>) != null
&& (System.Web.HttpRuntime.Cache["RunTime"] as Queue<Tuple<int, string>>).Count > 0)
{
var temp = (System.Web.HttpRuntime.Cache["RunTime"] as Queue<Tuple<int, string>>).Dequeue();
if (temp != null)
{
//! 超时,开始记录日志
global::Logger.Core.LoggerFactory.Instance.Logger_Info(
string.Format("出现异常的页面:{0},页面加载需要的时间:{1}秒,异常发生时间:{2}"
, temp.Item2, temp.Item1, DateTime.Now),"actionTime.log");
}
}
}
catch (Exception ex )
{

throw ex;
}
}
}

#endregion
}

从上面的代码中,我们可以看到,这是使用quartz组件实现的,对某个方法进行轮训调用的,下面是quartz的入口

const string DEFAULTINTERVAL = "300";//默认为5分钟
string user_Classroom_RJobInterval = ConfigurationManager.AppSettings["ActionRunTimeJob"]
?? DEFAULTINTERVAL;

ISchedulerFactory sf = new Quartz.Impl.StdSchedulerFactory();
IScheduler sched = sf.GetScheduler();
//一个工作可以由多个组组成,而每个组又可以由多个trigger组成
IDictionary<IJobDetail, IList<ITrigger>> scheduleJobs = new Dictionary<IJobDetail, IList<ITrigger>>();

#region ActionRunTimeJob
scheduleJobs.Add(JobBuilder.Create<ActionTimeJob>()
.WithIdentity("job1", "group1")
.Build(),
new List<ITrigger>
{
(ICronTrigger)TriggerBuilder.Create()
.WithIdentity("trigger", "group1")
.WithCronSchedule(user_Classroom_RJobInterval)
.Build()
});

sched.ScheduleJobs(scheduleJobs, true);
sched.Start();
#endregion

而何时向队列里添加信息这个功能还没有说,事实上,在MVC3里有这样一个功能,它可以向所有action上添加一些特性(过滤器,attribute),我们称它为全局过滤器,它的入口也是在global.asax里,下面添加了一个过滤器,实现的功能是当页面加载时间过长时,进行缓存队列的添加,这里默认是6秒时

/// <summary>
/// Action渲染页面所需要的时间
/// </summary>
public class ActionRenderTimeAttribute : System.Web.Mvc.ActionFilterAttribute
{
#region 本对象的timer不好使用
/// <summary>
/// 存储并发的队列
/// </summary>
public volatile static Queue<Tuple<int, string>> TempList = new Queue<Tuple<int, string>>();
/// <summary>
/// 时间戳
/// </summary>
static System.Timers.Timer sysTimer = new System.Timers.Timer(1000);
/// <summary>
/// 静态构造
/// </summary>
static ActionRenderTimeAttribute()
{
sysTimer.AutoReset = true;
sysTimer.Enabled = true;
sysTimer.Elapsed += sysTimer_Elapsed;
sysTimer.Start();
}
/// <summary>
/// 触发事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void sysTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (TempList.Count > 0)
{
lock (lockObj)
{
var temp = TempList.Dequeue();
//! 超时,开始记录日志
Logger.Core.LoggerFactory.Instance.Logger_Info(
string.Format("出现异常的页面:{0},超时时间{1}:秒,异常发生时间:{2}"
, temp.Item2, temp.Item1, DateTime.Now));
}
}
}
#endregion

/// <summary>
/// 锁对象
/// </summary>
static object lockObj = new object();
/// <summary>
/// 记录进行Action的时间
/// </summary>
DateTime joinTime;
/// <summary>
/// 进行action之前
/// </summary>
/// <param name="filterContext"></param>
public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)
{
joinTime = DateTime.Now;
base.OnActionExecuting(filterContext);
}
/// <summary>
/// 渲染页面HTML之后
/// </summary>
/// <param name="filterContext"></param>
public override void OnResultExecuted(System.Web.Mvc.ResultExecutedContext filterContext)
{
int outSeconds;//! 超时的秒数,默认为60000ms
int isActionRender;//开关
int.TryParse((System.Configuration.ConfigurationManager.AppSettings["ActionRenderTime"] ?? "6000").ToString(), out outSeconds);
int.TryParse((System.Configuration.ConfigurationManager.AppSettings["isActionRender"] ?? "0").ToString(), out isActionRender);

var timeSpan = (DateTime.Now - joinTime).Milliseconds;
if (timeSpan > outSeconds && isActionRender == 1)
{
lock (lockObj)
{
var temp = (System.Web.HttpRuntime.Cache["RunTime"] as Queue<Tuple<int, string>>) ?? new Queue<Tuple<int, string>>();
temp.Enqueue(new Tuple<int, string>(timeSpan, filterContext.RequestContext.HttpContext.Request.Url.AbsoluteUri));
System.Web.HttpRuntime.Cache.Insert("RunTime", temp);
}
}

base.OnResultExecuted(filterContext);
}


}

下面是FilterConfig注入的代码

public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new MVVM.ActionRenderTimeAttribute());
}
}

 

作者:仓储大叔,张占岭,
荣誉:微软MVP



举报

相关推荐

0 条评论