经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
.NET分布式Orleans - 2 - Grain的通信原理与定义
来源:cnblogs  作者:chester·chen  时间:2024/3/25 8:55:20  对本文有异议

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 上进行客户端到接收器通信。可以通过以下方式设置这些端口

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

在内部,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 接口,并为其增加了买装备的动作,并将买完的装备保存至内存中:

  1. public interface IPlayerGrain : IGrainWithStringKey
  2. {
  3. Task BuyEquipment(string equipmentName);
  4. Task<List<string>> GetOwnedEquipments();
  5. }
  6. public class PlayerGrain : Grain, IPlayerGrain
  7. {
  8. private IPersistentState<List<string>> _ownedEquipments;
  9. public PlayerGrain([PersistentState("ownedEquipments", "playerGrainStorage")] IPersistentState<List<string>> ownedEquipments)
  10. {
  11. _ownedEquipments = ownedEquipments;
  12. }
  13. public async override Task OnActivateAsync(CancellationToken cancellationToken)
  14. {
  15. await base.OnActivateAsync(cancellationToken);
  16. // 在激活时从持久化状态中加载数据
  17. await _ownedEquipments.ReadStateAsync();
  18. if (_ownedEquipments.State == null)
  19. {
  20. _ownedEquipments.State = new List<string>();
  21. await _ownedEquipments.WriteStateAsync(); // 将空列表持久化到存储中
  22. }
  23. }
  24. public async Task BuyEquipment(string equipmentName)
  25. {
  26. _ownedEquipments.State.Add(equipmentName);
  27. await _ownedEquipments.WriteStateAsync(); // 将更新后的装备列表持久化到存储中
  28. }
  29. public Task<List<string>> GetOwnedEquipments()
  30. {
  31. return Task.FromResult(_ownedEquipments.State);
  32. }
  33. }

 

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

  1. var host = Host.CreateDefaultBuilder()
  2. .ConfigureServices((context, services) =>
  3. {
  4. services.AddOrleans(builder =>
  5. {
  6. builder
  7. .UseLocalhostClustering()
  8. .Configure<ClusterOptions>(options =>
  9. {
  10. options.ClusterId = "dev";
  11. options.ServiceId = "OrleansExample";
  12. })
  13. .AddMemoryGrainStorage("playerGrainStorage");
  14. });
  15. })
  16. .ConfigureLogging(l => l.AddConsole())
  17. .Build();
  18. await host.StartAsync();
  19. var client = host.Services.GetRequiredService<IGrainFactory>();
  20. var palyer = client.GetGrain<IPlayerGrain>(Guid.NewGuid().ToString());
  21. await palyer.BuyEquipment("Sword");
  22. (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。
  1. // 通过依赖注入或直接实例化一个 IGrainFactory 对象
  2. IGrainFactory grainFactory = serviceProvider.GetRequiredService<IGrainFactory>();
  3. var grain = grainFactory.GetGrain<IMyGrain>(grainId);

 

IClusterClient:

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

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

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

 

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

原文链接:https://www.cnblogs.com/chenyishi/p/18091260

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号