Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Orleans] Silo Metadata and Placement Filtering #44187

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
22ccbed
[Orleans] Silo Metadata and Placement Filtering
rkargMsft Jan 8, 2025
94b2fb8
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
bbde6f2
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
475b2c9
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
2ebff2e
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
f635aa6
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
f3f82cb
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
ebae179
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
10e4197
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
8427b82
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
8908247
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
30180a8
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
fbb8158
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
fc0b782
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
7ed4878
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
2324adc
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
956ea79
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
e0dd2fe
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
812352c
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
5a3dd03
Update docs/orleans/grains/grain-placement-filtering.md
rkargMsft Jan 22, 2025
0be5521
reworded explaination
rkargMsft Jan 22, 2025
358a9e2
fixing markdownlint erros for multiple newlines
rkargMsft Jan 22, 2025
7e340f4
Update silo-metadata.md
rkargMsft Feb 28, 2025
ea92aed
update orleans toc
rkargMsft Feb 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions docs/orleans/grains/grain-placement-filtering.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
title: Grain placement filtering
description: Learn about grain placement filtering in Microsoft Orleans.

ms.date: 01/08/2025
---

# Grain placement filtering

Glain placement filtering in Orleans allows developers additional control over the placement of grains within a cluster. It works in conjunction with placement strategies, adding an additional layer of filtering to determine candidate silos for grain activation.

This filterting takes place before candidate silos are passed on to the configured placement method allowing for more flexibility and reuse of the filters.

For example, the existing `PreferLocal` placement strategy is hard coded to fall back to `Random` placement if the local silo is unable to host the grain type. But by using filters, a `PreferLocalPlacementFilter` could be implemented to filter down to either the local silo or all compatible silos. Then any placement strategy (`Random`, `ResourceOptimizedPlacement`, `ActivationCount`, etc.) could be configured for that grain type. This allows for any set of filters and any placement strategy to be configured for a grain type.

## How placement filtering works

Placement filtering operates as an additional step in the grain placement process. After all compatible silos for the grain type are identified, all placement filters configured for that grain type, if any, are applied to allow further refinement of the selection by eliminating silos that do not meet the defined criteria.

### Ordering

Filters running in different orders may result in different behavior so explicit ordering is required when two or more filters are defined on a type. This needs to be configured with the `order:` parameter, as the type metadata pulled at runtime may return the attributes on a type in a different order from how they appear in the source code. Ordering must have unique values so an explicit ordering can be determined.

## Built-in filters

