How to calculate events per second rate in Real-Time Analytics
This tutorial shows how to calculate the events-per-second (EPS) rate in Real-Time Analytics to monitor systems and alerts. Knowing the EPS helps detect spikes, bottlenecks and performance regressions immediately.
Prerequisites
- Streaming event source (e.g.: events sent to a service such as Azure Event Hubs or Kafka).
- Real-time storage/query compatible with KQL (e.g.: Azure Data Explorer / Kusto) or similar.
- Basic knowledge of KQL and time windows (sliding, tumbling).
Step 1: Choose the time window and aggregation type
Decide the granularity: 1s/5s/1m windows are common. For fast spike detection use short windows (1s-5s); for trends use 1m or longer. The main aggregation is the count of events per window and, optionally, a moving average to smooth noise.
Step 2: Write the base query to count events by window (KQL example)
This query counts events in 5-second windows using bin(), and computes the rate per second by dividing by the window duration. Replace EventTime and MyTable with the actual column/table name.
MyTable
| where EventTime >= ago(10m)
| summarize count_events = count() by bin(EventTime, 5s)
| extend eps = todouble(count_events) / 5.0
| order by EventTime asc
Step 3: Calculate a moving average to reduce noise
A simple moving average (rolling average) makes the visualization steadier. Here we use the series_fir or simple moving_avg with prev and next for Kusto; if not available, use a self-join or make-series. Example with make-series for regular windows and moving_avg.
MyTable
| where EventTime >= ago(10m)
| make-series count_events = count() on EventTime in range(now(-10m), now(), 5s)
| mv-expand EventTime to typeof(datetime), count_events to typeof(long)
| extend eps = todouble(count_events) / 5.0
| serialize
| extend eps_ma = moving_avg(eps, 6) // moving average of 6 points (~30s)
Step 4: Handle empty windows and normalize
It is common to have intervals with no events; ensure those points appear with zero value so they don't bias the average. In the example above, make-series guarantees zero points. If you use summarize+bin, add a continuous range and do a left-join.
// alternative using summarize+bin and zero fill
let times = range t from ago(10m) to now() step 5s;
let counts = MyTable
| where EventTime >= ago(10m)
| summarize c = count() by bin(EventTime, 5s);
times
| join kind=leftouter (counts) on $left.t == $right.EventTime
| extend count_events = coalesce(c, 0)
| extend eps = todouble(count_events) / 5.0
Step 5: Calculate thresholds and detect simple anomalies
Define static thresholds (e.g.: eps > 100) or dynamic ones using mean + k*stddev. Dynamic example with standard deviation to flag spikes.
// compute mean and stdev over the last 10m and flag spikes
let series = (
MyTable
| where EventTime >= ago(10m)
| make-series count_events = count() on EventTime in range(now(-10m), now(), 5s)
| mv-expand EventTime to typeof(datetime), count_events to typeof(long)
| extend eps = todouble(count_events) / 5.0
);
let stats = series | summarize mu = avg(eps), sigma = stdev(eps);
series
| extend mu = toscalar(stats.mu), sigma = toscalar(stats.sigma)
| extend is_spike = eps > mu + 3.0 * sigma
Verify the result
Create a dashboard/visual with two series: eps and eps_ma (moving average). Verify that points with is_spike=true match visible spikes. Also confirm that periods without events show eps=0. Test with synthetic data: inject events at high rate to see detected spikes.
Conclusion
Calculating the events-per-second (EPS) rate in Real-Time Analytics enables monitoring performance and triggering alerts. Next steps: integrate this query into an alerting pipeline (e.g.: alert rules that fire when is_spike=true) or correlate EPS with infrastructure metrics. Tip: experiment with the window duration and moving average size to balance sensitivity and noise.