Grain 是 Orleans 框架中的基本单元,代表了应用程序中的一个实体或者一个计算单元。

每个Silo都是一个独立的进程,Silo负责加载、管理和执行Grain实例,并处理来自客户端的请求以及与其他Silo之间的通信。

通信原理

在相同的Silo中,Grain与Grain之间的通信通过直接的方法调用实现。每个Silo都维护了一个Grain的运行时环境,当一个Grain需要调用另一个Grain时,它可以直接调用目标Grain的方法,无需经过网络传输,示意图如下所示:

在不同的Silo中,Grain与Grain之间的通信需要通过消息传递的方式实现。当一个Grain需要与另一个Silo中的Grain通信时,它会将消息发送给目标Grain所在的Silo,目标Silo接收到消息后,将其路由到目标Grain,然后目标Grain处理消息并返回结果。示意图如下所示:

外部客户端与Silo之间的通信是通过网络消息传输实现的。客户端需要使用Orleans提供的客户端库与Silo建立连接,并发送请求消息到目标Silo,目标Silo接收到消息后,进行处理并返回结果。在Orleans中,客户端与Silo之间的通信使用了一种名为Orleans Messaging Protocol (OMP)的自定义协议,用于保证通信的可靠性和效率。示意图如下所示:

内置端口

默认情况下,Orleans 将侦听端口 11111 用于silo之间通信,在端口 30000 上进行客户端到接收器通信。可以通过以下方式设置这些端口

siloBuilder.Configure<EndpointOptions>(options =>
{
// Port to use for silo-to-silo
options.SiloPort = 11_111;
// Port to use for the gateway
options.GatewayPort = 30_000;
// IP Address to advertise in the cluster
options.AdvertisedIPAddress = IPAddress.Parse("172.16.0.42");
// The socket used for client-to-silo will bind to this endpoint
options.GatewayListeningEndpoint = new IPEndPoint(IPAddress.Any, 40_000);
// The socket used by the gateway will bind to this endpoint
options.SiloListeningEndpoint = new IPEndPoint(IPAddress.Any, 50_000);
})

在内部,silo 将侦听 0.0.0.0:40000 和 0.0.0.0:50000,但在持久化提供程序中发布的值将是 172.16.0.42:11111 和 172.16.0.42:30000

GrainKey类型

在 Orleans 中,可以使用不同类型的键来标识 Grain。下面是几种常用的 GrainKey 接口:

  • IGrainWithStringKey: 使用字符串作为键的接口。适用于需要以字符串形式标识的场景,比如用户名称、订单号等。
  • IGrainWithGuidKey: 使用 Guid 作为键的接口。适用于需要全局唯一标识的场景,比如唯一的实体对象、全局唯一的标识符等。
  • IGrainWithIntegerKey: 使用整数作为键的接口。适用于需要连续递增或递减的序列标识的场景,比如自增主键、序列号等。
  • IGrainWithGuidCompoundKey: 使用复合的 Guid 作为键的接口。
  • IGrainWithIntegerCompoundKey: 使用复合的整数作为键的接口。
  • IGrainWithGuidCompoundKey: 使用复合的字符串作为键的接口。

下面是使用 IGrainWithStringKey 定义的 IPlayerGrain 接口,并为其增加了买装备的动作,并将买完的装备保存至内存中:

public interface IPlayerGrain : IGrainWithStringKey
{
Task BuyEquipment(string equipmentName);
Task<List<string>> GetOwnedEquipments();
} public class PlayerGrain : Grain, IPlayerGrain
{
private IPersistentState<List<string>> _ownedEquipments; public PlayerGrain([PersistentState("ownedEquipments", "playerGrainStorage")] IPersistentState<List<string>> ownedEquipments)
{
_ownedEquipments = ownedEquipments;
} public async override Task OnActivateAsync(CancellationToken cancellationToken)
{
await base.OnActivateAsync(cancellationToken); // 在激活时从持久化状态中加载数据
await _ownedEquipments.ReadStateAsync();
if (_ownedEquipments.State == null)
{
_ownedEquipments.State = new List<string>();
await _ownedEquipments.WriteStateAsync(); // 将空列表持久化到存储中
}
} public async Task BuyEquipment(string equipmentName)
{
_ownedEquipments.State.Add(equipmentName);
await _ownedEquipments.WriteStateAsync(); // 将更新后的装备列表持久化到存储中
} public Task<List<string>> GetOwnedEquipments()
{
return Task.FromResult(_ownedEquipments.State);
}
}

