在面向对象的环境中,对象的标识很难与对它的引用区分开来。因此,当使用new创建对象时,返回的引用,表示其标识的所有方面——除了那些将对象映射到它所表示的某个外部实体的方面。
在分布式系统中,对象引用不能表示实例标识,因为引用通常仅限于单个地址空间。对于.NET引用来说,情况当然如此。此外,一个grain必须有一个标识,不管它是否被激活,这样我们可以根据需要激活它。因此,grain有一个主键。主键可以是全局唯一标识符(GUID),长整数或字符串。
主键的作用域是grain类型。因此,grain的完整标识是由grain的类型及其主键组成的。
grain的调用者决定应该使用哪种方案。可选项有:
因为底层的数据是相同的,所以这些方案可以互换使用。当使用长整数时,实际上会创建一个GUID并用零填充。
需要单个grain实例(例如字典或注册表)的情况,可以使用Guid.Empty
作为其键来获得益处。这仅仅是一个约定,但通过遵循约定,调用方就能很清楚在做什么,正如我们在第一个教程中所看到的那样。
当有多个进程可以请求grain时,GUID很有用,例如Web Farm中的多个Web服务器。您不需要协调键的分配,这可能会导致系统中引入单点故障,或者系统端对可能出现瓶颈的资源的锁定。GUID碰撞的可能性非常小,因此在构建Orleans系统时,它们也许是默认的选择。
在client代码中通过GUID引用grain:
var grain = grainFactory.GetGrain<IExample>(Guid.NewGuid());
在grain代码中取回主键:
public override Task OnActivateAsync()
{
Guid primaryKey = this.GetPrimaryKey();
return base.OnActivateAsync();
}
也可以使用长整数,如果将grain持久化到关系数据库中,那么这是有意义的,在关系数据库中,数字索引比GUID更受欢迎。
在client代码中引用长整数的grain:
var grain = grainFactory.GetGrain<IExample>(1);
在grain的代码中取回主键:
public override Task OnActivateAsync()
{
long primaryKey = this.GetPrimaryKeyLong();
return base.OnActivateAsync();
}
也可以使用string。
在client代码中通过string来引用grain:
var grain = grainFactory.GetGrain<IExample>("myGrainKey");
在grain的代码中取回主键:
public override Task OnActivateAsync()
{
string primaryKey = this.GetPrimaryKeyString();
return base.OnActivateAsync();
}
如果您的系统不适合GUID或long,您可以选择复合主键,它允许您使用GUID或long和字符串的组合来引用grain。
您可以将您的接口继承自'IGrainWithGuidCompoundKey'或'IGrainWithIntegerCompoundKey',如下所示:
public interface IExampleGrain : Orleans.IGrainWithIntegerCompoundKey
{
Task Hello();
}
在client代码中,这会在grain工厂的方法GetGrain
中,添加第二个参数。
var grain = grainFactory.GetGrain<IExample>(0, "a string!", null);
要访问grain中的复合键,我们可以在GetPrimaryKey
方法上调用重载:
public class ExampleGrain : Orleans.Grain, IExampleGrain
{
public Task Hello()
{
string keyExtension;
long primaryKey = this.GetPrimaryKeyLong(out keyExtension);
Console.WriteLine("Hello from " + keyExtension);
Task.CompletedTask;
}
}