<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Leo Dev Blog</title>
    <description>The latest articles on DEV Community by Leo Dev Blog (@junjie_qin_512245a2eac9a4).</description>
    <link>https://dev.to/junjie_qin_512245a2eac9a4</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1651343%2F510c48aa-9a7a-46b1-b2fc-81ddb2ff72d3.jpg</url>
      <title>DEV Community: Leo Dev Blog</title>
      <link>https://dev.to/junjie_qin_512245a2eac9a4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/junjie_qin_512245a2eac9a4"/>
    <language>en</language>
    <item>
      <title>Automated Monitoring and Message Notification System for Payment Channels</title>
      <dc:creator>Leo Dev Blog</dc:creator>
      <pubDate>Mon, 25 Nov 2024 00:20:12 +0000</pubDate>
      <link>https://dev.to/junjie_qin_512245a2eac9a4/automated-monitoring-and-message-notification-system-for-payment-channels-5gn0</link>
      <guid>https://dev.to/junjie_qin_512245a2eac9a4/automated-monitoring-and-message-notification-system-for-payment-channels-5gn0</guid>
      <description>&lt;h1&gt;
  
  
  Building an Automated Monitoring System for Payment Channels
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;When third-party channels experience failures, our awareness is often delayed. Typically, we rely on extensive system alerts or feedback from users and business teams to detect anomalies. As the core system responsible for managing company-wide payment operations, it's insufficient to rely solely on manual maintenance. Thus, building a robust automated monitoring system for payment channels becomes crucial.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. Background
&lt;/h2&gt;

&lt;p&gt;To accommodate growing business demands, we have integrated numerous payment channels. However, the stability of third-party systems varies greatly, and channel failures occur frequently. When such anomalies happen, detection often lags, with alerts or user feedback as the primary indicators. For a core payment system aiming to provide stable services upstream, manual maintenance alone is inadequate. This necessitates the establishment of an automated monitoring and management system for payment channels.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Design Goals
&lt;/h2&gt;

&lt;p&gt;Based on our business requirements, the automated payment channel management system should address the following key challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Monitoring capabilities across multiple channels and entities.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rapid fault detection and precise identification of root causes.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimized false positives and missed alerts.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic failover in case of channel failures.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Technology Selection
&lt;/h2&gt;

&lt;p&gt;Given the background, the following technology options were evaluated:&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Circuit Breaker
&lt;/h3&gt;

&lt;p&gt;Circuit breakers are commonly associated with fault isolation and fallback mechanisms. We explored mature solutions such as &lt;strong&gt;Hystrix&lt;/strong&gt;, but identified several limitations for our use case:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Circuit breakers operate at the interface level, lacking granularity for channel- or merchant-level fault isolation.&lt;/li&gt;
&lt;li&gt;During traffic recovery, residual issues may persist, and there's no ability to define targeted traffic for testing (e.g., specific users or services), increasing the risk of secondary incidents.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3.2 Time-Series Database
&lt;/h3&gt;

&lt;p&gt;After ruling out circuit breakers, we turned to developing a custom monitoring system. Time-series databases are often used as the foundation for such systems. Below is an evaluation of popular options:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firtme0l97w2q47znyce2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firtme0l97w2q47znyce2.png" alt="Image description" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the final contenders being &lt;strong&gt;Prometheus&lt;/strong&gt; and a custom solution based on &lt;strong&gt;Redis&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Accuracy
&lt;/h4&gt;

&lt;p&gt;Prometheus sacrifices some accuracy in favor of higher reliability, simplicity in architecture, and reduced operational overhead. While this tradeoff is acceptable for traditional monitoring systems, it does not suit high-sensitivity scenarios like automatic channel failover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Missed Spikes:&lt;/strong&gt; Prometheus might miss transient spikes occurring between two sampling intervals (e.g., 15 seconds).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Statistical Estimates:&lt;/strong&gt; Metrics like QPS, RT, P95, and P99 are approximations and cannot achieve the precision of logs or database records.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1qwpkch5vh5c783xokl0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1qwpkch5vh5c783xokl0.png" alt="Image description" width="800" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Ease of Integration and Maintenance
&lt;/h4&gt;

&lt;p&gt;Prometheus has a learning curve for business developers and poses challenges in long-term maintenance. Conversely, Redis is already familiar to Java backend developers, offering lower initial learning and ongoing maintenance costs.&lt;/p&gt;