调用时使用IGrainFactory.GetGrain方法即可

var host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.AddOrleans(builder =>
{
builder
.UseLocalhostClustering()
.Configure<ClusterOptions>(options =>
{
options.ClusterId = "dev";
options.ServiceId = "OrleansExample";
})
.AddMemoryGrainStorage("playerGrainStorage");
});
})
.ConfigureLogging(l => l.AddConsole())
.Build(); await host.StartAsync(); var client = host.Services.GetRequiredService<IGrainFactory>(); var palyer = client.GetGrain<IPlayerGrain>(Guid.NewGuid().ToString());
await palyer.BuyEquipment("Sword");
(await palyer.GetOwnedEquipments()).ForEach(Console.WriteLine);

IGrainFactory 和 IClusterClient

在 Orleans 中,IGrainFactory 和 IClusterClient 都是用于创建和获取 Grains 的接口,但它们的作用和使用场景略有不同。

IGrainFactory:

IGrainFactory 是 Orleans 用于集群中创建 Grains 的工厂接口。 它通常用于在 Orleans Silo 或者 Orleans Client 中创建 Grains 实例。

  • 在 Silo 中,您可以通过依赖注入或者直接实例化一个 IGrainFactory 对象来创建 Grains。
  • 在 Silo 外部,比如 Orleans Client 中,您也可以通过依赖注入或者直接实例化一个 IGrainFactory 对象来创建 Grains。
// 通过依赖注入或直接实例化一个 IGrainFactory 对象
IGrainFactory grainFactory = serviceProvider.GetRequiredService<IGrainFactory>();
var grain = grainFactory.GetGrain<IMyGrain>(grainId);

IClusterClient:

IClusterClient 是 Orleans 中用于与 Orleans 集群进行通信的客户端接口。 它通常在 Orleans Client 中使用,用于与 Orleans Silo 进行通信,以调用 Grains 的方法或者获取 Grains 的引用。

IClusterClient 是 IGrainFactory 的一个超集,除了可以创建 Grains,还可以执行其他集群相关的操作,比如管理 Silo 的生命周期、订阅集群中的事件等。

// 通过依赖注入或直接实例化一个 IClusterClient 对象
IClusterClient clusterClient = serviceProvider.GetRequiredService<IClusterClient>();
var grain = clusterClient.GetGrain<IMyGrain>(grainId);

总的来说,IGrainFactory 主要用于在应用程序内部直接创建 Grains,而 IClusterClient 则更适合用于外部Client与 Orleans 集群进行通信,包括创建 Grains 和执行其他集群操作。

