5

There are currently two main options to create custom code-based modules on Azure IoT Edge:

  • Custom module (currently .NET Core, soon Python etc. as well)
  • Azure Functions (currently only .NET Core)

So now my question is, what would be the benefit of using one over the other when I want to write custom code in .NET Core (C#)?

There is much less boilerplate code required for the Function but how about things like performance?

Janley Zhang
  • 1,567
  • 7
  • 11
silent
  • 14,494
  • 4
  • 46
  • 86

2 Answers2

5

I don't know. Let's bench! ...on Windows cause that's what i had handy. CPU is Core i7-3770K.

.NET Core Web API (v2.1.3, middleware is whatever dotnet new webapi wires up) —

public class ValuesController : Controller
{
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

Azure Functions script host (v2.0.11587.0) —

// run.csx
public static IEnumerable<string> Run(HttpRequest req)
{
    return new string[] { "value1", "value2" };
}


// host.json
// Default "consoleLevel" is verbose which blocks on flushing stdout,
// performance suffered unnecessarily so i switched to "error".
{
    "tracing": {
      "consoleLevel": "error",
      "fileLoggingMode": "debugOnly"
    }
}

dotnet core and functions host side by side

Results:

// .NET Core Web API
C:\lab\bomb>bombardier-windows-amd64.exe -n 654321 http://127.0.0.1:5000/api/values

Bombarding http://127.0.0.1:5000/api/values with 654321 requests using 125 connections
 654321 / 654321 [===================================] 100.00% 23s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec     27744.21    6713.91  124074.44
  Latency        4.45ms   200.44us    46.97ms
  HTTP codes:
    1xx - 0, 2xx - 654321, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:     6.69MB/s



// Functions script host with .csx
C:\lab\bomb>bombardier-windows-amd64.exe -n 654321 http://127.0.0.1:7071/api/HttpTrigger

Bombarding http://127.0.0.1:7071/api/HttpTrigger with 654321 requests using 125 connections
 654321 / 654321 [===================================] 100.00% 5m31s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec      1976.64     181.69    4213.32
  Latency       63.23ms    20.74ms      2.12s
  HTTP codes:
    1xx - 0, 2xx - 654321, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:   492.23KB/s

I did a test run with precompiled functions (.DLL) as well, for the sake of science, both on v2 (.NET Core) and v1 (.NET Full Framework) runtime.

TL;DR

.NET Core Web API (v2.1.3):                             27744 requests/sec
Functions script host (v2.0.11587.0) .csx:               1976 requests/sec
Functions script host (v2.0.11587.0) precompiled DLL:    2062 requests/sec
Functions script host (v1.0.11535.0) precompiled DLL:    4734 requests/sec

YMMV. Things may look different if you actually crunch some IO not just return 16 bytes on the wire from memory. But it is what it is. If you don't need the extra goodies Functions give you, go raw dotnet.

evilSnobu
  • 24,582
  • 8
  • 41
  • 71
  • Thanks for the benchmark! While that’s pretty much what I expected in terms of native .NET vs. Functions, it doesn’t exactly answer my question in regards to IoT Edge. – silent Mar 28 '18 at 10:15
  • 1
    Not sure what you expect for "benefit of running one vs the other".. Web API / naked dotnet Core has nothing, Functions has built-in triggers, in/out bindings, App Insights integration, nice tooling. Running in the context of IoT Edge is just an implementation detail, it's the same Azure Functions runtime, no magic. – evilSnobu Mar 28 '18 at 11:44
  • 1
    While this benchmark is interesting, I also doubt it answers the question about pros and cons of custom module vs Azure functions in the context of IoT Edge. I am also wondering, how someone will benefit much of triggers and bindings when running on an Edge device. I guess, the only in and out will be the Edge Runtime itself (configured with routing rules), right? So what are the benefits compared to custom modules? Any links are highly appreciated! – Thomas Mutzl May 28 '18 at 09:48
1

As I didn't get any more of an answer apart from the performance aspect, here is my last take on it:

  • Functions are a good fit when:
    • First of all: The code does not need to be executed too often (e.g. don't route all messages through a Function), because performance will probably be a limiting factor
    • You need to have some kind of HTTP interface to your code. Just use a HTTP triggered Function and you don't need to worry about opening and maintaining a web server in your custom code
    • You need some time triggered (scheduled) code to be executed. Build a time triggered Function and you are all set
    • You don't like to have any boiler plate code ;-) Functions are great in the sense that you really only have to write and maintain your very own code. But as the template for custom modules bring all the required boiler plate code, I don't see this as too much of an advantage.

For any other custom modules, I would very probably go and build your own thing. As said before, starting from the templates, writing your own modules is very straightforward.

Hope that helps others as well! (this is not an official Microsoft answer ;) )

You can find some examples for different triggered Edge Functions in my github repo: https://github.com/sebader/azureiotedge/tree/master/edge-functions

silent
  • 14,494
  • 4
  • 46
  • 86