Skip to content

Commit

Permalink
Merge pull request #1 from allegro/feature/metrics
Browse files Browse the repository at this point in the history
Allow to collect metrics from CosmosAutoScaler
  • Loading branch information
starkpl authored Apr 19, 2022
2 parents b484f3c + ff8edb9 commit 1249600
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 21 deletions.
5 changes: 4 additions & 1 deletion samples/Allegro.CosmosDb.Demo/Allegro.CosmosDb.Demo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Asyncify" Version="0.9.7" />
<PackageReference Include="Asyncify" Version="0.9.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Meziantou.Analyzer" Version="1.0.676">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,28 @@
<PropertyGroup>
<PackageId>Allegro.CosmosDb.BatchUtilities</PackageId>
<PackageDescription>Utilities for performing batch operations in Azure CosmosDb, such as rate limiting and autoscaling.</PackageDescription>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
</PropertyGroup>

<Import Project="..\..\Package.Build.props"/>
<Import Project="..\..\Package.Build.props" />

<ItemGroup>
<PackageReference Include="AsyncFixer" Version="1.5.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Asyncify" Version="0.9.7"/>
<PackageReference Include="Asyncify" Version="0.9.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Meziantou.Analyzer" Version="1.0.676">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.22.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0"/>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0"/>
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.22.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.0.64">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
using Allegro.CosmosDb.BatchUtilities.Configuration;
using Allegro.CosmosDb.BatchUtilities.Events;
using Microsoft.Extensions.Logging;

#pragma warning disable VSTHRD110
Expand All @@ -18,13 +19,16 @@ public class CosmosAutoScaler : ICosmosAutoScaler
private readonly ICosmosScalableObject _scalableObject;
private readonly IRateLimiterWithVariableRate _ruLimiter;
private readonly CosmosBatchUtilitiesConfiguration _configuration;

private readonly Timer _timer = null!; // just keeping reference to prevent GC collection

private bool _scaledUp;

private DateTimeOffset _lastBatchReported = DateTimeOffset.MinValue;

/// <summary>
/// Emitted when periodic auto scaler metrics are calculated (every minute).
/// </summary>
public event CosmosAutoScalerMetricsCalculatedEventHandler? CosmosAutoScalerMetricsCalculated;

public CosmosAutoScaler(
ILogger<CosmosAutoScaler> logger,
ICosmosScalableObject scalableObject,
Expand Down Expand Up @@ -95,6 +99,7 @@ private void TimerCallback(object? state)
}

DownScaler();
PublishEvent();
}

private void DownScaler()
Expand Down Expand Up @@ -190,5 +195,24 @@ private async Task<bool> CheckIsCosmosScaledUp()
_ => false
};
}

private void PublishEvent()
{
if (_configuration.AutoScaler?.Enabled != true)
{
return;
}

CosmosAutoScalerMetricsCalculated?.Invoke(this, new CosmosAutoScalerMetricsCalculatedEventArgs(
this,
_scalableObject.DatabaseName,
_scalableObject.ContainerName,
_ruLimiter.MaxRate,
_ruLimiter.AvgRate,
_scaledUp
? _configuration.AutoScaler.ProcessingMaxThroughput
: _configuration.AutoScaler.IdleMaxThroughput,
_configuration.AutoScaler.ProvisioningMode));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Allegro.CosmosDb.BatchUtilities.Configuration;
using Allegro.CosmosDb.BatchUtilities.Events;
using Microsoft.Azure.Cosmos;
using Microsoft.Extensions.Logging;

Expand All @@ -25,18 +26,40 @@ public CosmosAutoScalerFactory(
CosmosClient cosmosClient,
ILoggerFactory loggerFactory,
params BatchUtilitiesRegistration[] batchUtilitiesRegistrations)
: this(
cosmosClient,
loggerFactory,
metricsCalculatedEventHandlers: Array.Empty<CosmosAutoScalerMetricsCalculatedEventHandler>(),
batchUtilitiesRegistrations)
{
}

public CosmosAutoScalerFactory(
CosmosClient cosmosClient,
ILoggerFactory loggerFactory,
IEnumerable<CosmosAutoScalerMetricsCalculatedEventHandler> metricsCalculatedEventHandlers,
params BatchUtilitiesRegistration[] batchUtilitiesRegistrations)
{
_autoScalers = batchUtilitiesRegistrations.ToDictionary(
x => FormatKey(x.DatabaseName, x.ContainerName),
x => new CosmosAutoScaler(
loggerFactory.CreateLogger<CosmosAutoScaler>(),
GetScalableObject(cosmosClient, x),
x.RuLimiter,
new CosmosBatchUtilitiesConfiguration
x =>
{
var autoScaler = new CosmosAutoScaler(
loggerFactory.CreateLogger<CosmosAutoScaler>(),
GetScalableObject(cosmosClient, x),
x.RuLimiter,
new CosmosBatchUtilitiesConfiguration
{
MaxRu = x.RuLimiter.MaxRate, AutoScaler = x.CosmosAutoScalerConfiguration
});

foreach (var eventHandler in metricsCalculatedEventHandlers)
{
MaxRu = x.RuLimiter.MaxRate,
AutoScaler = x.CosmosAutoScalerConfiguration
}));
autoScaler.CosmosAutoScalerMetricsCalculated += eventHandler;
}

return autoScaler;
});
}

public ICosmosAutoScaler ForContainer(string databaseName, string containerName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ namespace Allegro.CosmosDb.BatchUtilities
/// </summary>
public interface ICosmosScalableObject
{
string? ContainerName { get; }
string? DatabaseName { get; }

Task Scale(int targetThroughput, CosmosProvisioningMode provisioningMode);
Task<ThroughputResponse> GetCurrentThroughput();
}
Expand All @@ -29,6 +32,9 @@ public CosmosScalableObjectWrapper(Container container)
_container = container;
}

public string? ContainerName => _container?.Id;
public string? DatabaseName => _database?.Id ?? _container?.Database?.Id;

public Task Scale(int targetThroughput, CosmosProvisioningMode provisioningMode)
{
var throughputProperties = provisioningMode switch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ public AvgRateCalculatedEventArgs(
double avgRate,
TimeSpan period)
{
AvgRage = avgRate;
AvgRate = avgRate;
Period = period;
}

public double AvgRage { get; }
public double AvgRate { get; }
public TimeSpan Period { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using Allegro.CosmosDb.BatchUtilities.Configuration;

namespace Allegro.CosmosDb.BatchUtilities.Events
{
public delegate void CosmosAutoScalerMetricsCalculatedEventHandler(object sender, CosmosAutoScalerMetricsCalculatedEventArgs e);

public class CosmosAutoScalerMetricsCalculatedEventArgs : EventArgs
{
public CosmosAutoScalerMetricsCalculatedEventArgs(
CosmosAutoScaler cosmosAutoScaler,
string? databaseName,
string? containerName,
double limiterMaxRate,
double limiterAvgRate,
double maxThroughput,
CosmosProvisioningMode provisioningMode)
{
CosmosAutoScaler = cosmosAutoScaler;
DatabaseName = databaseName;
ContainerName = containerName;
LimiterMaxRate = limiterMaxRate;
LimiterAvgRate = limiterAvgRate;
MaxThroughput = maxThroughput;
ProvisioningMode = provisioningMode;
}

/// <summary>
/// <see cref="CosmosAutoScaler"/> that emitted the event.
/// </summary>
public CosmosAutoScaler CosmosAutoScaler { get; }

/// <summary>
/// Name of the database that is being auto scaled.
/// </summary>
public string? DatabaseName { get; }

/// <summary>
/// Name of the container that is being auto scaled.
/// </summary>
public string? ContainerName { get; }

/// <summary>
/// Max RU/s currently set for this <see cref="CosmosAutoScaler"/>.
/// </summary>
public double LimiterMaxRate { get; }

/// <summary>
/// Avg RU/s currently calculated for this <see cref="CosmosAutoScaler"/>.
/// </summary>
public double LimiterAvgRate { get; }

/// <summary>
/// Max RU/s configured for this <see cref="CosmosAutoScaler"/>.
/// </summary>
public double MaxThroughput { get; }

/// <summary>
/// Cosmos provisioning mode configured for this <see cref="CosmosAutoScaler"/>.
/// </summary>
public CosmosProvisioningMode ProvisioningMode { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Allegro.CosmosDb.BatchUtilities.Configuration;
using Allegro.CosmosDb.BatchUtilities.Events;
using Microsoft.Azure.Cosmos;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Extensions.Configuration;
Expand Down Expand Up @@ -100,9 +101,11 @@ public static IServiceCollection AddCosmosBatchUtilities(
{
var cosmosClient = sp.GetRequiredService<CosmosClient>();
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
var cosmosMetricsEventHandlers = sp.GetServices<CosmosAutoScalerMetricsCalculatedEventHandler>();
return new CosmosAutoScalerFactory(
cosmosClient,
loggerFactory,
cosmosMetricsEventHandlers,
autoScalerRegistrations);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,19 @@ public class RateLimiter : IRateLimiterWithVariableRate
public double MaxRate { get; private set; }
public TimeSpan RateInterval { get; }

/// <summary>
/// Emitted when <see cref="MaxRate"/> is exceeded.
/// </summary>
public event MaxRateExceededEventHandler? MaxRateExceeded;

/// <summary>
/// Emitted when <see cref="MaxRate"/> is changed.
/// </summary>
public event MaxRateChangedEventHandler? MaxRateChanged;

/// <summary>
/// Emitted when <see cref="AvgRate"/> is calculated.
/// </summary>
public event AvgRateCalculatedEventHandler? AvgRateCalculated;

public RateLimiter(double maxRate, TimeSpan rateInterval)
Expand Down
6 changes: 6 additions & 0 deletions src/Allegro.CosmosDb.BatchUtilities/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.2] - 2022-04-13

### Changed

* Add `CosmosAutoScalerMetricsCalculated` event to `CosmosAutoScaler` to enable metrics collection

## [1.0.1] - 2022-03-04

### Changed
Expand Down
15 changes: 15 additions & 0 deletions src/Allegro.CosmosDb.BatchUtilities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,18 @@ public class SampleBatchCommandHandler
}
}
```

### Collect auto scaler metrics

The Cosmos Auto Scaler utility periodically calculates some metrics, that can be collected using `CosmosAutoScalerMetricsCalculatedEventHandler`. Just register your handler with the DI container:

```c#
services.AddSingleton(
new CosmosAutoScalerMetricsCalculatedEventHandler(
(_, e) =>
{
Console.WriteLine($"[{e.DatabaseName}/{e.ContainerName}] LimiterMaxRate: {e.LimiterMaxRate}");
Console.WriteLine($"[{e.DatabaseName}/{e.ContainerName}] LimiterAvgRate: {e.LimiterAvgRate}");
Console.WriteLine($"[{e.DatabaseName}/{e.ContainerName}] MaxThroughput: {e.MaxThroughput}");
}));
```
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Asyncify" Version="0.9.7"/>
<PackageReference Include="Asyncify" Version="0.9.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Meziantou.Analyzer" Version="1.0.676">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down

0 comments on commit 1249600

Please sign in to comment.