如何访问无状态服务的特定副本

Posted

技术标签:

【中文标题】如何访问无状态服务的特定副本【英文标题】:How can I reach a specific replica of a stateless service 【发布时间】:2016-09-25 15:20:55 【问题描述】:

我在 Service Fabric 中创建了一个无状态服务。它有一个 SingletonPartition,但有多个实例(在我的例子中,InstanceCount 是 -1)。

我想与此服务的特定副本通信。要查找我使用的所有副本:

var fabricClient = new FabricClient();
var serviceUri = new Uri(SERVICENAME);

Partition partition = (await fabricClient.QueryManager.GetPartitionListAsync(serviceUri)).First();
foreach(Replica replica in await fabricClient.QueryManager.GetReplicaListAsync(partition.PartitionInformation.Id))

  // communicate with this replica, but how to construct the proxy?
  //var eventHandlerServiceClient = ServiceProxy.Create<IService>(new Uri(replica.ReplicaAddress));

问题是 ServiceProxy 没有过载来为副本创建一个。是否有其他方式与特定副本进行通信?

编辑

我们正在构建的场景如下。我们有不同的带有计数器信息的移动部分:1 个命名的分区状态服务(有几百个分区)、1 个 int64 分区状态服务和 1 个具有状态的参与者。为了汇总计数器信息,我们需要访问所有服务分区和参与者实例。

我们当然可以逆转它,让每个人都将计数发送到单个(分区)服务。但这会在正常流程中添加网络调用(因此会产生开销)。

相反,我们提出了以下建议。提到的服务和参与者被组合成一个可执行文件和一个服务清单。因此,它们处于相同的过程中。我们将 instancecount -1 的无状态服务添加到提到的服务和参与者中。所有计数器信息都存储在一个静态变量中。无状态服务可以读取此计数器信息。 现在,我们只需要接触到无状态服务(有节点数上限)。

【问题讨论】:

【参考方案1】:

首先要弄清楚一些术语,“副本”仅适用于有状态服务,其中您为服务的每个分区都有一个唯一的副本集,并在它们之间复制状态以实现 HA。无状态服务只有实例,所有实例都是平等的。

现在回答您的实际问题:ServiceProxy 没有连接到已部署无状态服务的特定实例的选项。您有以下选择:

主副本:连接到有状态服务分区的主副本。 随机实例:连接到无状态服务的随机实例。 随机副本:连接到有状态服务分区的随机副本(无论其角色如何)。 随机辅助副本 - 连接到有状态服务分区的随机辅助副本。

例如:

ServiceProxy.Create<IMyService>(serviceUri, partitionKey, TargetReplicaSelector.RandomInstance)

那么为什么没有连接到特定无状态服务实例的选项呢?

好吧,我会转过头来问你为什么想要连接到特定的无状态服务实例?根据定义,每个无状态实例应该是相同的。如果您在其中保留一些状态 - 例如用户会话 - 那么现在您是有状态的并且应该使用有状态服务。

您可能会考虑智能地决定连接到哪个实例以实现负载平衡,但同样,由于它是无状态的,只要请求均匀分布,任何实例都不应该比其他实例做更多的工作。为此,Service Proxy 具有随机分发选项。

考虑到这一点,如果您仍然有理由寻找特定的无状态服务实例,您始终可以使用不同的通信堆栈(例如 HTTP)并做任何您想做的事情。

【讨论】:

好的,返回实例的 API 称为 GetReplicaListAsync,这就是令人困惑的地方。我们采纳了您的最后一个建议:我们使用 HTTP 通信。我已经编辑了我的问题来描述我们正在构建的场景。 @Vaclav Turecek 如果我想在我的无状态服务中公开 WebSockets 端点怎么办?那么这些实例并不相同,因为我可以与每个实例有或多或少的连接。然后我可能想将更新从参与者推送到无状态服务,以便数据通过 WebSockets 路由到客户端 我想我可以使用 Actor 事件并且无状态的 web api 可以订阅它们 我找不到关于 serviceproxy 随机分发选项的任何信息。【参考方案2】:

“好吧,我想把这个问题转过来问你为什么要连接到特定的无状态服务实例?”

一个例子是,如果您有多个 (3x) 无状态服务实例,它们都具有到不同客户端的 WebSocket 连接,假设每个有 500 个。并且您想通知所有 1500 (500x3) 个用户相同的消息,如果可以直接连接到特定实例(我希望这是可能的,因为我可以使用 FabricClient 查询这些实例),我可以发送向每个实例发送一条消息,将其重定向到所有连接的客户端。

相反,我们必须想出多种解决方法中的任何一种:

    让所有实例连接到某个事件系统,允许它们触发传入消息,例如Azure 事件中心、Azure 服务总线、RedisCache。

    托管一个额外的端点,如此处所述,这使其成为服务实例的 3 个端点:WCF、WebSocket、HTTP。

    更改为不保存任何状态或任何副本的有状态分区服务,只允许调用分区。

目前 RedisCache 存在一些严重的问题,因此正在迁移,并希望避免外部依赖项,例如事件中心和服务总线。

每秒发送许多消息,这将在必须调用 HTTP 时产生额外开销,然后请求需要转换到 WebSocket 上下文。

【讨论】:

以上是关于如何访问无状态服务的特定副本的主要内容,如果未能解决你的问题,请参考以下文章

如何访问 Azure Service Fabric 有状态/无状态服务中的 settings.xml?

在条件下在无状态会话 Bean 中注入特定的 EntityManager

k8s 常用控制器development

如何在有状态或无状态小部件之外访问 BuildContext?

通过 ServiceProxy 访问无状态服务失败 + ASP.NET 5 Web API 项目引发健康状态错误

HTTP是不保存状态的协议,如何保存用户状态?