未加星标

Sharing State Between Azure Functions

字体大小 | |
[系统(windows) 所属分类 系统(windows) | 发布者 店小二03 | 时间 2016 | 作者 红领巾 ] 0人收藏点击收藏

The great thing about “serverless” code is that you don’t need to worry about servers at all. If my function gets invoked 10 times, all 10 invocations might run on the same server, or they might run on 10 different servers. I don’t need to know or care.

But suppose every time my function runs I need to look something up in a database. I might decide that it would be nice to temporarily cache the response in memory so that subsequent runs of my function can run a bit faster (assuming they run on the same server as the previous invocation).

Is that possible in Azure Functions? I did a bit of experimenting to see how it could be done.

To keep things simple, I decided to make a C# webhook function that counted how many times it had been called. And I counted in four ways. First, using a static int variable. Second, using the default MemoryCache . Third, using a text file in the home directory. Fourth, using a per-machine text file in the home directory. Let’s see what happens with each of these methods.

1. Static Integer

If you declare a static variable in your run.csx file, then the contents of that variable are available to all invocations of your function running on the same server. So if our function looks like this:

static int invocationCount = 0;
public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info($"Webhook triggered {++invocationCount}");
return ...
}

And we call it a few times, then we’ll see the invocation count steadily rising. Obviously this code is not thread-safe, but it shows that the memory persists between invocations on the same server.

Unsurprisingly, every time you edit your function, the count will reset. But also you’ll notice it reset at other times too. There’s no guarantee that what you store in a static variable will be present on the next invocation. But it’s absolutely fine for temporarily caching something to speed up function execution.

2. MemoryCache

The next thing I wanted to try was sharing memory between two different functions in the same function app. This would allow you to share a cache between functions. To try this out I decided to use MemoryCache.Default .

static MemoryCache memoryCache = MemoryCache.Default;
public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
var cacheObject = memoryCache["cachedCount"];
var cachedCount = (cacheObject == null) ? 0 : (int)cacheObject;
memoryCache.Set("cachedCount", ++cachedCount, DateTimeOffset.Now.AddMinutes(5));
log.Info($"Webhook triggered memory count {cachedCount}");
return ...
}

Here we try to find the count in the cache, increment it, and save it with a five minute expiry. If we copy this same code to two functions within the same Azure Function App, then sure enough they each can see the count set by the other one.

Again, this cache will lose its contents every time you edit your code, but its nice to know you can share in-memory data between two functions running on the same server.

3. On Disk Shared Across All Servers

Azure function apps have a %HOME% directory on disk which is actually a network share. If we write something into that folder, then all instances of my functions, whatever server they are running on can access it. Let’s put a text file in there containing the invocation count. Here’s a simple helper method I made to do that:

private static int IncrementInvocationCountFile(string fileName)
{
var folder = Environment.ExpandEnvironmentVariables(@"%HOME%\data\MyFunctionAppData");
var fullPath = Path.Combine(folder, fileName);
Directory.CreateDirectory(folder); // noop if it already exists
var persistedCount = 0;
if (File.Exists(fullPath))
{
persistedCount = int.Parse(File.ReadAllText(fullPath));
}
File.WriteAllText(fullPath, (++persistedCount).ToString());
return persistedCount;
}

We can call it like this:

public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
var persistedCount = IncrementInvocationCountFile("invocations.txt");
log.Info($"Webhook triggered {persistedCount}");
return ...;
}

Obviously this too isn’t thread-safe as we can’t have multiple instances of our function reading and writing the same file, but the key here is that anything in this folder is visible to all instances of our function, even across different servers (although it was several days before I saw my test function actually run on a different server). And unlike the in memory counter, this won’t be lost if your function restarts for any reason.

4. Per Machine File

What if you want to use disk storage for temporary caching, but only want per machine? Well, each server does have a local disk, and you can write data there by writing to the %TEMP% folder. This would give you temporary storage that persisted on the same server between invocations of functions in the same function app. But unlike putting things in %HOME% which the Azure Functions framework won’t delete, things you put in %TEMP% should be thought of as transient. The temp folder would probably best be used for storing data needed during a single function invocation.

For my experiment I decided to use System.Environment.MachineName as part of the filename, so each server would maintain its own invocation count file in the %HOME% folder.

public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
var machineCount = IncrementInvocationCountFile(System.Environment.MachineName + ".txt");
log.Info($"Webhook triggered {machineCount}");
return ...;
}

And so now I can use Kudu to look in my data folder and see how many different machines my function has run on.

Should I do this?

So you can use disk or memory to share state between Azure Functions. But does that mean you should?

Well, first of all you must consider thread safety. Multiple instances of your function could be running at the same time, so if you used the techniques above you’d get file access exceptions, and you’d need to protect the static int variable from multiple access (the MemoryCache example is already thread-safe).

And secondly, be aware of the limitations. Anything stored in memory can be lost at any time. So only use it for temporarily caching things to improve performance. By contrast anything stored in the %HOME% folder will persist across invocations, restarts and different servers. But it’s a network share. You’re not really storing it “locally”, so it’s not all that different from just putting the data you want to share in blob storage or a database.

本文系统(windows)相关术语:三级网络技术 计算机三级网络技术 网络技术基础 计算机网络技术

主题: C#
分页:12
转载请注明
本文标题:Sharing State Between Azure Functions
本站链接:http://www.codesec.net/view/481697.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 系统(windows) | 评论(0) | 阅读(35)