Remote Assembly Loading
Automatic remote assembly loading
Overview
Many Ignite APIs involve remote code execution. For example, Compute tasks and functions are serialized, sent to remote nodes, and executed there. However, .NET assemblies (dll files) with these functions must be loaded on remote nodes in order to instantiate and deserialize task instances.
Before version 2.1 you had to manually load assemblies (using -assembly
swith with Apache.Ignite.exe or some other ways). Ignite 2.1 introduces automatic remote assembly loading, controlled with IgniteConfiguration.PeerAssemblyLoadingMode
. Default is Disabled
, which means old behavior where assemblies must be loaded manually. This configuration property must have the same value on all nodes in the cluster. Another available mode is CurrentAppDomain
.
CurrentAppDomain Mode
PeerAssemblyLoadingMode.CurrentAppDomain
enables automatic on-demand assembly requests to other nodes in cluster, loading assemblies into AppDomain where Ignite node runs.
Consider the following code:
// Print Hello World on all cluster nodes.
ignite.GetCompute().Broadcast(new HelloAction());
class HelloAction : IComputeAction
{
public void Invoke()
{
Console.WriteLine("Hello World!");
}
}
- Ignite serializes
HelloAction
instance and sends to every node in cluster - Remote nodes attempt to deserialize
HelloAction
. If there is no such class in currently loaded or referenced assemblies, request is sent to the node whereBroadcast
was called, then to other nodes (if necessary). - Assembly file is sent from other node as a byte array and loaded with
Assembly.Load(byte[])
method.
Versioning
Assembly-qualified type name (which includes assembly version) is used to resolve types.
If you keep the cluster running, modify HelloAction
to print something else, change AssemblyVersion, recompile and run the code, new version of assembly will be deployed and executed.
However, if you keep AssemblyVersion
unchanged, Ignite will use existing assembly that was previously loaded, since nothing in the type name has changed.
Assemblies with different versions exist side by side. Old nodes can continue running old code, while new nodes execute computations with a newer version of the same class.
AssemblyVersion
attribute can include asterisk (*
) to enable autoincrement on build: [assembly: AssemblyVersion("1.0.*")]
. This way you can keep the cluster running, repeatedly modify and run computations, and new assembly version will be deployed every time.
Dependencies
Dependent assemblies are also loaded automatically (e.g. when ComputeAction
calls some code from a different assembly). Keep that in mind when using heavy frameworks and libraries: single compute call can cause lots of assemblies to be sent over the network.
Unloading
.NET does not allow assembly unloading; only entire AppDomain
can be unloaded with all assemblies. Currently available CurrentAppDomain
mode uses existing AppDomain, which means all peer-deployed assemblies will stay loaded while current AppDomain lives. This may cause increased memory usage.
Example
Binary distribution includes PeerAssemblyLoadingExample
, see details in the source code.
Here is how to test assembly loading with NuGet:
- Create a new Console Application in Visual Studio
- Install Ignite.NET NuGet package
Install-Package Apache.Ignite
- Open
packages\Apache.Ignite.2.1\lib\net40
folder - Add
peerAssemblyLoadingMode='CurrentAppDomain'
attribute to<igniteConfiguration>
element - Run Apache.Ignite.exe (one or more times), leave the processes running
- Change
[AssemblyVersion]
inAssemblyInfo.cs
to1.0.*
- Modify
Program.cs
in Visual Studio as shown below
using System;
using Apache.Ignite.Core;
using Apache.Ignite.Core.Compute;
using Apache.Ignite.Core.Deployment;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var cfg = new IgniteConfiguration
{
PeerAssemblyLoadingMode = PeerAssemblyLoadingMode.CurrentAppDomain
};
using (var ignite = Ignition.Start(cfg))
{
ignite.GetCompute().Broadcast(new HelloAction());
}
}
class HelloAction : IComputeAction
{
public void Invoke()
{
Console.WriteLine("Hello, World!");
}
}
}
}
<igniteConfiguration peerAssemblyLoadingMode='CurrentAppDomain' />
...
[assembly: AssemblyVersion("1.0.*")]
...
- Run the project and observe "Hello, World!" output in the console of all
Apache.Ignite.exe
windows. - Change "Hello, World!" text to something else and run the program again; observe different output on standalone nodes.
Updated over 4 years ago