系統架構~高併發日誌系統設計

對於一個項目來講,日誌是必須的,通常日誌的持久化方式有文件和數據庫,而在多數狀況下,咱們都採用文件系統來實現,而對於高併發的狀況下,頻繁進行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的入口ide

           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());
        }
    }
相關文章
相關標籤/搜索