Orleans provides various built-in filters for you to choose from. However, if you are unable to find one that suits your needs you can always [implement your own](#implement-placement-filters).

### Silo metadata

These filters work with [*Silo Metadata*](../host/configuration-guide/silo-metadata.md) to filter candidate silos.

#### `RequiredMatchSiloMetadata`

Silo Metadata is used to filter candidate silos to only ones that matches all of the specified metadata keys with the calling silo. If there are no compatible silos that match all of the keys then an empty set of silos will be returned and placement will ultimately fail for the grain.

#### `PreferredMatchSiloMetadata`

This filtering will attempt to select only silos that match all of the configured metadata keys with the values of the calling silo. However, instead of returning an empty set if there are not matches as the above Required filtering this will then fall back to partial matches. The first configured metadata key is dropped and a match is made against the remaining keys. This will continue, dropping the initial keys, until a sufficient number of matches are made. If there are not any compatible silos that match *any* of the metadata keys, then all of the candidate silos are returned.

The `minCandidates` value configures how many candidates must be found to stop the filtering process. This value is used to prevent a single silo or small number of silos from getting quickly overloaded if the match were that small.

If `minCandidates` were not considered, then there could be a scenario where there are a large number of silos but only one silo that best matches the configured metadata keys. All placements would be concentrated on that one silo despite having many more available that could host activations. The purpose of `minCandidates` is to allow for a balance between preferring only best matches and avoiding hot silos. It is often desirable to not focus activation (or do scheduling in general) on one target. Set it to a value larger than 1 to ensure a minimum candidate set size so that future placement decisions are able to avoid concentrating activations on one or a few hot silos. Note that this config is a minimum value; more candidates could be returned. If you would prefer most specific matching only then set `minCandidates: 1` to always prefer best match. This might be preferable in specific use cases where there is low activation throughput and where there is a great penalty when moving to a less specific match from a more specific one. In general use, the default value of 2 should be used (and not need to be specified in the attribute).

For example, if filtering on `[PreferredMatchSiloMetadata(["cloud.availability-zone", "cloud.region"], minCandidates:2)]` and there is only one matching silo on both `cloud.availability-zone` and `cloud.region`, then this scenario with `minCandidates: 2` would fail to match on both keys because only one silo matches both metadata keys and that's below the minimum configured size of 2. It would then then fall back to matching only on `cloud.region`. If there were 2 or more silos that match only `cloud.region` then those would get returned. Otherwise, it would fall back to returning all of the candidates.

## Implement placement filters

To implement a custom placement filter in Orleans, follow these steps:

1. **Implementation**
- Create marker Attribute derived from `PlacementFilterAttribute`
- Create Strategy derived from `PlacementFilterStrategy` to manage any configuration values
- Create Director derived from `IPlacementFilterDirector` which contains the filtering logic
- Define the filtering logic in the `Filter` method, which takes a list of candidate silos and returns a filtered list.

2. **Register the Filter**
- Call `AddPlacementFilter` to register the Strategy and corresponding Director

3. **Apply the Filter**
- Add the Attribute to a grain class to apply the filter

Here is an example of a simple custom Placement Filter. It is similar in behavior to using `[PreferLocalPlacement]` without any filter, but this has the advantage of being able to specify any placement method. Whereas `PreferLocalPlacement` falls back to Random placement if the local silo is unable to host a grain, this example has configured `ActivationCountBasedPlacement`. Any other placement could similarly be used with this filter

```csharp
[AttributeUsage(
AttributeTargets.Class, AllowMultiple = false)]
public class ExamplePreferLocalPlacementFilterAttribute(int order)
: PlacementFilterAttribute(
new ExamplePreferLocalPlacementFilterStrategy(order));
```

```csharp
public class ExamplePreferLocalPlacementFilterStrategy(int order)
: PlacementFilterStrategy(order);
```

```csharp
internal class ExamplePreferLocalPlacementFilterDirector(
ILocalSiloDetails localSiloDetails)
: IPlacementFilterDirector
{
public IEnumerable<SiloAddress> Filter(PlacementFilterStrategy filterStrategy, PlacementTarget target, IEnumerable<SiloAddress> silos)
{
var siloList = silos.ToList();
var localSilo = siloList.FirstOrDefault(s => s == localSiloDetails.SiloAddress);
if (localSilo is not null)
{
return [localSilo];
}
return siloList;
}
}
```

After implementing this filter, it can be registered and applied to grains.

```csharp
builder.ConfigureServices(services =>
{
services.AddPlacementFilter<
ExamplePreferLocalPlacementFilterStrategy,
ExamplePreferLocalPlacementFilterDirector>();

});
```

```csharp
[ExamplePreferLocalPlacementFilter]
[ActivationCountBasedPlacement]
public class MyGrain() : Grain, IMyGrain
{
// ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

}
```
119 changes: 119 additions & 0 deletions docs/orleans/host/configuration-guide/silo-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
title: Silo metadata
description: Learn about silo metadata in .NET Orleans.
ms.date: 01/08/2025
---

# Silo Metadata
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Silo Metadata
# Silo metadata


Silo Metadata is a new feature in Orleans that allows developers to assign custom metadata to silos within a cluster. This metadata provides a flexible mechanism for annotating silos with descriptive information or specific capabilities.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Silo Metadata is a new feature in Orleans that allows developers to assign custom metadata to silos within a cluster. This metadata provides a flexible mechanism for annotating silos with descriptive information or specific capabilities.
Silo metadata is a feature in Orleans that allows developers to assign custom metadata to silos within a cluster. This metadata provides a flexible mechanism for annotating silos with descriptive information or specific capabilities.


This feature is particularly useful in scenarios where different silos have distinct roles, hardware configurations, or other unique characteristics. For example, silos can be tagged based on their region, compute power, or specialized responsibilities within the system.

Silo Metadata lays the groundwork for additional Orleans features, such as Placement Filtering.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Silo Metadata lays the groundwork for additional Orleans features, such as Placement Filtering.
Silo metadata lays the groundwork for additional Orleans features, such as [Grain placement filtering](../grains/grain-placement-filtering.md).


## Key Concepts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Key Concepts
## Key concepts


Silo Metadata introduces a way to attach key-value pairs to silos within an Orleans cluster. This feature allows developers to configure silo-specific characteristics that can be leveraged by Orleans components.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Silo Metadata introduces a way to attach key-value pairs to silos within an Orleans cluster. This feature allows developers to configure silo-specific characteristics that can be leveraged by Orleans components.
Silo metadata introduces a way to attach key-value pairs to silos within an Orleans cluster. This feature allows developers to configure silo-specific characteristics that can be leveraged by Orleans components.


Silo Metadata is represented as an **immutable** dictionary of key-value pairs:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Silo Metadata is represented as an **immutable** dictionary of key-value pairs:
Silo metadata is represented as an **immutable** dictionary of key-value pairs:


- **Keys**: Strings that identify the metadata (e.g., `"cloud.region"`, `"compute.reservation.type"`).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the keys case insensitive? If so, that might be good info to include here.

Suggested change
- **Keys**: Strings that identify the metadata (e.g., `"cloud.region"`, `"compute.reservation.type"`).
- **Keys**: Strings that identify the metadata (for example, `"cloud.region"`, `"compute.reservation.type"`).

- **Values**: Strings that describe the corresponding property (e.g., `"us-east1"`, `"spot"`).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- **Values**: Strings that describe the corresponding property (e.g., `"us-east1"`, `"spot"`).
- **Values**: Strings that describe the corresponding property (for example, `"us-east1"`, `"spot"`).


## Configuration

Silo Metadata in Orleans can be configured using two methods: via .NET Configuration or directly in code.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Silo Metadata in Orleans can be configured using two methods: via .NET Configuration or directly in code.
Silo metadata in Orleans is configured using two methods, either .NET configuration or directly in code.


### **Configuring Silo Metadata via .NET Configuration**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### **Configuring Silo Metadata via .NET Configuration**
### Configure Silo metadata with configuration


Silo Metadata can be defined in the application’s Configuration, such as `appsettings.json`, environment variables, or any other Configuration source.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Silo Metadata can be defined in the application’s Configuration, such as `appsettings.json`, environment variables, or any other Configuration source.
Silo metadata can be defined in the app's configuration, such as _appsettings.json_, environment variables, or any other available configuration source.


#### Example: `appsettings.json` Configuration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### Example: `appsettings.json` Configuration
#### Example: _appsettings.json_ configuration


```json
{
"Orleans": {
"Metadata": {
"cloud.region": "us-east1",
"compute.reservation.type": "spot",
"role": "worker"
}
}
}
```

The above configuration defines metadata for a silo, tagging it with:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The above configuration defines metadata for a silo, tagging it with:
The preceding configuration defines metadata for a Silo, tagging it with:


- `cloud.region`: `"us-east1"`
- `compute.reservation.type`: `"spot"`
- `role`: `"worker"`

To apply this configuration, use the following setup in your silo host builder:

```csharp
var siloBuilder = new SiloHostBuilder()
// Configuration section Orleans:Metadata is used by default
.UseSiloMetadata();
```

Alternatively, an explicit `IConfiguration` or `IConfigurationSection` can be passed in to control where in configuration the metadata is pulled from.

---

### **Configuring Silo Metadata Directly in Code**
Comment on lines +61 to +64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
---
### **Configuring Silo Metadata Directly in Code**
### Configuring silo metadata in code


For scenarios requiring programmatic metadata configuration, developers can add metadata directly in the silo host builder.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For scenarios requiring programmatic metadata configuration, developers can add metadata directly in the silo host builder.
For scenarios requiring programmatic metadata configuration, developers can add metadata directly in the Silo host builder.


#### Example: Direct Code Configuration

```csharp
var siloBuilder = new SiloHostBuilder()
.UseSiloMetadata(new Dictionary<string, string>
{
{"cloud.region", "us-east1"},
{"compute.reservation.type", "spot"},
{"role", "worker"}
});
Comment on lines +71 to +77
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var siloBuilder = new SiloHostBuilder()
.UseSiloMetadata(new Dictionary<string, string>
{
{"cloud.region", "us-east1"},
{"compute.reservation.type", "spot"},
{"role", "worker"}
});
var siloBuilder = new SiloHostBuilder()
.UseSiloMetadata(new Dictionary<string, string>
{
["cloud.region"] = "us-east1",
["compute.reservation.type"] = "spot",
["role"] = "worker"
});

```

This example achieves the same result as the JSON configuration but allows metadata values to be computed or loaded dynamically during silo initialization.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This example achieves the same result as the JSON configuration but allows metadata values to be computed or loaded dynamically during silo initialization.
The preceding example achieves the same result as the JSON configuration but allows metadata values to be computed or loaded dynamically during Silo initialization.


---

### **Merging Configurations**
Comment on lines +81 to +84
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
---
### **Merging Configurations**
### Merge configurations


If both .NET Configuration and direct code configuration are used, the direct configuration overrides any conflicting metadata values from the .NET Configuration. This allows developers to set defaults via configuration files and dynamically adjust specific metadata during runtime.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If both .NET Configuration and direct code configuration are used, the direct configuration overrides any conflicting metadata values from the .NET Configuration. This allows developers to set defaults via configuration files and dynamically adjust specific metadata during runtime.
If both .NET configuration and direct code configuration are used, the direct configuration overrides any conflicting metadata values from the .NET configuration. This allows developers to set defaults with configuration files and dynamically adjust specific metadata during runtime.


## Usage

Developers can retrieve metadata through the `ISiloMetadataCache` interface. This interface allows for querying metadata for individual silos across the cluster. Metadata will always be returned from a local cache of metadata that gets updated in the background as cluster membership changes.

### **Accessing Metadata for a Specific Silo**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### **Accessing Metadata for a Specific Silo**
### Access metadata for a specific silo


The `ISiloMetadataCache` provides a method to retrieve the metadata for a specific silo by its unique identifier (`SiloAddress`). The `ISoloMetadataCache` implementation is registered in the `UseSiloMetadata` method and can be injected as a dependency.

#### Example: Accessing Metadata for a Silo
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### Example: Accessing Metadata for a Silo
#### Example: Access metadata for a Silo


```csharp
var siloMetadata = siloMetadataCache.GetSiloMetadata(siloAddress);

if (siloMetadata.Metadata.TryGetValue("role", out var role))
{
Console.WriteLine($"Silo Role for {siloAddress}: {role}");
// Execute role-specific logic
}
```

In this example:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In this example:
In the preceding example:


- `GetSiloMetadata(siloAddress)` retrieves the metadata for the specified silo.
- Metadata keys like `"role"` can be used to influence application logic.

---

## Internal Implementation
Comment on lines +112 to +115
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
---
## Internal Implementation
## Internal implementation


Internally, the `SiloMetadataCache` monitors changes in cluster membership on `MembershipTableManager` and will keep the local cache of metadata in sync with membership changes. Metadata is immutable for a given Silo so it will be retreived once and cached until that Silo leaves the cluster. Cached metadata for clusters that are `Dead` or have left the membership table will be cleared out of the local cache.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Internally, the `SiloMetadataCache` monitors changes in cluster membership on `MembershipTableManager` and will keep the local cache of metadata in sync with membership changes. Metadata is immutable for a given Silo so it will be retreived once and cached until that Silo leaves the cluster. Cached metadata for clusters that are `Dead` or have left the membership table will be cleared out of the local cache.
Internally, the `SiloMetadataCache` monitors changes in cluster membership on `MembershipTableManager` and keeps a local cache of metadata in sync with membership changes. Metadata is immutable for a given Silo, so it's retrieved once and cached until that Silo leaves the cluster. Cached metadata for clusters that are `Dead` or have left the membership table will be cleared out of the local cache.


Each silo hosts an ISystemTarget that provides that silo's metadata. Calls to `SiloMetadataCache : ISiloMetadataCache` then return a result from this local cache.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Each silo hosts an ISystemTarget that provides that silo's metadata. Calls to `SiloMetadataCache : ISiloMetadataCache` then return a result from this local cache.
Each silo hosts an `ISystemTarget` that provides that silo's metadata. Calls to `SiloMetadataCache : ISiloMetadataCache` return a result from the local cache.

4 changes: 4 additions & 0 deletions docs/orleans/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ items:
href: grains/grain-identity.md
- name: Grain placement
href: grains/grain-placement.md
- name: Grain placement filtering
href: grains/grain-placement-filtering.md
- name: Grain extensions
href: grains/grain-extensions.md
- name: Timers and reminders
Expand Down Expand Up @@ -138,6 +140,8 @@ items:
href: host/configuration-guide/typical-configurations.md
- name: Options classes
href: host/configuration-guide/list-of-options-classes.md
- name: Silo metadata
href: host/configuration-guide/silo-metadata.md
- name: Activation collection
href: host/configuration-guide/activation-collection.md
- name: Configure .NET garbage collection
Expand Down