我刚刚开始为Service Fabric应用程序编写一些动态端点发现,并正在寻找有关如何解析服务端点的示例。我在stackoverflow上找到了以下代码示例:
https://stackoverflow.com/a/38562986/4787510
我对此做了一些小的改动,所以这是我的代码:
private readonly FabricClient m_fabricClient
public async Task RefreshEndpointList()
{
var appList = await m_fabricClient.QueryManager.GetApplicationListAsync();
var app = appList.Single(x => x.ApplicationName.ToString().Contains("<MyFabricDeploymentName>"));
// Go through all running services
foreach (var service in await m_fabricClient.QueryManager.GetServiceListAsync(app.ApplicationName))
{
var partitions = await m_fabricClient.QueryManager.GetPartitionListAsync(service.ServiceName);
// Go through all partitions
foreach (var partition in partitions)
{
// Check what kind of service we have - depending on that the resolver figures out the endpoints.
// E.g. Singleton is easy as it is just one endpoint, otherwise we need some load balancing later on
ServicePartitionKey key;
switch (partition.PartitionInformation.Kind)
{
case ServicePartitionKind.Singleton:
key = ServicePartitionKey.Singleton;
break;
case ServicePartitionKind.Int64Range:
var longKey = (Int64RangePartitionInformation)partition.PartitionInformation;
key = new ServicePartitionKey(longKey.LowKey);
break;
case ServicePartitionKind.Named:
var namedKey = (NamedPartitionInformation)partition.PartitionInformation;
key = new ServicePartitionKey(namedKey.Name);
break;
default:
throw new ArgumentOutOfRangeException($"Can't resolve partition kind for partition with id {partition.PartitionInformation.Id}");
}
var resolvedServicePartition = await ServicePartitionResolver.GetDefault().ResolveAsync(service.ServiceName, key, CancellationToken.None);
m_endpointCache.PutItem(service.ServiceTypeName, new ServiceDetail(service.ServiceTypeName, service.ServiceKind, ServicePartitionKind.Int64Range, resolvedServicePartition.Endpoints));
}
}
}
}
我很高兴找到了这个片段,但是在研究它的过程中,我发现一件事让我有些困惑。
因此,在阅读完SF文档之后,据我所知,这似乎是它从上到下遵循的体系结构:
Service Fabric群集-> Service Fabric应用程序(例如myApp_Fabric)->服务(例如,前端服务,个人资料图片微服务,后端服务)
从服务中,我们可以深入到分区,而分区基本上类似于群集中可以驻留多个实例(副本)的节点上的“容器”,实例是服务的实际部署。
我不确定我是否正确设置了节点/分区/副本之间的差异。
但是,回到我的困惑和实际问题:
为什么有关分区策略(单身,intRange,命名)的信息附加在分区信息上,而不是服务本身?据我了解,分区基本上是我将服务配置为跨服务结构节点分布的产品。
那么,为什么分区策略不直接与服务绑定?
答案 0 :(得分:2)
关于Service Fabric中的服务,有两种类型:有状态服务和无状态服务。
无状态服务不会使用可靠的集合来处理状态。如果他们需要维护状态,则必须依靠数据库等外部持久性解决方案。由于它们不处理可靠集合提供的状态,因此会为其分配Singelton分区类型。
有状态服务具有将状态存储在可靠集合中的能力。为了能够扩展那些服务,应该将这些集合中的数据划分为多个分区。每个服务实例都分配有一个特定的分区。按服务指定分区数量,如以下示例所示:
<Service Name="Processing">
<StatefulService ServiceTypeName="ProcessingType" TargetReplicaSetSize="3" MinReplicaSetSize="3">
<UniformInt64Partition PartitionCount="26" LowKey="0" HighKey="25" />
</StatefulService>
</Service>
因此,在上述示例中,我不明白您关于分区策略未直接与服务绑定的最后一句话。
鉴于上述情况,该服务将运行26个实例,每个分区一个实例,乘以乘以副本数量。
在无状态服务的情况下,将只有一个分区(单例分区),因此实际实例的数量为1 * 3(副本数)=3。(3个副本只是一个示例。无状态服务的实例计数设置为-1,表示群集中每个节点的实例数为1。)
另一件事:在您的代码中,您在代码迭代的分区中有一条注释行:
//例如Singleton很容易,因为它只是一个端点,否则我们稍后需要负载均衡
此注释是错误的,说明分区与负载平衡有关。并非如此,这与如何在服务实例上划分数据有关,并且您需要获取处理特定分区的服务的地址。假设我有一个包含26个分区的服务,并且我想获取存储在第5个分区中的数据。然后,我需要获取服务于该分区的实例的端点。
您可能已经读过the docs。如果没有,我建议也阅读它。
解决您的评论
我只是想知道,是否不可能在同一分区上运行多个服务?
可靠的集合使用它们与服务耦合,基础分区也是如此。因此,同一分区上只能运行一项服务。
但是,服务实例可以。如果服务的副本大小为3,则将有3个实例为该分区提供服务。但是主实例只有1个,可以读写复制到辅助实例的数据。
答案 1 :(得分:2)
想象一下您的服务就像披萨一样,当您请求披萨时,您要求的是披萨的风味(服务类型),通常不需要指定如何将披萨切成薄片(即:8片),通常比萨店会为您解决这个问题,根据比萨的大小,有些比萨店可能会切成4、8或更多的切片。
创建服务实例时,您会以类似的方式看到,您需要一个服务,该服务将保存您的数据,并且您不必关心数据的存储方式。
作为消费者,当您需要了解服务的分区时,就像您打电话给比萨店并要求他们将比萨饼切成4片而不是8片一样,您仍然会得到相同的比萨饼,但是现在您担心的是将被切成多少块。服务分区的主要问题在于,许多应用程序设计都会将此分区泄漏给客户端,并且客户端在使用之前需要知道它有多少个分区或放置在什么位置。
您不应该将服务分区视为消费者,而应该将其作为提供者(比萨店),假设您订购了一个大比萨饼,而比萨店的包装盒(节点)用完了就可以放入比萨饼,他们可以将比萨饼分开两个小盒子里的披萨。最终,消费者会收到相同的披萨,但要放在单独的盒子中,必须处理它才能在其中找到切片。
以此类推,我们可以看到比较:
在Service Fabric中,将其解耦的原因是,消费者可以请求服务,而提供者可以决定如何对其进行分区,在大多数情况下,分区是在创建应用程序时静态定义的,但是可以是动态的,就像在UniformInt64Partition中一样,您可以定义特定服务实例所需的分区数量,可以在不更改代码的情况下,使用相同的服务的多个实例具有不同的分区或不同的方案。实现这些细节的方法是如何将这些分区公开给客户端。