&lt;p&gt;Considering the above factors, we decided to build a custom "time-series database" based on Redis to meet our requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Architecture Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Workflow Design
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Transaction Routing:&lt;/strong&gt; For both receiving and making payments, requests are routed through the respective channel router to filter available payment channels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order Processing:&lt;/strong&gt; After selecting the channel, the gateway processes the payment or disbursement request and sends it to the third-party provider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring Data:&lt;/strong&gt; The response from the third-party provider is reported to the monitoring system via a message queue (MQ).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Monitoring System Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;The monitoring system listens to MQ messages and stores monitoring data in Redis.&lt;/li&gt;
&lt;li&gt;The data processing module fetches data from Redis, filters it, calculates failure rates for each channel, and triggers alerts based on configured rules.&lt;/li&gt;
&lt;li&gt;Data in Redis is periodically backed up to MySQL for subsequent fault analysis.&lt;/li&gt;
&lt;li&gt;Offline tasks regularly clean Redis data to avoid excessive storage.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Data Visualization
&lt;/h3&gt;

&lt;p&gt;To observe changes in channel metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Metrics are reported to &lt;strong&gt;Prometheus&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grafana&lt;/strong&gt; dashboards display the channel's health status.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu23zaknjzefbxhie2cyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu23zaknjzefbxhie2cyl.png" alt="Image description" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Automated Channel Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Initially, only manual channel management (online/offline) is enabled due to the sensitivity of the operation.&lt;/li&gt;
&lt;li&gt;After collecting substantial samples and refining the algorithms, the system will gradually enable automated channel management based on monitoring results.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Implementation Details
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Data Structure
&lt;/h3&gt;

&lt;p&gt;The data is stored in Redis with a design inspired by time-series databases like InfluxDB:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;InfluxDB&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;tags&lt;/td&gt;
&lt;td&gt;set to record monitoring dimensions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;time&lt;/td&gt;
&lt;td&gt;zset to store timestamps (in seconds)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fields&lt;/td&gt;
&lt;td&gt;hash to store specific values&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tags (Labels):&lt;/strong&gt; Monitored dimensions are stored using Redis sets (&lt;code&gt;SET&lt;/code&gt;), leveraging its deduplication feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timestamps:&lt;/strong&gt; Data points are stored using Redis sorted sets (&lt;code&gt;ZSET&lt;/code&gt;) to allow time-based lookups and ordering. Each point represents one second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fields (Metrics):&lt;/strong&gt; Specific monitoring data is stored in Redis hashes (&lt;code&gt;HASH&lt;/code&gt;). Each key-value pair represents:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key:&lt;/strong&gt; Result type (e.g., success or failure).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Value:&lt;/strong&gt; Count of occurrences within one second, including specific failure reasons.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example Redis Data Structure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SET: Tags -&amp;gt; Stores monitored dimensions.
ZSET: Timestamps -&amp;gt; Stores event times.
HASH: Metrics -&amp;gt; Stores success/failure counts and failure reasons.

### Redis Data Structure

1. **Set**
   - Stores the monitored dimensions, specific to the merchant ID.
   - **Key**: `routeAlarm:alarmitems`  
   - **Values**:  
     - `WeChat-Payment-100000111`  
     - `WeChat-Payment-100000112`  
     - `WeChat-Payment-100000113`  
     - ...

2. **ZSet**
   - Stores timestamps (in seconds) for requests from a specific merchant ID. Data for the same second will overwrite previous entries.
   - **Key**: `routeAlarm:alarmitem:timeStore:WeChat-Payment-100000111`  
   - **Scores and Values**:  
     - `score: 1657164225`, `value: 1657164225`  
     - `score: 1657164226`, `value: 1657164226`  
     - `score: 1657164227`, `value: 1657164227`  
     - ...

3. **Hash**
   - Stores the aggregated request results within 1 second for a specific merchant ID.
   - **Key**: `routeAlarm:alarmitem:fieldStore:WeChat-Payment-100000111:1657164225`  
   - **Fields and Values**:  
     - `key: success`, `value: 10` (count)  
     - `key: fail`, `value: 5`  
     - `key: balance_not_enough`, `value: 3`  
     - `key: third_error`, `value: 2`  
     - ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.2 Core Algorithm
&lt;/h3&gt;

&lt;p&gt;To avoid missing short spikes between monitoring intervals and ensure accurate reporting, the algorithm combines &lt;strong&gt;local counting&lt;/strong&gt; with a &lt;strong&gt;global sliding window&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per-Second Tracking:&lt;/strong&gt; Records the number of successes and failures for each second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sliding Window Calculation:&lt;/strong&gt; Computes success and failure counts across the entire window duration, ultimately determining the failure rate for each channel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Window Duration:&lt;/strong&gt; 1 minute.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring Frequency:&lt;/strong&gt; Every 10 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqrzagduma0u3jo1ex3x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqrzagduma0u3jo1ex3x.png" alt="Image description" width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Factors Affecting Accuracy:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring Frequency:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;Low frequency results in insufficient samples, reducing accuracy.&lt;/li&gt;
&lt;li&gt;High frequency may miss short-term spikes, causing underreporting.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Window Size:&lt;/strong&gt; Must balance sample size and real-time accuracy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The frequency and window size are determined based on metrics like daily transaction volume, hourly order frequency, and submission rates for each channel.&lt;/p&gt;




&lt;h3&gt;
  
  
  5.3 Handling Low Traffic
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Challenges with Low Traffic:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Channel Dimension:&lt;/strong&gt; Handling channels with low daily transaction volumes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time Dimension:&lt;/strong&gt; Managing off-peak periods with sparse transactions.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Solution:
&lt;/h4&gt;

&lt;p&gt;For channels with low traffic or off-peak times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there is only one transaction in the monitoring window and it fails, the window size is incrementally expanded:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initial Window:&lt;/strong&gt; 1 minute.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expanded Window:&lt;/strong&gt; Doubles (e.g., 2 minutes, 4 minutes) up to 10x.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;If the failure rate exceeds the threshold even after expansion, an alert is triggered, as such cases are treated as critical anomalies.&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  6. Outcomes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ensured accuracy of monitoring and alerting, minimizing missed anomalies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqujjwm9tjnp2ppn13eba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqujjwm9tjnp2ppn13eba.png" alt="Image description" width="528" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Merge duplicate alarm entries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpfhemg5vhrfdhhokztr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpfhemg5vhrfdhhokztr.png" alt="Image description" width="537" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Channel Anomaly Recovery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz7ymqwk3bdm2sv1xx3kv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz7ymqwk3bdm2sv1xx3kv.png" alt="Image description" width="523" height="207"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Future Plans
&lt;/h3&gt;

&lt;p&gt;To further enhance the automated monitoring system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Continuously optimize monitoring algorithms to achieve alert accuracy of 99% or higher.&lt;/li&gt;
&lt;li&gt;Integrate with the monitoring system to enable automatic channel deactivation upon fault detection.&lt;/li&gt;
&lt;li&gt;Implement automatic fault recovery detection and enable automated channel reactivation.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>systemdesign</category>
      <category>payment</category>
      <category>eventdriven</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>High Performance Notification System Practices</title>
      <dc:creator>Leo Dev Blog</dc:creator>
      <pubDate>Thu, 21 Nov 2024 04:20:53 +0000</pubDate>
      <link>https://dev.to/junjie_qin_512245a2eac9a4/high-performance-notification-system-practices-1kfp</link>
      <guid>https://dev.to/junjie_qin_512245a2eac9a4/high-performance-notification-system-practices-1kfp</guid>
      <description>&lt;h1&gt;
  
  
  Building a High-Performance Notification System
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Service Segmentation
&lt;/h2&gt;

&lt;h2&gt;
  
  
  2. System Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Initial Message Sending
&lt;/h3&gt;

&lt;h3&gt;
  
  
  2.2 Retry Message Sending
&lt;/h3&gt;

&lt;h2&gt;
  
  
  3. Ensuring Stability
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Handling Traffic Surges
&lt;/h3&gt;

&lt;h3&gt;
  
  
  3.2 Resource Isolation for Faulty Services
&lt;/h3&gt;

&lt;h3&gt;
  
  
  3.3 Protection of Third-Party Services
&lt;/h3&gt;

&lt;h3&gt;
  
  
  3.4 Middleware Fault Tolerance
&lt;/h3&gt;

&lt;h3&gt;
  
  
  3.5 Comprehensive Monitoring System
&lt;/h3&gt;

&lt;h3&gt;
  
  
  3.6 Active-Active Deployment and Elastic Scaling
&lt;/h3&gt;

&lt;h2&gt;
  
  
  4. Conclusion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Feedback on Results
&lt;/h3&gt;

&lt;h3&gt;
  
  
  4.2 Final Thoughts
&lt;/h3&gt;




&lt;p&gt;In any company, a notification system is an indispensable component. Each team may develop its own notification modules, but as the company grows, problems like maintenance complexity, issue debugging, and high development costs begin to emerge. For example, in our enterprise WeChat notification system, due to variations in message templates, a single project may use three different components—not even counting other notification functionalities.&lt;/p&gt;

&lt;p&gt;Given this context, there is an urgent need to develop a universal notification system. The key challenge lies in efficiently handling a large volume of message requests while ensuring system stability. This article explores how to build a high-performance notification system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configuration Layer&lt;/strong&gt;: This layer consists of a backend management system for configuring sending options, including request methods, URLs, expected responses, channel binding and selection, retry policies, and result queries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Interface Layer&lt;/strong&gt;: Provides external services, supporting both RPC and MQ. Additional protocols like HTTP can be added later as needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Core Service Layer&lt;/strong&gt;: The business logic layer manages initial and retry message sending, message channel routing, and service invocation encapsulation. This design isolates normal and abnormal service execution to prevent faulty services from affecting normal operations. For instance, if a particular message channel has a high latency, it could monopolize resources, impacting normal service requests. Executors are selected via routing strategies, including both configured routing policies and dynamic fault discovery.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Common Component Layer&lt;/strong&gt;: Encapsulates reusable components for broader use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Storage Layer&lt;/strong&gt;: Includes a caching layer for storing sending strategies, retry policies, and other transient data, as well as a persistence layer (ES and MySQL). MySQL stores message records and configurations, while ES is used for storing message records for user queries.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  2. System Design
&lt;/h1&gt;

&lt;h2&gt;
  
  
  2.1 Initial Message Sending
&lt;/h2&gt;

&lt;p&gt;When handling message-sending requests, two common approaches are RPC service requests and MQ message consumption. Each has its pros and cons. RPC ensures no message loss, while MQ supports asynchronous decoupling and load balancing.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1.1 Idempotency Handling
&lt;/h3&gt;

&lt;p&gt;To prevent processing duplicate message content, idempotency designs are implemented. Common approaches include locking followed by querying or using unique database keys. However, querying the database can become slow with high message volumes. Since duplicate messages usually occur within short intervals, Redis is a practical solution. By checking for duplicate Redis keys and verifying message content, idempotency can be achieved. Note: identical Redis keys with different message content may be allowed, depending on business needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1.2 Faulty Service Dynamic Detector
&lt;/h3&gt;

&lt;p&gt;Routing strategies include both configured routes and dynamic service fault-detection routing. The latter relies on a dynamic service detector to identify faulty channels and reroute execution via a fault-notification executor.&lt;/p&gt;

&lt;p&gt;This functionality uses Sentinel APIs within JVM nodes to track total and failed requests within a time window. If thresholds are exceeded, the service is flagged as faulty. Key methods include &lt;code&gt;loadExecuteHandlerRules&lt;/code&gt; (setting flow control rules, dynamically adjustable via Apollo/Nacos) and &lt;code&gt;judge&lt;/code&gt; (intercepting failed requests to mark services as faulty).&lt;/p&gt;

&lt;p&gt;Faulty services are not permanently flagged. An automatic recovery mechanism includes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Silent Period&lt;/strong&gt;: Requests during this time are handled by the fault executor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Half-Open Period&lt;/strong&gt;: If sufficient successful requests occur, the service is restored to normal.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2.1.3 Sentinel Sliding Window Implementation (Circular Array)
&lt;/h3&gt;

&lt;p&gt;Sliding windows are implemented using a circular array. The array size and indices are calculated based on the time window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
For a 1-second window with two sub-windows (500ms each):  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Window IDs: 0, 1
&lt;/li&gt;
&lt;li&gt;Time ranges: 0–500ms (ID 0), 500–1000ms (ID 1)
&lt;/li&gt;
&lt;li&gt;At 700ms, &lt;code&gt;window ID = (700 / 500) % 2 = 0&lt;/code&gt; and &lt;code&gt;windowStart = 700 - (700 % 500) = 200&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;At 1200ms, &lt;code&gt;window ID = (1200 / 500) % 2 = 0&lt;/code&gt;, requiring reset of ID 0 to reflect the new start time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.1.4 Dynamic Thread Pool Adjustment
&lt;/h3&gt;

&lt;p&gt;After message processing, a thread pool is used for asynchronous sending. Separate pools exist for normal and faulty services, configured based on task type and CPU cores, with dynamic adjustments informed by performance testing.&lt;/p&gt;

&lt;p&gt;A dynamically adjustable thread pool design leverages tools like Apollo or Nacos to modify parameters. Thread queue lengths remain fixed unless a custom queue is implemented. Instead, an unbounded pool is defined with matching core and max threads, using a discard policy. Overloading the pool triggers task persistence in MQ for retries, ensuring no memory overflow or message loss.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.2 Retrying Message Sending
&lt;/h2&gt;

