Azure Service Fabric Scaling

本文关键字:Scaling Fabric Service Azure | 更新日期: 2023-09-27 17:56:15

我有一个在 Azure Service Fabric 上运行计划任务的应用。我的应用程序必须同时运行三十到四十个任务,所以我使用的是异步编程。我有一些问题:

是否建议异步运行任务?如果没有,我是否应该同步运行任务并纵向扩展?如何扩大规模?我不需要运行任务的返回信息。

我是否应该将排队和出队列分离到单独的有状态服务中?如果是这样,这些服务将如何相互通信?

这是我的代码:

internal sealed class JMATaskRunner : StatefulService
   {
    public JMATaskRunner(StatefulServiceContext context)
        : base(context)
    { }
    /// <summary>
    /// Optional override to create listeners (e.g., HTTP, Service Remoting, WCF, etc.) for this service replica to handle client or user requests.
    /// </summary>
    /// <remarks>
    /// For more information on service communication, see http://aka.ms/servicefabricservicecommunication
    /// </remarks>
    /// <returns>A collection of listeners.</returns>
    protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
    {
        return new ServiceReplicaListener[0];
    }

    public async Task<List<JMATask>> GetMessagesAsync()
    {
        await AddTasks();
        List<JMATask> ts = new List<JMATask>();
        IReliableQueue<JMATask> tasks =
            await this.StateManager.GetOrAddAsync<IReliableQueue<JMATask>>("JMATasks");
        using (ITransaction tx = this.StateManager.CreateTransaction())
        {
            var messagesEnumerable = await tasks.CreateEnumerableAsync(tx);
            using (var enumerator = messagesEnumerable.GetAsyncEnumerator())
            {
                while (await enumerator.MoveNextAsync(CancellationToken.None))
                {
                    ts.Add(enumerator.Current);
                }
            }
        }
        return ts;
        //return messagesEnumerable.ToList();
    }
    public async Task AddMessageAsync(JMATask task)
    {
        IReliableQueue<JMATask> tasks =
            await this.StateManager.GetOrAddAsync<IReliableQueue<JMATask>>("JMATasks");
        using (ITransaction tx = this.StateManager.CreateTransaction())
        {
            await tasks.EnqueueAsync(tx, task);
            await tx.CommitAsync();
        }
    }
    /// <summary>
    /// This is the main entry point for your service replica.
    /// This method executes when this replica of your service becomes primary and has write status.
    /// </summary>
    /// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service replica.</param>
    protected override async Task RunAsync(CancellationToken cancellationToken)
    {
        // TODO: Replace the following sample code with your own logic 
        //       or remove this RunAsync override if it's not needed in your service.
        IReliableQueue<JMATask> tasks =
            await this.StateManager.GetOrAddAsync<IReliableQueue<JMATask>>("JMATasks");
        while (true)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var messagesEnumerable = await GetMessagesAsync();
            using (ITransaction tx = this.StateManager.CreateTransaction())
            {
                foreach (var message in messagesEnumerable)
                {
                    var result = await tasks.TryDequeueAsync(tx);
                    await PerformTask(result.Value);
                }
                await tx.CommitAsync();
                await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
            }
        }

    }
    async Task<JMATask> PerformTask(JMATask task)
    {
        await Task.Run(() => Perform(task));
        return task;
    }
    void Perform(JMATask task)
    {
        Thread.Sleep(50000);
    }
    async Task<JMATask> AddTasks()
    {
        m_TaskProvider = JMATaskFactory.Get(conString);
        //List<JMATask> tasks = m_TaskProvider.GetAllTasks();
        //foreach(JMATask task in tasks)
        //{
        //    await AddMessageAsync(task);
        //}
        JMATask task = m_TaskProvider.GetJMATask(80);
        JMATask task2 = m_TaskProvider.GetJMATask(97);
        await AddMessageAsync(task);
        await AddMessageAsync(task2);
        return new JMATask();
    }
}

Azure Service Fabric Scaling

对于 Service Fabric(和其他基于参与者的系统),通常需要横向扩展,而不是纵向扩展 [纵向扩展与横向扩展] 请参阅 (http://www.vtagion.com/scalability-scale-up-scale-out-care/)

Azure 关于纵向扩展和缩减的文章(略有用词不当)。

从本质上讲,Service Fabric 负责处理有关故障转移、负载平衡等的大部分问题。

有关如何扩展群集的文档非常值得一读。

关于可靠参与者的文档也进入了系统的"线程"模型,因为它是基于参与者的,所以基本上是异步的。

您当然可以执行异步任务,但是当您创建的任务多于计算机上可用的物理线程时,您将开始看到收益递减。

Service Fabric 允许你非常轻松地跨多台计算机缩放此类工作负荷 - 将计算机视为资源池。如果每个 VM 有 4 个物理线程,则使用 5 台计算机时,可以拥有一个包含 20 个物理线程的池。

执行此操作的方法是使用分区的有状态服务。服务的每个分区处理总工作负载的一个子集,该子集根据您创建的每个工作单元的分区键进行分配。请参阅此处以开始使用分区:https://azure.microsoft.com/en-us/documentation/articles/service-fabric-concepts-partitioning/

我会尝试使用actor模型并远离可靠的队列。每当需要添加任务时,它都会要求 Service Fabric 运行时为新的参与者实例提供表示任务逻辑的实例。Service Fabric 将处理参与者的分布及其生存期。如果将来需要返回值,可以使用有状态服务或其他聚合参与者来获取它。此外,您将对任务有更多的控制权。