Handling large number of same requests in Azure/IIS WebRole - iis

I have a Azure Cloud Service based HTTP API which is currently serving its data out of an Azure SQL database. We also have a in role cache at the WebRole side.
Generally this model is working fine for us but sometimes what happening is that we get a large number of requests for the same resource within a short period of time span and if that resource is not there in the cache, all the requests went directly to our DB which is a problem for us as many time DB is not able to take that much load.
By looking at the nature of the problem, it seems like it should be a pretty common problem which most of the people build API would face. I was thinking if somehow, I can send only 1st request to DB and hold all the remaining till the time when 1st one completes, to control the load going to DB but I did get any good of doing it. Is there any standard/recommended way of doing it in Azure/IIS?

The way we're handling this kind of scenario is by putting calls to the DB in a lock statement. That way only one caller will hit the DB. Here's pseudo code that you can try:
var cachedItem = ReadFromCache();
if (cachedItem != null)
{
return cachedItem;
}
lock(object)
{
cachedItem = ReadFromCache();
if (cachedItem != null)
{
return cachedItem;
}
var itemsFromDB = ReadFromDB();
putItemsInCache(itemsFromDB);
reurn itemsFromDB;
}

Related

Writing all your functions in one cloud function

What if I put multiple function inside a single cloud function so that its instance lives at max and that I will have to deal with cold start once?
Why is this a bad idea?
export const shop = functions.https.onCall(async (data, context) => {
switch (data.type) {
case "get_fruits":
return await getFruits();
case "place_order":
return await placeOrder();
case "add_to_cart":
return await addToCart();
default:
return;
}
});
It will work but, IMO, it's not a good thing to do. There are many principles and patterns that exist today and that you do not enforce your solution.
Microservice
One of them is the split in microservices. There is no problem to build a monolith, but when I'm seeing your example (get_fruit, place_order, add_to_cart), I'm seeing different roles and responsibilities. I love the separation of concern: 1 service does 1 thing.
Routing
But, maybe your service is only a service for the routing and call functions deployed independently (and you enforce the microservice principle). If so, your service can become a bottleneck, if there are a lot of entries and a lot of queries.
In addition, there are services dedicated for routing: load balancers. They use the URL path of the requests and reach the correct microservices to serve them
Developer usage
Yes a URL, not a field in the body of your message to route the traffic. Today, the developers are familiar with the REST API. To get the fruit, they perform a GET request to the /fruit URL and they know they will get the fruits. If they want to add to the cart, they perform a POST request to the /cart URL and it works!
You USE URL, standard REST definition, load balancers and microservices.
You can imagine other benefits:
Each microservice can scale independently (you can have more get_fruit request than place_order, the service scale differently)
The security is easier to control (no security to get the catalog (fruits)), but you have to be authenticated to place an order
Evolution velocity can be decoupled between the services
...

Timer based Azure function with Table storage, HTTP request, and Azure Service Bus

I have a process written in a console application right now that fires on a scheduled task to read data from Azure table storage and based on that data, make API calls to a third party vendor we use, deserialize the response data, loop over an array in the results, save the individual iterations of the loop into a different table in Azure table storage, and then publish messages for each iteration of the loop to Azure service bus where those messages are consumed by another client.
In an effort to get more of our tasks into the cloud, I've done some research and it seems that an Azure function would be a good candidate to replace my console application. I spun up a new Azure function project in Visual Studio 2019 as a "timer" function and then dove into some reading where I got lost really fast.
The reading I've done talks about using "bindings" in my Run() method arguments decorated with attributes for connection strings etc but I'm not sure that is the direction I should be heading. It sounds like that would make it easier for authentication to my table storage, but I can't figure out how to use those "hooks" to query my table and then perform inserts. I haven't even gotten to the service bus stuff yet nor looked into making HTTP calls to our third party vendor's api.
I know this is a very broad question and I don't have any code to post because I'm having a tough time even getting out of the starting blocks with this. The MS documentation is all over the map and I can't find anything specific to my needs and I promise I've spent a fair bit of time trying.
Are Azure functions even the right path I should be travelling? If not, what other options are out there?
TIA
You should keep with Azure Functions with the Time Trigger to replace your console app.
The bindings (which can be used for input /output) are helpers to save you some lines of code, for example:
Rather than using the following code to insert data into azure table:
// Retrieve storage account information from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);
// Create a table client for interacting with the table service
CloudTableClient tableClient = storageAccount.CreateCloudTableClient(new TableClientConfiguration());
// Create a table client for interacting with the table service
CloudTable table = tableClient.GetTableReference("MyTable");
//some code to populate an entity
var entity = new { PartitionKey = "Http", RowKey = Guid.NewGuid().ToString(), Text = input.Text };
// Create the InsertOrReplace table operation
TableOperation insertOrMergeOperation = TableOperation.InsertOrMerge(entity);
// Execute the operation.
TableResult result = await table.ExecuteAsync(insertOrMergeOperation);
you would use:
[FunctionName("TableOutput")]
[return: Table("MyTable")]
public static MyPoco TableOutput([HttpTrigger] dynamic input, ILogger log)
{
log.LogInformation($"C# http trigger function processed: {input.Text}");
return new MyPoco { PartitionKey = "Http", RowKey = Guid.NewGuid().ToString(), Text = input.Text };
}
PS: the input trigger in the previous code is a HTTP Trigger, but was only to explain how to use output binding.
you can find more information in here:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings
https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-table
and you should watch: https://learn.microsoft.com/en-us/learn/modules/chain-azure-functions-data-using-bindings/