.NET分布式Orleans - 2 - Grain的通信原理与定义的更多相关文章

  1. RPC通信原理概述

    RPC通信原理概述 1.RPC概述 1.什么是RPC RPC(Remote Procedure Call Protocol)远程过程调用协议.它是一种通过网络从远程计算机程序上请求服务,而不需要了解底 ...

  2. 基于web的IM软件通信原理分析

    关于IM(InstantMessaging)即时通信类软件(如微信,QQ),大多数都是桌面应用程序或者native应用较为流行,而网上关于原生IM或桌面IM软件类的通信原理介绍也较多,此处不再赘述.而 ...

  3. Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)

    转载地址:http://blog.csdn.net/mad1989/article/details/9147661 ZERO.前言 有关通信原理内容是在网上或百科整理得到,代码部分为本人所写,如果不当 ...

  4. SSL 通信原理及Tomcat SSL 配置

    SSL 通信原理及Tomcat SSL 双向配置 目录1 参考资料 .................................................................. ...

  5. Java 下 SSL 通信原理及实例

    有关SSL的原理和介绍在网上已经有不少,对于Java下使用keytool生成证书,配置SSL通信的教程也非常多.但如果我们不能够亲自动手做一个SSL Sever和SSL Client,可能就永远也不能 ...

  6. AIDL通信原理

    AIDL (Android Interface Definition Language),通过定义通信接口来实现进程间通信.这是Google提供的一种在安卓应用进程间通信的工具.所以要了解AIDL的通 ...

  7. Java基础知识强化之网络编程笔记02:Socket通信原理图解

    1. Socket (1)Socket套接字  网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字 (2)Socket原理机制:  • 通信两端都有Socket.  • 网 ...

  8. Python Socket通信原理

    [Python之旅]第五篇(一):Python Socket通信原理   python Socket 通信理论 socket例子 摘要:  只要和网络服务涉及的,就离不开Socket以及Socket编 ...

  9. RS-232通信原理

    rs232串口通信原理 串口是计算机上一种非常通用设备通信的协议(不要与通用串行总线Universal Serial Bus或者USB混淆).大多数计算机包含两个基于RS232的串口.串口同时也是仪器 ...

  10. SSL 通信原理及Tomcat SSL 双向配置

    SSL 通信原理及Tomcat SSL 双向配置 目录1 参考资料 .................................................................. ...

随机推荐

  1. 错误发布--如何配置最新的JDK21

    如何配置最新的JDK21 时间:2024/2/3 官网 www.oracle.com 找到对应版本JDK21 可选择语言翻译版本 根据需求选择合适JDK版本.操作系统.位数 三个安装包格式:最简洁的是 ...

  2. NC16664 [NOIP2004]合唱队形

    题目链接 题目 题目描述 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2-,K,他们的身高分 ...

  3. Swoole从入门到入土(27)——协程[协程容器]

    这一章开始,我们要开始全方位讨论Swoole为我们提供的协程机制.在swoole中所有的协程必须在协程容器里面创建(Swoole\Coroutine\Scheduler),Swoole 程序启动的时候 ...

  4. 解决linux下zip文件解压后中文乱码问题

    最近项目上碰到在windows上压缩了一些图片,图片文件名称都是中文的,scp到linux下用unzip解压后文件名 全是乱码,找了半天解决方案,下面这个亲测可行,特记录一下,与大家分享: 原因: 由 ...

  5. 解密C语言选择结构:掌握条件语句与分支逻辑的利器

    欢迎大家来到贝蒂大讲堂 养成好习惯,先赞后看哦~ 所属专栏:C语言学习 贝蒂的主页:Betty's blog 引言 C语⾔是结构化的程序设计语⾔,这⾥的结构指的是顺序结构.选择结构.循环结构.为什么有 ...

  6. Linux驱动开发笔记(三):基于ubuntu的helloworld驱动源码编写、makefile编写以及驱动编译加载流程测试

    前言   前面学习了驱动的基础框架,上一篇编译了gcc7.3.0,那么为了方便很好的熟悉流程,本篇,将使用ubuntu18.04,直接编译ubuntu18.04的驱动,然后做好本篇文章的相关实战测试. ...

  7. Vue框架设计:性能权衡的艺术

    "框架设计里到处都体现了权衡的艺术." 当我们设计一个框架的时候,框架本身的各个模块之间并不是相互独立的,而是相互关联.相互制约的.因此作为框架设计者,一定要对框架的定位和方向拥有 ...

  8. 【LeetCode贪心#01】分饼干,贪心算法入门(入了但是还没完全入)

    分饼干 力扣题目链接(opens new window) 假设你是一位很棒的家长,想要给你的孩子们一些小饼干.但是,每个孩子最多只能给一块饼干. 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子 ...

  9. clickhouse 安装启动报<Error> Application: DB::Exception: There is no profile 'default' in configuration file. 以及常见的错误的总结

    1.启动时报错<Error> Application: DB::Exception: There is no profile 'default' in configuration file ...

  10. 2.Canal连接MQ

    1. 配置文件介绍 Canal的启动,是以创建实例(instance)的方式,每个实例都有自己单独的工作环境, 而配置也分成两个部分 canal.properties (系统根配置文件) instan ...