Orleans 中的每个粒子都有一个由用户定义的唯一标识符,包含两个部分:
- 颗粒类型名称,唯一标识颗粒类。
- 粒度 键,唯一标识该粒度类的逻辑实例。
Orleans 将粒度类型和键表示为可读字符串。 按照约定,使用以字符分隔 /
的粒度类型和键编写粒度标识。 例如,shoppingcart/bob65
表示用键bob65
命名shoppingcart
的粒度类型。
直接构造粒度标识并不常见。 相反,使用Orleans.IGrainFactory创建粒度引用更为常见。
以下部分更详细地讨论粒度类型名称和粒度键。
粒度类型名称
Orleans 基于粒度实现类创建粒度类型名称。 它将从类名中删除后缀“Grain”(如果存在)并将生成的字符串转换为其小写表示形式。 例如,名为ShoppingCartGrain
的类接收粒度类型名称shoppingcart
。 建议粒度类型名称和键仅包含可打印字符,如字母数字字符(a
-z
、A
-Z
和0
-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,以创建粒子类型名dict
dict`2
。 这在粒度类的属性中指定: [GrainType("dict
2“]'。
粒度键
为方便起见,Orleans公开了几种方法,允许从Guid、Int64或String构造粒度键。 主键的范围限定为粒度类型。 因此,谷物的完整身份由其类型和关键组成。
谷物的调用方决定使用哪个方案。 选项包括:
由于基础数据相同,因此方案可以互换使用:它们都被编码为字符串。。
需要单一实例粒度实例的情况可以使用已知的固定值,例如 "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 或长字符串来引用粒度。
如下所示,从 IGrainWithGuidCompoundKey 或 IGrainWithIntegerCompoundKey 继承接口。
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 使用逻辑标识符来避免此限制。 粒度使用逻辑标识符,因此粒度引用在进程生存期内保持有效,并且可以从一个进程移植到另一个进程。 这样,就可以在应用程序中存储和检索以后,或者通过网络发送到应用程序中的另一个进程,同时仍引用同一实体:为其创建引用的粒度。