This commit is contained in:
arramac 2016-08-12 13:32:42 -07:00
Родитель 6d4e53c6b0
Коммит b6ddd7645b
4 изменённых файлов: 48 добавлений и 149 удалений

Просмотреть файл

@ -12,13 +12,14 @@
<add key="DatabaseName" value="db"/>
<add key="CollectionName" value="data"/>
<add key="MetricCollectionName" value="metrics"/>
<add key="CollectionThroughput" value="50000"/>
<add key="CollectionThroughput" value="10100"/>
<add key="ShouldCleanupOnStart" value="false"/>
<add key="ShouldCleanupOnFinish" value="true"/>
<add key="DegreeOfParallelism" value="500"/>
<add key="NumberOfDocumentsToInsert" value="100000"/>
<add key="ShouldCleanupOnFinish" value="false"/>
<!-- determined by the tool -->
<add key="DegreeOfParallelism" value="-1"/>
<add key="NumberOfDocumentsToInsert" value="1000000"/>
<add key="CollectionPartitionKey" value="/partitionKey"/>
<add key="DocumentTemplateFile" value="Player.json"/>

Просмотреть файл

@ -11,7 +11,7 @@
<AssemblyName>DocumentDBBenchmark</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>b4fb0ea4</NuGetPackageImportStamp>
<NuGetPackageImportStamp>f78fc7b6</NuGetPackageImportStamp>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -34,8 +34,8 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Azure.Documents.Client, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Azure.DocumentDB.1.7.1\lib\net45\Microsoft.Azure.Documents.Client.dll</HintPath>
<Reference Include="Microsoft.Azure.Documents.Client, Version=1.9.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Azure.DocumentDB.1.9.2\lib\net45\Microsoft.Azure.Documents.Client.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
@ -72,12 +72,12 @@
<Folder Include="Properties\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="packages\Microsoft.Azure.DocumentDB.1.7.1\build\Microsoft.Azure.DocumentDB.targets" Condition="Exists('packages\Microsoft.Azure.DocumentDB.1.7.1\build\Microsoft.Azure.DocumentDB.targets')" />
<Import Project="packages\Microsoft.Azure.DocumentDB.1.9.2\build\Microsoft.Azure.DocumentDB.targets" Condition="Exists('packages\Microsoft.Azure.DocumentDB.1.9.2\build\Microsoft.Azure.DocumentDB.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\Microsoft.Azure.DocumentDB.1.7.1\build\Microsoft.Azure.DocumentDB.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Azure.DocumentDB.1.7.1\build\Microsoft.Azure.DocumentDB.targets'))" />
<Error Condition="!Exists('packages\Microsoft.Azure.DocumentDB.1.9.2\build\Microsoft.Azure.DocumentDB.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Azure.DocumentDB.1.9.2\build\Microsoft.Azure.DocumentDB.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

Просмотреть файл

