粒度标识

Orleans 中的每个粒子都有一个由用户定义的唯一标识符,包含两个部分:

  1. 颗粒类型名称,唯一标识颗粒类。
  2. 粒度 ,唯一标识该粒度类的逻辑实例。

Orleans 将粒度类型和键表示为可读字符串。 按照约定,使用以字符分隔 / 的粒度类型和键编写粒度标识。 例如,shoppingcart/bob65表示用键bob65命名shoppingcart的粒度类型。

直接构造粒度标识并不常见。 相反,使用Orleans.IGrainFactory创建粒度引用更为常见。

以下部分更详细地讨论粒度类型名称和粒度键。

粒度类型名称

Orleans 基于粒度实现类创建粒度类型名称。 它将从类名中删除后缀“Grain”(如果存在)并将生成的字符串转换为其小写表示形式。 例如,名为ShoppingCartGrain 的类接收粒度类型名称shoppingcart。 建议粒度类型名称和键仅包含可打印字符,如字母数字字符(a-zA-Z0-9)以及符号(如-_@=)。 在日志中打印或显示为其他系统中的标识符(如数据库)时,可能不支持其他字符,并且通常需要特殊处理。

或者,使用 Orleans.GrainTypeAttribute 特性自定义附加到的粒度类的粒度类型名称,如以下示例所示:

[GrainType("cart")]
public class ShoppingCartGrain : IShoppingCartGrain
{
    // Add your grain implementation here
}

在前面的示例中,粒度类 ShoppingCartGrain 具有粒度类型名称 cart。 每个粒度只能有一个粒度类型名称。

对于泛型粒,请在粒类型名称中包含泛型元数。 例如,考虑以下 DictionaryGrain<K, V> 类:

[GrainType("dict`2")]
public class DictionaryGrain<K, V> : IDictionaryGrain<K, V>
{
    // Add your grain implementation here
}

粒子类具有两个泛型参数,因此在粒子类型名的末尾添加一个反引号`,后跟泛型的元数是2,以创建粒子类型名dictdict`2。 这在粒度类的属性中指定: [GrainType("dict2“]'。

粒度键

为方便起见,Orleans公开了几种方法,允许从GuidInt64String构造粒度键。 主键的范围限定为粒度类型。 因此,谷物的完整身份由其类型和关键组成。

谷物的调用方决定使用哪个方案。 选项包括:

由于基础数据相同,因此方案可以互换使用:它们都被编码为字符串。。

需要单一实例粒度实例的情况可以使用已知的固定值,例如 "default"。 这只是一个惯例,但遵循这个惯例能够明确调用方站点正在使用单例粒。

使用全局唯一标识符 (GUID) 作为键

需要随机性和全局唯一性时(例如在作业处理系统中创建新作业时),System.Guid 会生成有用的键。 不需要协调密钥分配,这可能会在资源上引入单一故障点或系统端锁,从而可能造成瓶颈。 GUID 冲突的可能性非常低,因此在构建需要随机标识符分配的系统时,它们成为一个常见选择。

在客户端代码中按 GUID 引用粒度:

var grain = grainFactory.GetGrain<IExample>(Guid.NewGuid());

从粒度代码检索主键:

public override Task OnActivateAsync()
{
    Guid primaryKey = this.GetPrimaryKey();
    return base.OnActivateAsync();
}

使用整数作为键

长整数也可用。 如果粒度持续到关系数据库,其中数值索引通常优先于 GUID,则这是有意义的。

在客户端代码中按长整型引用粒度:

var grain = grainFactory.GetGrain<IExample>(1);

从粒度代码检索主键:

public override Task OnActivateAsync()
{
    long primaryKey = this.GetPrimaryKeyLong();
    return base.OnActivateAsync();
}

使用字符串作为键

字符串键也可用。

在客户端代码中按字符串引用粒度:

var grain = grainFactory.GetGrain<IExample>("myGrainKey");

从粒度代码检索主键:

public override Task OnActivateAsync()
{
    string primaryKey = this.GetPrimaryKeyString();
    return base.OnActivateAsync();
}

使用复合键

如果系统不适合 GUID 或长密钥,请选择复合主键。 这允许结合使用 GUID 或长字符串来引用粒度。

如下所示,从 IGrainWithGuidCompoundKeyIGrainWithIntegerCompoundKey 继承接口。

public interface IExampleGrain : Orleans.IGrainWithIntegerCompoundKey
{
    Task Hello();
}

在客户端代码中,这会向粒度工厂上的 IGrainFactory.GetGrain 方法添加第二个参数:

var grain = grainFactory.GetGrain<IExample>(0, "a string!", null);

若要访问粒度中的复合键,请调用方法的 GrainExtensions.GetPrimaryKey 重载(例如 GrainExtensions.GetPrimaryKeyLong):

public class ExampleGrain : Orleans.Grain, IExampleGrain
{
    public Task Hello()
    {
        long primaryKey = this.GetPrimaryKeyLong(out string keyExtension);
        Console.WriteLine($"Hello from {keyExtension}");

        return Task.CompletedTask;
    }
}

为什么粒度使用逻辑标识符

在面向对象的环境中,如 .NET,对象的标识很难与对它的引用区分开来。 使用 new 关键字创建对象时,返回的引用表示其标识的所有方面,除了将对象映射到其所表示的某些外部实体的方面。 Orleans 专为分布式系统设计。 在分布式系统中,对象引用不能表示实例标识,因为它们仅限于单个进程的地址空间。 Orleans 使用逻辑标识符来避免此限制。 粒度使用逻辑标识符,因此粒度引用在进程生存期内保持有效,并且可以从一个进程移植到另一个进程。 这样,就可以在应用程序中存储和检索以后,或者通过网络发送到应用程序中的另一个进程,同时仍引用同一实体:为其创建引用的粒度。