Akshay Sura - Partner
12 Nov 2018
This past weekend I was playing with the Azure IoT hub and decided to load test it to see how much throughput can be achieved.





On this install, I ran 6 tests of 500 clients with 200 messages each and was able to get 107 Messages per second through put. I then decided to test it out by increasing the Device to Cloud partitions to see if it makes any difference. I added a new hub which has 32 partitions.


I ran a few more tests with 500 devices with 200 messages each and got about 109 Messages per second throughput. I decided to reduce the number of messages being transmitted to see if we get a better throughput and indeed we did. I tested with 500 devices with 20 messages each and I was able to achieve 294 Messages per second.
Depending on what you are trying to do, you might find a suitable scaling option. The results I got satisfied my need for the project I am working on.
// Copyright (c) Microsoft. All rights reserved.// Licensed under the MIT license. See LICENSE file in the project root for full license information. using System ;using System . Collections . Generic ;using System . Linq ;using System . Text ;using System . Threading . Tasks ;using Microsoft . Azure . Devices . Client ;using System . Threading ;using Microsoft . Azure . Devices ; namespace Microsoft . Azure . Devices . Client . Samples{class Program{// needed when creating devices// Example "HostName=myhub.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=0U1REMOVEDvrfUDo=";static string iotHubConnectionString = "Your Connection String" ;static string IoTHub = iotHubConnectionString . Split ( ';' )[ 0 ]. Split ( '=' )[ 1 ];static string IoTDevicePrefix = "loadTest" ;static string commonKey = "Your Key" ;static int deviceCount = 500 ; // how many devices we will create and clients we will launchstatic int maxMessages = 20 ; // once this count of messages are sent, the client shuts downstatic int messageDelaySeconds = 0 ; // how long between each message, honoring IoT Hub Quotasstatic int runningDevices = 0 ;static bool allDevicesDeleted = false ;static int totalMessageSent = 0 ;static int allClientStarted = 0 ; static void Main ( string [] args ){// if the devices already exist, you can comment out this linecreateDevices ( deviceCount );Console . ReadKey ();DateTime startTime = DateTime . Now ;for ( int deviceNumber = 1 ; deviceNumber <= deviceCount ; deviceNumber ++){startClient ( IoTHub , IoTDevicePrefix , deviceNumber , commonKey , maxMessages , messageDelaySeconds );} // wait for the first few to startThread . Sleep ( 1000 * 30 ); while ( runningDevices != 0 ){// if we still have devices running, waitThread . Sleep ( 3000 );}DateTime endTime = DateTime . Now ;Console . WriteLine ( "Total Client: " + deviceCount );Console . WriteLine ( "Total Messages Sent: " + deviceCount * maxMessages );Console . WriteLine ( "Total Execution Time: " + ( endTime - startTime ). TotalSeconds + " seconds" );Console . WriteLine ( "Messages Per Second: " + totalMessageSent / ( endTime - startTime ). TotalSeconds );Thread . Sleep ( 7000 );deleteDevices ( deviceCount );Thread . Sleep ( 1000 * 30 );while ( allDevicesDeleted != true ){// if we still have devices being deleted, waitThread . Sleep ( 1000 );}Console . WriteLine ( "Total Client: " + deviceCount );Console . WriteLine ( "Total Messages Sent: " + deviceCount * maxMessages );Console . WriteLine ( "Total Execution Time: " + ( endTime - startTime ). TotalSeconds + " seconds" );Console . WriteLine ( "Messages Per Second: " + totalMessageSent / ( endTime - startTime ). TotalSeconds ); Console . WriteLine ( "Press any key to end" );Console . ReadKey ();} static async Task startClient ( string IoTHub , string IoTDevicePrefix , int deviceNumber , string commonKey , int maxMessages , int messageDelaySeconds ){allClientStarted ++;runningDevices ++;string connectionString = "HostName=" + IoTHub + ";DeviceId=" + IoTDevicePrefix + deviceNumber + ";SharedAccessKey=" + commonKey ;DeviceClient device = DeviceClient . CreateFromConnectionString ( connectionString , Microsoft . Azure . Devices . Client . TransportType . Mqtt );await device . OpenAsync ();Random rnd = new Random ();int mycounter = 1 ;Console . WriteLine ( "Device " + IoTDevicePrefix + deviceNumber + " started" ); while ( mycounter <= maxMessages ){Thread . Sleep (( messageDelaySeconds * 1000 ) + rnd . Next ( 1 , 100 ));string message = "{ \'deviceId\': \'" + string . Concat ( IoTDevicePrefix , deviceNumber ) + "\',\'message\':\'Be My Friend!\', 'sequenceNumber': " + mycounter + ", \'submitTime\': \'" + DateTime . UtcNow + "\'}" ;Console . WriteLine ( message );Message IoTMessage = new Microsoft . Azure . Devices . Client . Message ( Encoding . UTF8 . GetBytes ( message ));await device . SendEventAsync ( IoTMessage );totalMessageSent ++;mycounter ++;}await device . CloseAsync ();Console . WriteLine ( "Device " + IoTDevicePrefix + deviceNumber + " ended" );runningDevices --;} static void createDevices ( int number ){for ( int i = 1 ; i <= number ; i ++){var registryManager = RegistryManager . CreateFromConnectionString ( iotHubConnectionString );Device mydevice = new Device ( IoTDevicePrefix + i . ToString ());mydevice . Authentication = new AuthenticationMechanism ();mydevice . Authentication . SymmetricKey . PrimaryKey = commonKey ;mydevice . Authentication . SymmetricKey . SecondaryKey = commonKey ;try{registryManager . AddDeviceAsync ( mydevice ). Wait ();Console . WriteLine ( "Adding device: " + IoTDevicePrefix + i . ToString ());}catch ( Exception er ){Console . WriteLine ( " Error adding device: " + IoTDevicePrefix + i . ToString () + " error: " + er . InnerException . Message );}} }static async void deleteDevices ( int number ){for ( int i = 1 ; i <= number ; i ++){var registryManager = RegistryManager . CreateFromConnectionString ( iotHubConnectionString ); try{Device mydevice = await registryManager . GetDeviceAsync ( IoTDevicePrefix + i . ToString ());registryManager . RemoveDeviceAsync ( mydevice ). Wait ();Console . WriteLine ( "Deleting device " + IoTDevicePrefix + i . ToString ());}catch ( Exception er ) { } }allDevicesDeleted = true ; }}}// Copyright (c) Microsoft. All rights reserved.// Licensed under the MIT license. See LICENSE file in the project root for full license information. // This application uses the Microsoft Azure Event Hubs Client for .NET// For samples see: https://github.com/Azure/azure-event-hubs/tree/master/samples/DotNet// For documenation see: https://docs.microsoft.com/azure/event-hubs/using System ;using Microsoft . Azure . EventHubs ;using System . Threading . Tasks ;using System . Threading ;using System . Text ;using System . Collections . Generic ;using Newtonsoft . Json ;using System . Linq ; namespace read_d2c_messages{class ReadDeviceToCloudMessages{private static int noOfMessages = 0 ;// az iot hub show --query properties.eventHubEndpoints.events.endpoint --name {your IoT Hub name}private readonly static string s_eventHubsCompatibleEndpoint = "Your End Point" ; // Event Hub-compatible name// az iot hub show --query properties.eventHubEndpoints.events.path --name {your IoT Hub name}private readonly static string s_eventHubsCompatiblePath = "bemyfriendiothub" ; // az iot hub policy show --name iothubowner --query primaryKey --hub-name {your IoT Hub name}private readonly static string s_iotHubSasKey = "Your Key" ;private readonly static string s_iotHubSasKeyName = "iothubowner" ;private static EventHubClient s_eventHubClient ; // Asynchronously create a PartitionReceiver for a partition and then start// reading any messages sent from the simulated client.private static async Task ReceiveMessagesFromDeviceAsync ( string partition , CancellationToken ct ){//messages.Clear();// Create the receiver using the default consumer group.// For the purposes of this sample, read only messages sent since// the time the receiver is created. Typically, you don't want to skip any messages.var eventHubReceiver = s_eventHubClient . CreateReceiver ( "$Default" , partition , EventPosition . FromEnqueuedTime ( DateTime . Now ));Console . WriteLine ( "Create receiver on partition: " + partition );while ( true ){if ( ct . IsCancellationRequested ) break ;//Console.WriteLine("Listening for messages on: " + partition);// Check for EventData - this methods times out if there is nothing to retrieve.var events = await eventHubReceiver . ReceiveAsync ( 100 ); // If there is data in the batch, process it.if ( events == null ) continue ; foreach ( EventData eventData in events ){string message = Encoding . UTF8 . GetString ( eventData . Body . Array );noOfMessages ++;Console . WriteLine ( "Message: {0} Messages Received:{1}" , message , noOfMessages . ToString ());}}} private static async Task Main ( string [] args ){noOfMessages = 0 ;Console . WriteLine ( "IoT Hub Quickstarts - Read device to cloud messages. Ctrl-C to exit.n" ); // Create an EventHubClient instance to connect to the// IoT Hub Event Hubs-compatible endpoint.var connectionString = new EventHubsConnectionStringBuilder ( new Uri ( s_eventHubsCompatibleEndpoint ), s_eventHubsCompatiblePath , s_iotHubSasKeyName , s_iotHubSasKey );s_eventHubClient = EventHubClient . CreateFromConnectionString ( connectionString . ToString ()); // Create a PartitionReciever for each partition on the hub.var runtimeInfo = await s_eventHubClient . GetRuntimeInformationAsync ();var d2cPartitions = runtimeInfo . PartitionIds ; CancellationTokenSource cts = new CancellationTokenSource (); Console . CancelKeyPress += ( s , e ) =>{Console . WriteLine ( "Number of Messages Received: {0}" , noOfMessages . ToString ());}; var tasks = new List < Task >();foreach ( string partition in d2cPartitions ){tasks . Add ( ReceiveMessagesFromDeviceAsync ( partition , cts . Token ));} // Wait for all the PartitionReceivers to finsih.Task . WaitAll ( tasks . ToArray ());}}}Useful Links:
If you have any questions or concerns, please get in touch with me. (@akshaysura13 on Twitter or on Slack).

Akshay is a nine-time Sitecore MVP and a two-time Kontent.ai. In addition to his work as a solution architect, Akshay is also one of the founders of SUGCON North America 2015, SUGCON India 2018 & 2019, Unofficial Sitecore Training, and Sitecore Slack.
Akshay founded and continues to run the Sitecore Hackathon. As one of the founding partners of Konabos Consulting, Akshay will continue to work with clients to lead projects and mentor their existing teams.