天天看點

Adhesive架構系列文章--報警服務子產品使用和實作

Adhesive架構的Mongodb資料服務子產品提供了大量資料的存儲功能。在有的時候,我們希望對資料量或是資料的某個值進行一個監控,并且在達到某個閥值之後進行報警。此時,可以使用報警服務子產品進行郵件報警和短信報警。報警服務的實作其實很簡單,定期檢測資料量或資料的值,然後根據配置決定是否要報警,如果要的話,根據配置擷取報警的接收者,然後進行相應的報警。現在先來看一下報警服務的配置,同樣,打開配置背景可以在全局配置中找到報警服務的配置節點:

點選進去:
Adhesive架構系列文章--報警服務子產品使用和實作

在這裡依次介紹一下每一個配置:

1、狀态資料的報警配置:這裡配置了基于狀态資料的報警配置。所謂狀态資訊,就是始終隻有一條最新的資料代表了一個狀态,報警也就是檢視其中某個列的值,根據這個值來判斷是否需要報警。

2、統計資料的報警配置:這裡配置了基于統計資料的報警配置。所謂統計資料,就是一個時間間隔内有多少條資料寫入,報警取決于資料量,而不是其中某一條資料的某個列的值。

3、接收者的配置:在這裡把報警資料接收者分了組,使用組的概念來管理這些資訊接收者。

4、短信服務的類别ID:這個是我們公司特有的短信通道的類别ID,不具有普适性。

5、郵件伺服器的位址和帳号:在這裡發送郵件使用的是Common子產品中提供的JMail發送郵件的功能。

6、郵件标題和正文以及短信和日志消息的模闆:這裡配置的是,發送郵件的标題和正文、發消息的内容以及日志記錄的内容的一個模闆。其中有很多占位符:

1)配置的名字

2)列名

3)報警時間間隔

4)資料量

5)條件類型

6)閥值

一個典型的資料如下:

Adhesive.Test.Mvc錯誤日志監控 ItemCount 60秒 1400 MoreThan 100

7、發送郵件和短消息的時間間隔,發送郵件和短消息出錯後的時間間隔:在這裡我們還是使用了記憶體隊列服務子產品來發送郵件和短消息,這裡配置的是正常情況下多少毫秒發送一次郵件或短消息,以及錯誤情況下多少時間後再一次嘗試進行短消息和郵件的發送。

先來看一下報警接收者分組的配置:

Adhesive架構系列文章--報警服務子產品使用和實作

在這裡我們添加了一個名為測試的組:

Adhesive架構系列文章--報警服務子產品使用和實作

對于每一個組都有如下的配置:

1、組名

2、是否開啟郵件消息

3、是否開啟手機短信消息

4、發送郵件消息的間隔,也就是在一定時間内隻會發送一次消息

5、發送手機消息的間隔,同上。在有的時候我們可能會對相同的報警資訊發送到兩個組,第一個組允許1秒收一次消息,而第二個組是上司組,不希望有很多騷擾,那麼可以配置時間長一點。

6、組内的接收者明細:

Adhesive架構系列文章--報警服務子產品使用和實作

這裡配置了一個使用者,再點選進去檢視明細:

Adhesive架構系列文章--報警服務子產品使用和實作

對于每一個使用者配置帳号、真實姓名、手機号碼和郵箱位址。

然後,來看一下兩種報警模式的配置,第一個是基于資料量的報警:

Adhesive架構系列文章--報警服務子產品使用和實作

點選進入資料量統計配置節點之後可以看到在這裡我們配置了一個叫錯誤日志監控的報警。也就是希望監控Adhesive.Test.Mvc這個表中錯誤日志的資料量,現在來看一下怎麼通過靈活的配置完成這個功能:

Adhesive架構系列文章--報警服務子產品使用和實作

首先,我們知道錯誤日志是存在Aic__Log這個資料庫中的,那麼我們指定資料庫名為Aic__Log。然後我們希望針對Adhesive.Test.Mvc這個表進行報警,那麼也需要配置相應的表名。然後我們希望配置1分鐘内資料量超過100條則報警,那麼需要把時間間隔配置為1分鐘,把資料量閥值配置成100,把條件類型配置為MoreThan,這是一個枚舉:

internal enum AlarmConditionType
    {
        LessThan = 1,
        LessThanAndEqualTo = 2,
        MoreThan = 3,
        MoreThanAndEqualTo = 4,
    }      

并且配置10秒進行一次檢查,前1分鐘是不是達到閥值。這裡還有一個問題,就是我們希望隻針對錯誤級别的日志進行報警,那麼我們需要進一步配置資料過濾:

Adhesive架構系列文章--報警服務子產品使用和實作

在這裡配置Lev為4。可以對比下LogInfo的定義:

[MongodbPersistenceItem(MongodbIndexOption = MongodbIndexOption.Ascending, ColumnName = "Lev")]
        [MongodbPresentationItem(MongodbFilterOption = MongodbFilterOption.DropDownListFilter, DisplayName = "日志級别", ShowInTableView = true)]
        public LogLevel LogLevel { get; set; }      

