zoukankan      html  css  js  c++  java
  • 系统架构~高并发日志系统设计

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

    一 项目结构图

    二 项目实现代码

      /// <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());
            }
        }
  • 相关阅读:
    初识 Rabbitmq
    Lambda表达式(C语言-gcc编译器)
    二叉树转换成双向链表
    进程的内存分布
    Linux shell之数组
    Ubuntu 使用Gparted工具扩大第一分区方法步骤
    Android源码编译出错解决办法
    IIC总线解析
    VirtualBox Ubuntu虚拟机串口编程
    ubuntu虚拟机上解决克隆github代码慢的方法
  • 原文地址:https://www.cnblogs.com/lori/p/3921310.html
Copyright © 2011-2022 走看看