【问题标题】:Why is the partitioning strategy for a service fabric service tied to the partition instead of to the service?为什么服务结构服务的分区策略绑定到分区而不是服务?
【发布时间】:2019-08-28 16:42:24
【问题描述】:

我刚刚开始为我的 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));
            }
        }
    }
}

我很高兴找到了这个 sn-p,但是在处理它的过程中,我发现了一件让我有点困惑的事情。

所以,在阅读了 SF 文档之后,据我了解,这似乎是它从上到下遵循的架构:

Service Fabric 集群 -> Service Fabric 应用程序(例如 myApp_Fabric)-> 服务(例如,前端服务、个人资料图片微服务、后端服务)

从服务中我们可以深入了解分区,而分区基本上类似于集群中节点上的“容器”,可以驻留多个实例(副本),实例是服务的实际部署。

不过,我不太确定节点/分区/副本的差异是否正确。

但是,回到我的困惑和实际问题:

为什么分区策略的信息(singleton、intRange、named)附加到分区信息,而不是服务本身?据我了解,分区基本上是我将服务配置为跨服务结构节点分布的产物。

那么,为什么分区策略不直接与服务绑定?

【问题讨论】:

    标签: azure azure-service-fabric


    【解决方案1】:

    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 个实例。)

    另一件事:在您的代码中,您在代码迭代中的分区中有一个注释行:

    // 例如单例很简单,因为它只是一个端点,否则我们需要一些负载平衡稍后

    此评论错误地指出分区与负载平衡有关。不是,它与数据在服务实例上的分区方式有关,您需要获取处理特定分区的服务的地址。假设我有一个包含 26 个分区的服务,我想获取存储在第 5 个分区中的数据。然后,我需要获取为该分区提供服务的实例的端点。

    您可能已经阅读过the docs。如果没有,我建议您也阅读它。

    解决您的 cmets:

    我只是想知道,多个服务不可能在同一个分区上运行吗?

    可靠的集合与使用它们的服务耦合,底层分区也是如此。因此,不能在同一个分区上运行多个服务。

    但是,服务实例可以。如果服务的副本大小为 3,则将有 3 个实例为该分区提供服务。但只有 1 个是主实例,读取和写入复制到辅助实例的数据。

    【讨论】:

    • “我不明白你关于分区策略没有直接绑定到服务的最后评论。”我认为这里的混淆与应用程序模型与可用于查询 Service Fabric 的 API 有关。用于查询服务的 API 不包含有关分区的信息,可能是因为它们专注于提供来自服务清单的信息。服务 instance 的分区信息在应用程序清单中指定。我知道没有任何 API 可用于获取有关其应用程序的服务实例的信息。所以我们必须深入到分区列表中。
    • @abarger 我想你是对的,没有那样看。
    【解决方案2】:

    将您的服务想象成比萨饼,当您请求比萨饼时,您要求比萨饼的风味(服务类型),您通常不会指定要如何切片比萨饼(即:8 块),通常是披萨店会为您处理,有些可能会根据披萨的大小切成 4 片、8 片或更多片。

    当您创建服务的实例时,您可以以类似的方式看到,您需要一个服务,该服务将保存您的数据,您不必关心数据是如何存储的。

    作为消费者,当您需要了解服务的划分时,就像您打电话给比萨店并要求他们将比萨切成 4 片,而不是 8 片,您仍然得到相同的比萨,但现在您关心的是是多少片它将被切片。服务分区的主要问题是,许多应用程序设计将此分区泄漏给客户端,并且客户端在使用它之前需要知道它有多少个分区或它们放置在哪里。

    作为消费者,您不应该关心服务分区,而应该作为提供者(比萨店),假设您订购了一个大比萨饼并且比萨店用完了盒子(节点)来放置比萨饼,他们可以拆分两个小盒子里的披萨。最后,消费者收到相同的披萨,但在不同的盒子里,必须处理它才能找到里面的切片。

    通过这个类比,我们可以将比较视为:

    • 风味 = 服务类型
    • 披萨 = 服务
    • 大小和切片方式 = 分区方案
    • 切片 = 分区
    • 框 = 节点
    • 比萨饼数 = 副本

    在 Service Fabric 中,将其解耦的原因是因为消费者可以请求服务,而提供者可以决定如何对其进行分区,在大多数情况下,分区是在应用程序创建时静态定义的,但它可能是动态的,如 UniformInt64Partition 中所示,您可以定义特定服务实例需要多少个分区,您可以拥有具有不同分区或不同方案的同一服务的多个实例,而无需更改一行代码。如何将这些分区公开给客户端,是一个实现细节。

    【讨论】:

    • 这是一个很好的解释,非常感谢!多么美妙的比喻:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    • 2016-10-12
    • 2018-08-30
    • 2020-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多