Я только начинаю писать динамическое обнаружение конечных точек для своего приложения 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) -> Службы (например, внешняя служба, микрослужба изображения профиля, внутренние службы)
От служб мы можем перейти к разделам, в то время как раздел в основном напоминает «контейнер» на узле в моем кластере, на котором могут находиться несколько экземпляров (реплик), причем экземпляры представляют собой фактические развертывания службы.
Однако я не совсем уверен, правильно ли я понял разницу между узлом/разделом/репликой.
Однако вернемся к моему замешательству и актуальному вопросу:
Почему информация о стратегии разделения (singleton, intRange, named) прикреплена к информации о разделе, а не к самой службе? Насколько я понял, раздел — это в основном продукт того, как я настроил свой сервис для распределения по узлам сервисной фабрики.
Итак, почему же стратегия разделения напрямую не привязана к сервису?
Что касается служб в Service Fabric, существует два типа: службы с отслеживанием состояния и службы без отслеживания состояния.
Службы без сохранения состояния не работают с состоянием, используя надежные коллекции. Если им необходимо поддерживать состояние, им приходится полагаться на внешние решения для сохранения состояния, такие как базы данных и т. д. Поскольку они не имеют дело с состоянием, предоставляемым надежными коллекциями, им назначается тип Singelton Partition.
Службы с отслеживанием состояния могут хранить состояние в надежных коллекциях. Чтобы иметь возможность масштабировать эти службы, данные в этих коллекциях должны быть разделены на разделы. Каждому экземпляру службы назначается определенный раздел. Количество разделов указывается для каждой службы, как в примере ниже:
<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 экземпляр для каждого узла в кластере.)
Еще одна вещь: в вашем коде у вас есть строка комментария в фрагменте кода, итерирующего разделы:
// E.g. Singleton is easy as it is just one endpoint, otherwise we need some load balancing later on
Этот комментарий неверен, утверждая, что разделение связано с балансировкой нагрузки. Это не так, это связано с тем, как данные распределяются по экземплярам службы, и вам нужно получить адрес службы, которая имеет дело с конкретным разделом. Скажем, у меня есть служба с 26 разделами, и я хочу получить данные, которые хранятся, скажем, в 5-м разделе. Затем мне нужно получить конечную точку для экземпляра, который обслуживает этот раздел.
Вы, наверное, уже читали документы. Если нет, то тоже советую прочитать.
Обращение к вашим комментариям:
I was just wondering, is it not possible that multiple services run on the same partition?
Надежные коллекции связаны со службой, использующей их, так же как и базовые разделы. Следовательно, в одном разделе может работать не более одной службы.
Но экземпляры службы могут. Если служба имеет размер реплики, скажем, 3, то этот раздел будет обслуживать 3 экземпляра. Но только 1 является основным экземпляром, считывающим и записывающим данные, которые реплицируются во вторичные экземпляры.
@abarger Я полагаю, ты прав, не смотрел на это с такой стороны.
Представьте, что ваша услуга похожа на пиццу, когда вы заказываете пиццу, вы запрашиваете вкус пиццы (тип услуги), вы обычно не указываете, как вы хотите нарезать эту пиццу (например, на 8 кусочков), как правило, пиццерия обрабатывает это. для вас, а некоторые могут быть нарезаны на 4, 8 или более частей в зависимости от размера пиццы.
Когда вы создаете экземпляр службы, вы можете видеть аналогичным образом, что вам нужна служба, эта служба будет хранить ваши данные, и вам не нужно заботиться о том, как эти данные хранятся.
Как потребитель, когда вам нужно понять разделение вашей услуги, вы звоните в пиццерию и просите их разрезать пиццу на 4 куска вместо 8, вы по-прежнему получаете ту же пиццу, но теперь вас интересует, сколько куски он будет нарезан. Основная проблема с разделением служб заключается в том, что многие проекты приложений пропускают это разделение к клиенту, и клиент должен знать, сколько у него разделов или где они размещены, прежде чем использовать его.
Вы не должны заботиться о разделе услуг как потребитель, но как поставщик (пиццерия), скажем, вы заказываете большую пиццу, и в пиццерии заканчиваются коробки (узел), чтобы положить пиццу, они могут разделить пиццу на две части. маленькие коробки. В итоге потребитель получает ту же самую пиццу, но в разных коробках, и ему придется брать ее в руки, чтобы найти в ней кусочки.
С этой аналогией мы можем увидеть сравнение как:
В Service Fabric причина его разъединения заключается в том, что потребитель может запросить службу, а поставщик может решить, как он хочет ее разбить. В большинстве случаев разделы определяются статически при создании приложения, но они могут быть динамическими. , как показано в UniformInt64Partition, вы можете определить, сколько разделов вам нужно для конкретного экземпляра службы, вы можете иметь несколько экземпляров одной и той же службы с разными разделами или разными схемами без изменения строки кода. То, как вы будете предоставлять эти разделы клиенту, является деталью реализации.
Это было отличное объяснение, большое спасибо! Какая вкусная аналогия :)
«Я не понимаю вашего последнего замечания о том, что стратегия разделения напрямую не связана со службой». Я думаю, что путаница здесь связана с моделью приложения и API, доступными для запросов к Service Fabric. API-интерфейсы для запроса службы не включают информацию о разделе, вероятно, потому, что они ориентированы на предоставление информации из манифеста службы. Информация о разделе для службы пример указана в манифесте приложения. Я не знаю API-интерфейсов для получения информации об экземпляре службы относительно его приложения. Итак, нам нужно углубиться в список разделов.