@ -28,13 +28,21 @@
{
private static readonly string DatabaseName = ConfigurationManager.AppSettings["DatabaseName"];
private static readonly string DataCollectionName = ConfigurationManager.AppSettings["CollectionName"];
private static readonly string MetricCollectionName = ConfigurationManager.AppSettings["MetricCollectionName"];
private static readonly int CollectionThroughput = int.Parse(ConfigurationManager.AppSettings["CollectionThroughput"]);
private static readonly ConnectionPolicy ConnectionPolicy = new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp, RequestTimeout = new TimeSpan(1, 0, 0) };
private static readonly ConnectionPolicy ConnectionPolicy = new ConnectionPolicy
{
ConnectionMode = ConnectionMode.Direct,
ConnectionProtocol = Protocol.Tcp,
RequestTimeout = new TimeSpan(1, 0, 0),
MaxConnectionLimit = 1000,
RetryOptions = new RetryOptions
{
MaxRetryAttemptsOnThrottledRequests = 100,
MaxRetryWaitTimeInSeconds = 60
}
};
private static readonly int TaskCount = int.Parse(ConfigurationManager.AppSettings["DegreeOfParallelism"]);
private static readonly int DefaultConnectionLimit = int.Parse(ConfigurationManager.AppSettings["DegreeOfParallelism"]);
private static readonly string InstanceId = Dns.GetHostEntry("LocalHost").HostName + Process.GetCurrentProcess().Id;
private const int MinThreadPoolSize = 100;
@ -58,9 +66,6 @@
/// <param name="args">command line arguments.</param>
public static void Main(string[] args)
{
ServicePointManager.UseNagleAlgorithm = true;
ServicePointManager.Expect100Continue = true;
ServicePointManager.DefaultConnectionLimit = DefaultConnectionLimit;
ThreadPool.SetMinThreads(MinThreadPoolSize, MinThreadPoolSize);
string endpoint = ConfigurationManager.AppSettings["EndPointUrl"];
@ -71,7 +76,7 @@
Console.WriteLine("Endpoint: {0}", endpoint);
Console.WriteLine("Collection : {0}.{1} at {2} request units per second", DatabaseName, DataCollectionName, ConfigurationManager.AppSettings["CollectionThroughput"]);
Console.WriteLine("Document Template*: {0}", ConfigurationManager.AppSettings["DocumentTemplateFile"]);
Console.WriteLine("Degree of parallelism*: {0}", TaskCount);
Console.WriteLine("Degree of parallelism*: {0}", ConfigurationManager.AppSettings["DegreeOfParallelism"]);
Console.WriteLine("--------------------------------------------------------------------- ");
Console.WriteLine();
@ -112,7 +117,9 @@
/// <returns>a Task object.</returns>
private async Task RunAsync()
{
DocumentCollection dataCollection = GetCollectionIfExists(DatabaseName, DataCollectionName);
int currentCollectionThroughput = 0;
if (bool.Parse(ConfigurationManager.AppSettings["ShouldCleanupOnStart"]) || dataCollection == null)
{
@ -127,49 +134,39 @@
Console.WriteLine("Creating collection {0} with {1} RU/s", DataCollectionName, CollectionThroughput);
dataCollection = await this.CreatePartitionedCollectionAsync(DatabaseName, DataCollectionName);
currentCollectionThroughput = CollectionThroughput;
}
else
{
OfferV2 offer = (OfferV2)client.CreateOfferQuery().Where(o => o.ResourceLink == dataCollection.SelfLink).AsEnumerable().FirstOrDefault();
int throughput = offer.Content.OfferThroughput;
Console.WriteLine("Found collection {0} with {1} RU/s", DataCollectionName, CollectionThroughput);
currentCollectionThroughput = offer.Content.OfferThroughput;
Console.WriteLine("Found collection {0} with {1} RU/s", DataCollectionName, currentCollectionThroughput);
}
DocumentCollection metricCollection = GetCollectionIfExists(DatabaseName, MetricCollectionName);
int taskCount;
int degreeOfParallelism = int.Parse(ConfigurationManager.AppSettings["DegreeOfParallelism"]);
// Configure to expire metrics for old clients if not updated for longer than a minute
int defaultTimeToLive = 60;
if (metricCollection == null)
if (degreeOfParallelism == -1)
{
Console.WriteLine("Creating metric collection {0}", MetricCollectionName);
DocumentCollection metricCollectionDefinition = new DocumentCollection();
metricCollectionDefinition.Id = MetricCollectionName;
metricCollectionDefinition.DefaultTimeToLive = defaultTimeToLive;
metricCollection = await ExecuteWithRetries<ResourceResponse<DocumentCollection>>(
this.client,
() => client.CreateDocumentCollectionAsync(
UriFactory.CreateDatabaseUri(DatabaseName),
new DocumentCollection { Id = MetricCollectionName },
new RequestOptions { OfferThroughput = 5000 }),
true);
// set TaskCount = 10 for each 10k RUs
taskCount = currentCollectionThroughput / 1000;
}
else
{
metricCollection.DefaultTimeToLive = defaultTimeToLive;
await client.ReplaceDocumentCollectionAsync(metricCollection);
taskCount = degreeOfParallelism;
}
Console.WriteLine("Starting Inserts with {0} tasks", TaskCount);
Console.WriteLine("Starting Inserts with {0} tasks", taskCount);
string sampleDocument = File.ReadAllText(ConfigurationManager.AppSettings["DocumentTemplateFile"]);
pendingTaskCount = TaskCount;
pendingTaskCount = taskCount;
var tasks = new List<Task>();
tasks.Add(this.LogOutputStats());
long numberOfDocumentsToInsert = long.Parse(ConfigurationManager.AppSettings["NumberOfDocumentsToInsert"])/TaskCount;
for (var i = 0; i < TaskCount; i++)
long numberOfDocumentsToInsert = long.Parse(ConfigurationManager.AppSettings["NumberOfDocumentsToInsert"]) / taskCount;
for (var i = 0; i < taskCount; i++)
{
tasks.Add(this.InsertDocument(i, client, dataCollection, sampleDocument, numberOfDocumentsToInsert));
}
@ -179,10 +176,7 @@
if (bool.Parse(ConfigurationManager.AppSettings["ShouldCleanupOnFinish"]))
{
Console.WriteLine("Deleting Database {0}", DatabaseName);
await ExecuteWithRetries<ResourceResponse<Database>>(
this.client,
() => client.DeleteDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseName)),
true);
await client.DeleteDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseName));
}
}
@ -199,12 +193,10 @@
try
{
ResourceResponse<Document> response = await ExecuteWithRetries<ResourceResponse<Document>>(
client,
() => client.CreateDocumentAsync(
ResourceResponse<Document> response = await client.CreateDocumentAsync(
UriFactory.CreateDocumentCollectionUri(DatabaseName, DataCollectionName),
newDictionary,
new RequestOptions() { }));
new RequestOptions() { });
string partition = response.SessionToken.Split(':')[0];
requestUnitsConsumed[taskId] += response.RequestCharge;
@ -252,20 +244,6 @@
Math.Round(ruPerSecond),
Math.Round(ruPerMonth / (1000 * 1000 * 1000)));
Dictionary<string, object> latestStats = new Dictionary<string, object>();
latestStats["id"] = string.Format("latest{0}", InstanceId);
latestStats["type"] = "latest";
latestStats["totalDocumentsCreated"] = currentCount;
latestStats["documentsCreatedPerSecond"] = Math.Round(this.documentsInserted / seconds);
latestStats["requestUnitsPerSecond"] = Math.Round(ruPerSecond);
latestStats["requestUnitsPerMonth"] = Math.Round(ruPerSecond) * 86400 * 30;
latestStats["documentsCreatedInLastSecond"] = Math.Round((currentCount - lastCount) / (seconds - lastSeconds));
latestStats["requestUnitsInLastSecond"] = Math.Round((requestUnits - lastRequestUnits) / (seconds - lastSeconds));
latestStats["requestUnitsPerMonthBasedOnLastSecond"] =
Math.Round(((requestUnits - lastRequestUnits) / (seconds - lastSeconds)) * 86400 * 30);
await InsertMetricsToDocumentDB(latestStats);
lastCount = documentsInserted;
lastSeconds = seconds;
lastRequestUnits = requestUnits;
@ -286,22 +264,6 @@
Console.WriteLine("--------------------------------------------------------------------- ");
}
private async Task InsertMetricsToDocumentDB(Dictionary<string, object> latestStats)
{
try
{
await ExecuteWithRetries<ResourceResponse<Document>>(
client,
() => client.UpsertDocumentAsync(
UriFactory.CreateDocumentCollectionUri(DatabaseName, MetricCollectionName),
latestStats));
}
catch (Exception e)
{
Trace.TraceError("Insert metrics document failed with {0}", e);
}
}
/// <summary>
/// Create a partitioned collection.
/// </summary>
@ -317,16 +279,14 @@
// Show user cost of running this test
double estimatedCostPerMonth = 0.06 * CollectionThroughput;
double estimatedCostPerHour = estimatedCostPerMonth / (24 * 30);
Console.WriteLine("The collection will cost an estimated ${0} per hour (${1} per month)", estimatedCostPerHour, estimatedCostPerMonth);
Console.WriteLine("The collection will cost an estimated ${0} per hour (${1} per month)", Math.Round(estimatedCostPerHour, 2), Math.Round(estimatedCostPerMonth, 2));
Console.WriteLine("Press enter to continue ...");
Console.ReadLine();
return await ExecuteWithRetries<ResourceResponse<DocumentCollection>>(
this.client,
() => client.CreateDocumentCollectionAsync(
return await client.CreateDocumentCollectionAsync(
UriFactory.CreateDatabaseUri(databaseName),
collection,
new RequestOptions { OfferThroughput = CollectionThroughput }));
new RequestOptions { OfferThroughput = CollectionThroughput });
}
/// <summary>
@ -352,67 +312,5 @@
return client.CreateDocumentCollectionQuery(UriFactory.CreateDatabaseUri(databaseName))
.Where(c => c.Id == collectionName).AsEnumerable().FirstOrDefault();
}
/// <summary>
/// Execute the function with retries on throttle.
/// </summary>
/// <typeparam name="V">The type of return value from the execution.</typeparam>
/// <param name="client">The DocumentDB client instance.</param>
/// <param name="function">The function to execute.</param>
/// <returns>The response from the execution.</returns>
public static async Task<V> ExecuteWithRetries<V>(DocumentClient client, Func<Task<V>> function, bool shouldLogRetries = false)
{
TimeSpan sleepTime = TimeSpan.Zero;
int[] expectedStatusCodes = new int[] { 429, 400, 503 };
while (true)
{
try
{
return await function();
}
catch (System.Net.Http.HttpRequestException)
{
sleepTime = TimeSpan.FromSeconds(1);
}
catch (Exception e)
{
DocumentClientException de;
if (!TryExtractDocumentClientException(e, out de))
{
throw;
}
sleepTime = de.RetryAfter;
if (shouldLogRetries)
{
Console.WriteLine("Retrying after sleeping for {0}", sleepTime);
}
}
await Task.Delay(sleepTime);
}
}
private static bool TryExtractDocumentClientException(Exception e, out DocumentClientException de)
{
if (e is DocumentClientException)
{
de = (DocumentClientException)e;
return true;
}
if (e is AggregateException)
{
if (e.InnerException is DocumentClientException)
{
de = (DocumentClientException)e.InnerException;
return true;
}
}
de = null;
return false;
}
}
}

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Azure.DocumentDB" version="1.7.1" targetFramework="net451" />
<package id="Microsoft.Azure.DocumentDB" version="1.9.2" targetFramework="net451" />
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net451" />
</packages>