We are working one project which required high volume of message/command exchanged between device to device.
We are using Cloud Service Worker role for processing commands and send to relevant devices using Cloud to Device Direct Method.
The worker role configuration is A2V2-2 Core with 4 GB RAM.There is no problem with worker role capacity.The CPU and Memory all in control.
For less no of message/command processing its working fine(Eg 500 Messages).But when no of messages increase we are facing performance issue(Eg 1000 Messages).We are targeting <5 Sec latency.When we try to log in Worker Role VM and found that the no of TCP connections keep increasing and its causing slowness while sending message/commands to devices.
The following line of code which we are using to send messages using Direct Method.Looking better way to dispose Service client object after each direct method call.
var methodInvocation = new CloudToDeviceMethod(methodInfo.MethodName) { ResponseTimeout = TimeSpan.FromSeconds(methodInfo.ResponseTimeout) };
//set the payload
methodInvocation.SetPayloadJson(methodInfo.Payload);
//invokes direct method
var response = _serviceClient.InvokeDeviceMethodAsync(methodInfo.DeviceId, methodInvocation);
if (_serviceClient != null)
{
//closes the service client connection
_serviceClient.CloseAsync();
_serviceClient.Dispose();
}
At last we found the solution.The Azure Service Client object was not properly closed and disposed.We have closed and disposed Service Client object explicitly after successful direct method call.
//closes the service client connection
await _serviceClient.InvokeDeviceMethodAsync(methodInfo.DeviceId, methodInvocation);
_serviceClient.CloseAsync().Wait();
_serviceClient.Dispose();
Related
I'm using a .NET web app as a buffer between an IoT device and IoT Hub. The IoT device sends data to the web app which then routes that data to Azure IoT Hub. I'm using the Device Client to do this. It worked fine until the number of requests started growing as we went into production.
Here is the bit of code that sends data to IoT Hub.
public async Task SendDataToIoTHub(Message eventMessage, string deviceId, string deviceKey)
{
string connectionString = $"HostName=" + IoTHubHostname + ";DeviceId=" + deviceId + ";SharedAccessKey=" + deviceKey;
using (DeviceClient deviceClient = DeviceClient.CreateFromConnectionString(connectionString))
{
if (deviceClient == null)
{
return;
}
await deviceClient.SendEventAsync(eventMessage);
}
}
I have about 3k-4k requests every minute and the above code gets called for each request. It has really started being unreliable since the request rate hit this amount. There was a ' too many TCP connections' warning for a brief period of time which caused the entire application to start slowing down dramatically.
I'm wondering if this initialization of the device client is correct or if there is a better way to do it.
Thanks!
This could be due to reaching the maximum outbound TCP connections. The limits are:
1,920 connections per B1/S1/P1 instance
3,968 connections per B2/S2/P2 instance
8,064 connections per B3/S3/P3 instance
16,000 connections per I1/I2/I3 instance
Source (This post also shows how to view the number of TCP connections over time)
You're opening a new connection every time you create a new DeviceClient, so with those rates, you will hit some limits. You could scale up your instance, but maybe you should consider keeping a single DeviceClient per device (if you don't have thousands of devices).
There might be a reason for this "web app as a buffer" as you call it, and if you want to continue using it, you might consider using the REST API to send your device events instead. You don't need an AMQP connection if you're only going to send one event.
This question is not about Scaleout with SignalR and Azure Service Bus. I want to build a Service Bus listener (e.g. OnMessage) into my SignalR web socket app that then distributes the message accordingly to connected users. Messages will be posted from various separately running services into the centralized Service Bus and the UI/browser connected to the web socket servers should receive these.
Option 1: I can add an async Task into a hub method to subscribe to a Service Bus and filter by the connected user. The problem with this is it uses an extra thread from the thread pool and will do this for every socket connection the user has started. Our app can easily start 5-10 or more sockets for every tab open.
Option 2: I can add a single task to the SignalR Startup.Configuration method that then receives all messages and distributes them to the proper connected users. The problem I've encountered here is that I don't have access to the Clients object used for sending to the browser.
I feel like SignalR and Service Bus are a good complement to each other to enable near real-time communications but I can find very little to implement a scenario like this. And I feel like this should be a common enough scenario. Perhaps I'm missing some obvious design patterns that would be a better solution.
I was able to figure this out. In the SignalR Startup.Configuration method I added a method to start the listener and in that method I called GlobalHost.ConnectionManager.GetHubContext. Currently this doesn't send to individual users but I'll add a connection manager of some sort to handle that.
public void startServiceBusListener()
{
// setup subcsription
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.SubscriptionExists("myTopic", Environment.MachineName))
namespaceManager.CreateSubscription("myTopic", Environment.MachineName);
SubscriptionClient busClient = SubscriptionClient.CreateFromConnectionString(connectionString, "myTopic", Environment.MachineName);
// Configure the callback options.
OnMessageOptions options = new OnMessageOptions();
options.AutoComplete = false;
options.AutoRenewTimeout = TimeSpan.FromMinutes(1);
receiveTask = Task.Run(() =>
{
// handle new messages
busClient.OnMessage((message) =>
{
try
{
Notification note = message.GetBody<Notification>();
string notification = JsonConvert.SerializeObject(note);
GlobalHost.ConnectionManager.GetHubContext<DispatchHub>().Clients.All.notify(notification);
// Remove message from subscription.
message.Complete();
}
catch (Exception)
{
// Indicates a problem, unlock message in subscription.
message.Abandon();
}
}, options);
}, cts.Token);
}
I am building a c#/wpf project.
It's architecture is this:
A console application which will be on a virtual machine (or my home computer) that will be the server side.
A wpf application that will be the client app.
Now my problem is this - I want the server to be able to send changes to the clients. If for example I have a change for client ABC, I want the server to know how to call a service on the clients computer.
The problem is, that I don't know how the server will call the clients.
A small example in case I didn't explain it well:
The server is on computer 1, and there are two clients, on computers 2 and 3.
Client 2 has a Toyota car and client 3 has a BMW car.
The server on computer 1 wants to tell client 2 that it has a new car, an Avenger.
How do I keep track and call services on the clients?
I thought of saving their ip address (from calling ipconfig from the cmd) in the DB - but isn't that based on the WI-FI/network they are connected to?
Thanks for any help!
You could try implementing SignalR. It is a great library that uses web sockets to push data to clients.
Edit:
SignalR can help you solve your problem by allowing you to set up Hubs on your console app (server) that WPF application (clients) can connect to. When the clients start up you will register them with a specified Hub. When something changes on the server, you can push from the server Hub to the client. The client will receive the information from the server and allow you to handle it as you see fit.
Rough mockup of some code:
namepsace Server{}
public class YourHub : Hub {
public void SomeHubMethod(string userName) {
//clientMethodToCall is a method in the WPF application that
//will be called. Client needs to be registered to hub first.
Clients.User(userName).clientMethodToCall("This is a test.");
//One issue you may face is mapping client connections.
//There are a couple different ways/methodologies to do this.
//Just figure what will work best for you.
}
}
}
namespace Client{
public class HubService{
public IHubProxy CreateHubProxy(){
var hubConnection = new HubConnection("http://serverAddress:serverPort/");
IHubProxy yourHubProxy = hubConnection.CreateHubProxy("YourHub");
return yourHubProxy;
}
}
}
Then in your WPF window:
var hubService = new HubService();
var yourHubProxy = hubService.CreateHubProxy();
yourHubProxy.Start().Wait();
yourHubProxy.On("clientMethodToCall", () => DoSometingWithServerData());
You need to create some kind of subscription model for the clients to the server to handle a Publish-Subscribe channel (see http://www.enterpriseintegrationpatterns.com/patterns/messaging/PublishSubscribeChannel.html). The basic architecture is this:
Client sends a request to the messaging channel to register itself as a subscriber to a certain kind of message/event/etc.
Server sends messages to the channel to be delivered to subscribers to that message.
There are many ways to handle this. You could use some of the Azure services (like Event hub, or Topic) if you don't want to reinvent the wheel here. You could also have your server application track all of these things (updates to IP addresses, updates to subscription interest, making sure that messages don't get sent more than once; taking care of message durability [making sure messages get delivered even if the client is offline when the message gets created]).
In general, whatever solution you choose is plagued with a common problem - clients hide behind firewalls and have dynamic IP addresses. This makes it difficult (I've heard of technologies claiming to overcome this but haven't seen any in action) for a server to push to a client.
In reality, the client talks and the server listens and response. However, you can use this approach to simulate a push by;
1. polling (the client periodically asks for information)
2. long polling (the client asks for information and the server holds onto the request until information arrives or a timeout occurs)
3. sockets (the client requests server connection that is used for bi-directional communication for a period of time).
Knowing those terms, your next choice is to write your own or use a third-party service (azure, amazon, other) to deliver messages for you. I personally like long polling because it is easy to implement. In my application, I have the following setup.
A web API server on Azure with and endpoint that listens for message requests
A simple loop inside the server code that checks the database for new messages every 100ms.
A client that calls the API, handling the response.
As mentioned, there are many ways to do this. In your particular case, one way would be as follows.
Client A calls server API to listen for message
Server holds onto call, waiting for new message entry in database
Client B calls server API to post new message
Server saves message to database
Server instance from step 2 sees new message
Server returns message to Client A.
Also, the message doesn't have to be stored in a database - it just depends on your needs.
Sounds like you want to track users à la https://www.simple-talk.com/dotnet/asp.net/tracking-online-users-with-signalr/ , but in a desktop app in the sense of http://www.codeproject.com/Articles/804770/Implementing-SignalR-in-Desktop-Applications or damienbod.wordpress.com/2013/11/20/signalr-a-complete-wpf-client-using-mvvm/ .
Using the code as shown here.. I was able to create a web app that every 30 seconds sent data to client using System.Threading.Timer.
I was able to add some code which received data from a service bus queue using Messaging factory and Messaging receiver and based on that sent data to signalR client instead of hard-coding as in the mentioned example.
Now my real application gets data from 50 such queue..
Theoretically, I could create 50 timer objects which would call 50 different methods which in turn would call service bus queue.
I would sincerely appreciate if someone could suggest the right way to achieve my goal..
Thanks
The message pump pattern seems like it would be a good fit for this application. You create a separate client for each queue and configure each one to automatically listen for messages in its queue and process them as they come in.
foreach (var queueName in queueNames){
var queueClient = QueueClient.CreateFromConnectionString(connectionString, queueName);
queueClient.OnMessage(message =>
{
// Do work here
Console.Out.WriteLine(string.Format("Recieved message {0} on queue {1}", message.MessageId, queueName));
});
}
All,
I have a WCF web service (let's called service "B") hosted under IIS using a service account (VM, Windows 2003 SP2). The service exposes an endpoint that use WSHttpBinding with the default values except for maxReceivedMessageSize, maxBufferPoolSize, maxBufferSize and some of the time outs that have been increased.
The web service has been load tested using Visual Studio Load Test framework with around 800 concurrent users and successfully passed all tests with no exceptions being thrown. The proxy in the unit test has been created from configuration.
There is a sharepoint application that use the Office Sharepoint Server Search service to call web services "A" and "B". The application will get data from service "A" to create a request that will be sent to service "B". The response coming from service "B" is indexed for search. The proxy is created programmatically using the ChannelFactory.
When service "A" takes less than 10 minutes, the calls to service "B" are successfull. But when service "A" takes more time (~20 minutes) the calls to service "B" throw the following exception:
Exception Message: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail
Inner Exception Message: The message could not be processed. This is most likely because the action 'namespace/OperationName' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.
The binding settings are the same, the time in both client server and web service server are synchronize with the Windows Time service, same time zone.
When i look at the server where web service "B" is hosted i can see the following security errors being logged:
Source: Security
Category: Logon/Logoff
Event ID: 537
User NT AUTHORITY\SYSTEM
Logon Failure:
Reason: An error occurred during logon
Logon Type: 3
Logon Process: Kerberos
Authentication Package: Kerberos
Status code: 0xC000006D
Substatus code: 0xC0000133
After reading some of the blogs online, the Status code means STATUS_LOGON_FAILURE and the substatus code means STATUS_TIME_DIFFERENCE_AT_DC. but i already checked both server and client clocks and they are syncronized.
I also noticed that the security token seems to be cached somewhere in the client server because they have another process that calls the web service "B" using the same service account and successfully gets data the first time is called. Then they start the proccess to update the office sharepoint server search service indexes and it fails. Then if they called the first proccess again it will fail too.
Has anyone experienced this type of problems or have any ideas?
Regards,
--Damian
10 mins is the default receive timeout. If you have an idled proxy for more than 10mins, the security session of that proxy is aborted by the server. Enable logging and you will see this in the diagnostics log of the server. The error message you reported fits for this behavior.
Search your system diagnostic file for "SessionIdleManager". If you find it, the above is your problem.
Give it a whirl and set the establishSecurityContext="false" for the client and the server.
Don't call the service operation in a using statement. Instead use a pattern such as...
client = new ServiceClient("Ws<binding>")
try
{
client.Operation(x,y);
client.Close();
}
catch ()
{
client.Abort();
}
I don't understand why this works but I would guess that when the proxy goes out of scope in the using statement, Close isn't called. The service then waits until receiveTimeout (on the binding) has expired and then aborts the connection causing subsequent calls to fail.
What I believe is happening here is that your channel is timing out (as you suspect).
If I understand correctly, it is not the calls to service A that are timing out, but rather to service B, before you call your operation.
I'm guessing that you are creating your channel before you call service A, rather than just in time (i.e. before calling service B). You should create the channel (proxy, service client) just before you use it like:
AResponse aResp = null;
BResponse bResp = null;
using (ServiceAProxy proxyA = new ServiceAProxy())
{
aResp = proxyA.DoServiceAWork();
using (ServiceBProxy proxyB = new ServiceBProxy())
{
bResp = proxyB.DoOtherork(aResp);
}
}
return bResp;
I believe however, that once you get over that problem (service B timing out), you'll realize that the sharepoint app's proxy (that called service A) will timeout.
To solve that, you may wish to change your service model from a request-response, to a publish-subscribe model.
With long-running services, you'll want your sharepoint app to subscribe to service A, and have service A publish its results when it is ready to do so - regardless of how long it takes.
Programming WCF Services (O'Reilly) by Juval Lowey, has a great explanation, and IDesign (Juval's company) published a great set of coding standards for WCF, as well as the code for a great Publish-Subscribe Framework.
Hope this helps,
Assaf.
I actually triggered this error just now by doing something silly. I have a unit test that modifies the system date in order to test some time-based features. And I guess the apparent time difference between when I created the context and when I called my method (because of the changes to the system date), caused something to expire.