简体   繁体   English

Azure Service Fabric缩放

[英]Azure Service Fabric Scaling

I have an app that runs scheduled tasks on Azure Service Fabric. 我有一个在Azure Service Fabric上运行计划任务的应用程序。 My app must run thirty to forty tasks at the same time, so I am using asynchronous programming. 我的应用程序必须同时运行三十至四十个任务,因此我正在使用异步编程。 I have some questions: 我有一些疑问:

Do you recommend running the tasks asynchronously? 您是否建议异步运行任务? If not, should I run the task synchronously and scale up? 如果没有,我是否应该同步运行任务并扩大规模? How do I scale up? 如何扩大规模? I need no return information from running the task. 我不需要运行任务的返回信息。

Should I separate the queuing and dequeuing into separate stateful services? 我应该将排队和出队分开到单独的有状态服务中吗? If so, how would these services communicate to each other? 如果是这样,这些服务将如何相互通信?

Here is my code: 这是我的代码:

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();
    }
}

For service fabric (and other actor-based systems), you typically want to scale out as opposed to scaling up [Scaling Up vs Scaling Out] see ( http://www.vtagion.com/scalability-scale-up-scale-out-care/ ) 对于服务结构(和其他基于actor的系统),通常需要扩展而不是扩展 [扩展与扩展],请参阅( http://www.vtagion.com/scalability-scale-up-scale-门诊/

Azure Article on scaling up and down (slight misnomer). 有关扩大和缩小的Azure文章 (轻微的误称)。

Essentially, service fabric takes care of most of the concerns around failover, load balancing etc. 从本质上讲,服务结构可以解决故障转移,负载平衡等方面的大部分问题。

The documentation on how to scale the clusters is well worth a read. 有关如何扩展群集的文档非常值得一读。

The documentation on reliable actors also goes into the "threading" model of the system, which as it's actor-based is fundamentally asynchronous. 有关可靠参与者的文档也包含在系统的“线程”模型中,该模型基于参与者的基础上是异步的。

You can certainly do asynchronous tasks, but when you create more tasks than physical threads available on a machine you'll start seeing diminishing returns. 您当然可以执行异步任务,但是当您创建的任务多于计算机上可用的物理线程时,您将开始看到收益递减。

Service Fabric allows you to scale workloads like this out across multiple machines very easily - think of your machines as a pool of resources. Service Fabric允许您非常轻松地在多台计算机上扩展此类工作负载-将您的计算机视为资源池。 If each VM has 4 physical threads, then with 5 machines you can have a pool of 20 physical threads. 如果每个VM具有4个物理线程,则在5台计算机上,您可以拥有20个物理线程的池。

The way to do this is with a partitioned stateful service. 执行此操作的方法是使用分区的有状态服务。 Each partition of the service handles a subset of the total workload, which is distributed based on a partition key for each unit of work that you create. 服务的每个分区处理总工作量的一个子集,该工作量是基于您创建的每个工作单元的分区键进行分配的。 See here to get started with partitioning: https://azure.microsoft.com/en-us/documentation/articles/service-fabric-concepts-partitioning/ 请参阅此处以开始分区: https : //azure.microsoft.com/en-us/documentation/articles/service-fabric-concepts-partitioning/

I would try to use actor model and move away from the reliable queue. 我将尝试使用参与者模型,并远离可靠的队列。 Whenever a task needs to be added, it will ask the service fabric runtime give an new instance of actors the represent the logic of task. 每当需要添加任务时,它将要求服务结构运行时为角色的新实例提供代表任务逻辑的代表。 the service fabric will handle the distribution of the actors and its lifetime. 服务结构将处理参与者的分布及其生命周期。 if you need the return value in the future, you can use the stateful service or another aggregate actor to get it. 如果将来需要返回值,则可以使用有状态服务或其他聚合参与者来获取它。 In addition, you will have a little more control over the task. 此外,您将对该任务有更多的控制权。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM