In the previous part, the formulation, loading and analysis of alarm rules, as well as the definition, loading and expansion of alarm executor were explained. Basically, the core content has been finished, and the rest of the content is relatively simple

  • Alarm frequency statistics
  • Alarm thread pool
  • Decoupling available uniformly for external packaging

I. Alarm frequency statistics

1. The design

In the previous alarm rule parsing, there was a count parameter, which was used to determine the specific selection of the core parameters of the alarm actuator. Our maintenance method was also relatively simple:

  • For the alarm type, count statistics, not called once, count +1
  • Zero out every minute

2. Implement

For each alarm type, a separate counter is maintained

Define a map to store the mappings

private ConcurrentHashMap<String, AtomicInteger> alarmCountMap;
Copy the code

Zeros are cleared every minute

// Clear one alarm count per minute
ScheduledExecutorService scheduleExecutorService = Executors.newScheduledThreadPool(1);
scheduleExecutorService.scheduleAtFixedRate(() -> {
    for (Map.Entry<String, AtomicInteger> entry : alarmCountMap.entrySet()) {
        entry.getValue().set(0); }},0.1, TimeUnit.MINUTES);
Copy the code

Notice the implementation above, what’s the problem?

Is it possible that because the data in the map is too large (or gc whatever), it takes a lot of time to clear each zero, resulting in inaccurate counts? (No answer yet)

Count plus one operation

/** * Thread safe to get the total number of alarms and automatically increment by 1 **@param key
 * @return* /
private int getAlarmCount(String key) {
    if(! alarmCountMap.containsKey(key)) {synchronized (this) {
            if(! alarmCountMap.containsKey(key)) { alarmCountMap.put(key,new AtomicInteger(0)); }}}return alarmCountMap.get(key).addAndGet(1);
}
Copy the code

II. Alarm thread pool

The main idea is to abstract a forkJoin-based concurrency framework to handle this. The main idea is that I have recently come across a forkjoin-based concurrency component, so when I get to the bottom of it, I will try to copy it.

// Alarm thread pool
private ExecutorService alarmExecutorService = new ThreadPoolExecutor(3.5.60,
        TimeUnit.SECONDS,
        new LinkedBlockingDeque<>(10), 
        new DefaultThreadFactory("sms-sender"),
        new ThreadPoolExecutor.CallerRunsPolicy());
Copy the code

Task Submission execution

private void doSend(final ExecuteHelper executeHelper, 
  final AlarmContent alarmContent) {
    alarmExecutorService.execute(() ->
      executeHelper.getIExecute().sendMsg(
        executeHelper.getUsers(), 
        alarmContent.getTitle(), 
        alarmContent.getContent()));
}
Copy the code

III. Interface encapsulation

There’s nothing more to say about that

public void sendMsg(String key, String content) {
    sendMsg(new AlarmContent(key, null, content));
}


public void sendMsg(String key, String title, String content) {
    sendMsg(new AlarmContent(key, title, content));
}

/** * 1. Get alarm configuration item * 2. Get current alarm number * 3. Select appropriate alarm type * 4. Execute alarm * 5. Alarm times +1 * *@param alarmContent
 */
private void sendMsg(AlarmContent alarmContent) {
    try {
        // get alarm config
        AlarmConfig alarmConfig = confLoader.getAlarmConfig(alarmContent.key);

        // get alarm count
        int count = getAlarmCount(alarmContent.key);
        alarmContent.setCount(count);


        ExecuteHelper executeHelper;
        if (confLoader.alarmEnable()) { // get alarm execute
            executeHelper = AlarmExecuteSelector.getExecute(alarmConfig, count);
        } else {  // If the alarm is off, the alarm process will be empty and the alarm information will be written into the log file
            executeHelper = AlarmExecuteSelector.getDefaultExecute();
        }


        // do send msg
        doSend(executeHelper, alarmContent);
    } catch (Exception e) {
        logger.error("AlarmWrapper.sendMsg error! content:{}, e:{}", alarmContent, e); }}Copy the code

How to use the interface after encapsulation?

We use singleton mode to encapsulate the only AlarmWrapper class for external use, which is relatively simple to use. The following is a test case

@Test
public void sendMsg(a) throws InterruptedException {
    String key = "NPE";
    String title = "NPE abnormal";
    String msg = "NPE abnormal!!";

    AlarmWrapper.getInstance().sendMsg(key, title, msg);  // Wechat alarm

    // There is no abnormal configuration type and the default alarm is used. If the number of times is small, the alarm is directly deployed
    AlarmWrapper.getInstance().sendMsg("zzz"."No XXX abnormal configuration exists"."Call the police, ta-da, ta-da.");
    
    Thread.sleep(1000);
}
Copy the code

It’s a little bit easier to use, just one line, and you can see from this use that the entire initialization is done when this object is first accessed

The constructor looks like this:

private AlarmWrapper(a) {
  // Record the number of alarms for each exception
  alarmCountMap = new ConcurrentHashMap<>();

  // Load alarm configuration information
  confLoader = ConfLoaderFactory.loader();

  // Initialize the thread pool
  initExecutorService();
}
Copy the code

So if you want to load all the configuration before your application uses it, you might want to call alarmWrapper.getInstance ().

IV. The summary

Based on this, the whole system design is basically completed, of course, the code level is OK, the rest is the user manual

Looking at our entire logic, it’s basically the following flow

  1. Submit the report to the police
  • Encapsulate alarm content (alarm type, alarm subject, alarm content)
  • Maintain alarm count (count cleared per minute, one alarm count for each alarm type)
  1. Select the alarm
  • Select alarm rules according to alarm types
  • Select alarm actuator according to alarm rule and current alarm frequency
    • If interval mapping is not enabled, the default actuator is returned
    • Otherwise, the alarm frequency interval of all actuators is traversed and the matching alarm rule is selected
  1. Perform alarm
  • Encapsulate the alarm task and submit the thread pool
  • The concrete alarm logic is realized inside the alarm actuator

V. other

Related blog

  1. Alarm system QuickAlarm overview
  2. Design and implementation of alarm actuator for QuickAlarm alarm system
  3. Setting and loading of alarm rules for alarm system QuickAlarm
  4. Alarm rule parsing for Alarm system QuickAlarm
  5. Alarm system QuickAlarm frequency statistics and interface encapsulation
  6. Alarm System QuickAlarm User manual

Project: QuickAlarm

  • Project address: Quick-alarm
  • Blog address: Little Grey Blog

Personal Blog:Z+|blog

Hexo + Github Pages, hexo + Github Pages, hexo + Github Pages, Hexo + Github Pages

The statement

As far as the letter book is not as good as, has been on the content, pure one’s opinion, because of my ability is general, knowledge is limited, if you find a bug or have a better suggestion, welcome criticism and correction at any time, my micro Blog address: small gray Blog

Scanning attention