&lt;p&gt;Messages failing due to bottlenecks or errors are retried via distributed task scheduling frameworks. Techniques like sharding and broadcasting optimize retry efficiency. Duplicate message control is achieved using locks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retry Mechanism:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Check if the handler’s resources are sufficient. If not, tasks wait in a queue.&lt;/li&gt;
&lt;li&gt;Lock control prevents duplicate processing across nodes.&lt;/li&gt;
&lt;li&gt;Task volume is based on handler settings.&lt;/li&gt;
&lt;li&gt;Retrieved tasks are sent to MQ, then processed via thread pools.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2.2.1 ES and MySQL Data Synchronization
&lt;/h3&gt;

&lt;p&gt;For large datasets, Elasticsearch (ES) is used for queries. Data consistency between ES and the database must be maintained.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Synchronization Flow&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update ES first, then change the database state to "updated."&lt;/li&gt;
&lt;li&gt;If synchronization isn't complete, reset the state to "init."&lt;/li&gt;
&lt;li&gt;Synchronization includes the database &lt;code&gt;update_time&lt;/code&gt; to ensure updates only occur for the latest data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;ES Index Management&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monthly rolling indices are created.
&lt;/li&gt;
&lt;li&gt;New indices are tagged as "hot," storing new data on high-performance nodes.
&lt;/li&gt;
&lt;li&gt;A scheduled task marks previous indices as "cold," moving them to lower-performance nodes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Stability Assurance
&lt;/h3&gt;

&lt;p&gt;The designs outlined above focus on high performance, but stability must also be considered. Below are several aspects of stability assurance.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.1 Sudden Traffic Spikes
&lt;/h4&gt;

&lt;p&gt;A two-layer degradation approach is implemented to handle sudden traffic spikes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gradual Traffic Increase&lt;/strong&gt;: When traffic grows steadily, and the thread pool becomes busy, &lt;strong&gt;MQ&lt;/strong&gt; is used for traffic shaping. Data is asynchronously persisted, and subsequent tasks are scheduled with a 0s delay for processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rapid Traffic Surge&lt;/strong&gt;: In the case of abrupt spikes, &lt;strong&gt;Sentinel&lt;/strong&gt; directly routes traffic to MQ for shaping and persistence without additional checks. Subsequent processing is delayed until resources become available.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3.2 Resource Isolation for Problematic Services
&lt;/h4&gt;

&lt;p&gt;Why isolate problematic services? Without isolation, problematic services share thread pool resources with normal services. If problematic services experience long processing times, thread releases are delayed, preventing timely processing of normal service requests. Resource isolation creates a separation to ensure problematic services do not impact normal operations.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.3 Protection of Third-Party Services
&lt;/h4&gt;

&lt;p&gt;Third-party services often implement rate-limiting and degradation to prevent overload. For those that lack such mechanisms, the following should be considered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid overwhelming third-party services due to high request volume.&lt;/li&gt;
&lt;li&gt;Ensure our services are resilient to third-party service failures by using &lt;strong&gt;circuit breakers&lt;/strong&gt; and &lt;strong&gt;graceful degradation&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3.4 Middleware Fault Tolerance
&lt;/h4&gt;

&lt;p&gt;Fault tolerance for middleware is essential. For example, during a scaling operation or upgrade, MQ might experience a few seconds of downtime. The system design must account for such transient failures to ensure service continuity.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.5 Comprehensive Monitoring System
&lt;/h4&gt;

&lt;p&gt;A robust monitoring system should be established to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Detect and mitigate issues before they escalate.&lt;/li&gt;
&lt;li&gt;Provide rapid incident resolution.&lt;/li&gt;
&lt;li&gt;Offer actionable insights for post-incident analysis and optimization.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  3.6 Active-Active Deployment and Elastic Scaling
&lt;/h4&gt;

&lt;p&gt;Operationally, &lt;strong&gt;active-active deployment&lt;/strong&gt; across multiple data centers ensures service availability. Elastic scaling, based on comprehensive service metrics, accommodates traffic variations while optimizing costs.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Conclusion
&lt;/h3&gt;

&lt;p&gt;System design should address service architecture, functionality, and stability assurance comprehensively. Achieving scalability, fault tolerance, and adaptability to dynamic scenarios is an ongoing challenge. There is no universal "silver bullet"; technical designs must be tailored to specific business needs through thoughtful planning and iteration.&lt;/p&gt;

</description>
      <category>design</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