其中看到,日志級别的列名為Lev,并且LogLevel值為4的級别是Error:

public enum LogLevel
    {
        None = 99,
        Debug = 1,
        Info = 2,
        Warning = 3,
        Error = 4
    }      

最後,看一下基于狀态的配置:

Adhesive架構系列文章--報警服務子產品使用和實作

在這裡我們希望監控Mongodb服務端記憶體隊列中目前項的數量,如果數量超過100則報警(記憶體中有100條剩餘的資料來不及送出到資料庫)。

Adhesive架構系列文章--報警服務子產品使用和實作

基本的配置和統計量的配置差不多,隻不過注意這裡的列名是模糊比對的:

Adhesive架構系列文章--報警服務子產品使用和實作

對比一下State__MongodbServer的定義,也就是任意一個記憶體隊列的CurrentItemConut超過100都會報警。之是以能這樣是因為我們Mongodb存儲字典是樹形結構的。

介紹了報警服務的配置之後,我們來看其中的一個最關鍵的實作,也就是服務的初始化過程:

internal static void Init()
        {
            mailService.Init(AlarmConfiguration.GetConfig().MailSmtp, AlarmConfiguration.GetConfig().MailUsername, AlarmConfiguration.GetConfig().MailPassword);
            mobileService.Init(AlarmConfiguration.GetConfig().MobileCategoryId);

            mailMemoryQueueService.Init(new MemoryQueueServiceConfiguration("AlarmService_MailQueue", mailService.Send)
            {
                ConsumeItemCountInOneBatch = 1,
                ConsumeIntervalMilliseconds = AlarmConfiguration.GetConfig().MailMessageInerval,
                ConsumeIntervalWhenErrorMilliseconds = AlarmConfiguration.GetConfig().MailMessageErrorInerval,
                ConsumeErrorAction = MemoryQueueServiceConsumeErrorAction.EnqueueTwiceAndLogException
            });
            mobileMemoryQueueService.Init(new MemoryQueueServiceConfiguration("AlarmService_MobileQueue", mobileService.Send)
            {
                ConsumeItemCountInOneBatch = 1,
                ConsumeIntervalMilliseconds = AlarmConfiguration.GetConfig().MobileMessageInerval,
                ConsumeIntervalWhenErrorMilliseconds = AlarmConfiguration.GetConfig().MobileMessageErrorInerval,
                ConsumeErrorAction = MemoryQueueServiceConsumeErrorAction.EnqueueTwiceAndLogException
            });
            var config = AlarmConfiguration.GetConfig();
            foreach (var item in config.AlarmConfigurationByStatistics)
            {
                var alarmServiceState = new AlarmServiceState
                {
                    AlarmConfigurationItemName = item.Key,
                    AlarmServiceStateItems = new Dictionary<string, AlarmServiceStateItem>(),
                };
                item.Value.AlarmReceiverGroupNames.Values.Each(groupName =>
                {
                    alarmServiceState.AlarmServiceStateItems.Add(groupName, new AlarmServiceStateItem
                    {
                        ReceiverGroupName = groupName,
                        AlarmReceiverGroupLastMailMessageTime = DateTime.MinValue,
                        AlarmReceiverGroupLastMobileMessageTime = DateTime.MinValue,
                    });
                });
                var interval = item.Value.CheckTimeSpan;
                var timer = new System.Threading.Timer(CheckActionForStatistics, item.Key, interval, interval);
                alarmServiceState.CheckTimer = timer;
                alarmServiceStates.Add(alarmServiceState);
            }

            foreach (var item in config.AlarmConfigurationByStates)
            {
                var alarmServiceState = new AlarmServiceState
                {
                    AlarmConfigurationItemName = item.Key,
                    AlarmServiceStateItems = new Dictionary<string, AlarmServiceStateItem>(),
                };
                item.Value.AlarmReceiverGroupNames.Values.Each(groupName =>
                {
                    alarmServiceState.AlarmServiceStateItems.Add(groupName, new AlarmServiceStateItem
                    {
                        ReceiverGroupName = groupName,
                        AlarmReceiverGroupLastMailMessageTime = DateTime.MinValue,
                        AlarmReceiverGroupLastMobileMessageTime = DateTime.MinValue,
                    });
                });
                var interval = item.Value.CheckTimeSpan;
                var timer = new System.Threading.Timer(CheckActionForState, item.Key, interval, interval);
                alarmServiceState.CheckTimer = timer;
                alarmServiceStates.Add(alarmServiceState);
            }
        }
    }      

我們知道在報警服務子產品中,我們也是通過記憶體隊列服務來進行郵件和短信資料發送的,那麼我們首先是初始化兩個記憶體隊列。

然後,我們讀取配置,分别為基于統計資料的報警和基于狀态的報警初始化背景的定時器,每一種配置一個定時器。定時器的執行間隔就是前面提到的CheckTimeSpan。而我們的代碼中也定義了alarmServiceStates字段作為根:

private static List<AlarmServiceState> alarmServiceStates = new List<AlarmServiceState>();      

作者:

lovecindywang

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。