Refreshing in-memory cache across multiple instances in Azure

I have an Azure web app which uses in-memory caching, adding keys as follows
public static void Add(object item, string key)
{
var wrapper = new CacheItemWrapper()
{
InsertedAt = DateTime.Now,
Item = item
};
MemoryCache.Default.Add(key, wrapper, ObjectCache.InfiniteAbsoluteExpiration);
}
Occasionally the user of our application will make a change which requires the cache to refresh. I can call a method which clears the cache, the problem is, it only works on the instance which picks up the request. Other instances still have the old values in memory.
Is there any way I can do either of these things
a) run a method across multiple instances, or
b) raise an event which all instances listen for?
The code above could be changed to expire within a short time so that all instances could pick this up. However, it's quite a long process to update the cache and this might affect performance. Given the application knows when it needs to refresh the cache, it would be much better and more responsive if it could be done programmatically.

Upload an entire XML file to Azure Mobile Services

I have an XML with 25,000 objects that I want to transition to the cloud instead of keeping it local. Buuuuuut I have no idea how to get the XML document into the service, preferably I want it in the SQL database that comes with the service. I know how to upload from the app but with 25,000 objects the service times out. I am sure there is something I just cant find the documentation on.
private async void bw_Worker(object sender, DoWorkEventArgs e)
{
foreach(card x in cardsList)
{
await App.MobileService.GetTable<card>().InsertAsync(x);
}
}
It gets just past 7500 then times out. I am running it in a background worker. I couldn't find any such limits on that so I just imagined its a process that takes too long to complete.

How to get x-ms-request-id from Azure table storage api call

I getting slow behavior for my azure tablestorage api calls on a windows azure app.I need to get the request id (x-ms-request-id in the response header) for a particular call. Is there a way I can get it using the storageclient api? Does the storage client api even expose this id? If not, is there any other way to get this id?
I am using the api in the following way:
public UserDataModel GetUserData(String UserId)
{
UserDataModel osudm = null;
try
{
var result = (from c in GetServiceContext().OrgUserIdTable
where (c.RowKey == UserId)
select c).FirstOrDefault();
UserDataSource osuds = new UserDataSource(this.account);
osudm = osuds.GetUserData(result.PartitionKey, result.UserName);
}
catch (Exception e)
{
}
return osudm;
}
What you're asking here is more related to WCF Data Services than it is to Windows Azure (the storage client client API uses this). Here is some example code how you can access the response headers:
var tableContext = new MyTableServiceContext(...);
DataServiceQuery<Order> query = tableContext.Orders.Where(o => o.RowKey == "1382898382") as DataServiceQuery<Order>;
IEnumerable<Order> result = query.Execute();
QueryOperationResponse response = result as QueryOperationResponse;
string requestId;
response.Headers.TryGetValue("x-ms-request-id", out requestId);
So what you'll be doing first is simply create your query and cast it to a DataServiceQuery of TType. Then you can call the Execute method on that query and cast it to a QueryOperationResponse. This class will give you access to all headers, including the x-ms-request-id.
Note that in this case you won't be able to use FirstOrDefault, since this doesn't return an IQueryable and you can't cast it to a DataServiceQuery of TType (unless there's an other way to do it using WCF Data Services).
Note: The reason why the call is so slow might be caused by your query. When you query the OrgUserIdTable table, you only filter based on the RowKey. I don't know how much data or partitions you have in that table, but if you don't use the PartitionKey this might have a significant performance impact. You have to know that, by not including the PartitionKey, you'll force a search on all partitions (possibly over multiple servers) which might be causing the call being so slow.
I suggest you take a look at the following real world guidance to get a better insight on how and why partitioning relates to performance in Windows Azure Storage: Designing a Scalable Partitioning Strategy for Windows Azure Table Storage

Resources