在 .NET 中优化后台批处理的 8 种实用方法

作者:微信公众号:【架构师老卢】
7-11 18:4
41

概述:在当今快节奏的商业环境中,效率和响应能力对于保持竞争优势至关重要。后台批处理通过异步处理耗时的任务在实现这些目标方面发挥着关键作用,从而释放系统资源并确保无缝的用户体验。在需要处理大量数据的情况下,或者必须在没有直接用户交互的情况下定期执行任务的情况下,这种技术尤为重要。后台批处理的常见业务方案电子商务平台: 更新库存水平、处理订单和管理用户通知。金融服务: 运行夜间报告、处理交易并监控欺诈检测算法。医疗保健系统: 更新患者记录、处理保险索赔和管理预约时间表。社交媒体平台: 处理用户活动日志、更新推荐算法以及处理内容审核任务。在 .NET 中实现后台批处理在 .NET 中实现后台批处理可以通过

在当今快节奏的商业环境中,效率和响应能力对于保持竞争优势至关重要。后台批处理通过异步处理耗时的任务在实现这些目标方面发挥着关键作用,从而释放系统资源并确保无缝的用户体验。在需要处理大量数据的情况下,或者必须在没有直接用户交互的情况下定期执行任务的情况下,这种技术尤为重要。

后台批处理的常见业务方案

  1. 电子商务平台: 更新库存水平、处理订单和管理用户通知。
  2. 金融服务: 运行夜间报告、处理交易并监控欺诈检测算法。
  3. 医疗保健系统: 更新患者记录、处理保险索赔和管理预约时间表。
  4. 社交媒体平台: 处理用户活动日志、更新推荐算法以及处理内容审核任务。

在 .NET 中实现后台批处理

在 .NET 中实现后台批处理可以通过多种方式实现,具体取决于业务的特定需求和现有的技术堆栈。以下是一些有效的方法:

1.Using the Keyword in C#

C# 中的关键字允许异步执行任务,这意味着可以在不阻塞主执行线程的情况下执行某些操作。这对于后台处理特别有用,因为在后台处理中,任务可以与其他操作同时执行。

C# 中的示例:

public async Task ProcessBatchAsync()  
{  
    var data = await FetchDataAsync();  
    await ProcessDataAsync(data);  
    Console.WriteLine("Batch processing completed");  
}  
  
public void ScheduleBatchProcessing()  
{  
    var timer = new System.Threading.Timer(  
        async e => await ProcessBatchAsync(),  
        null,  
        TimeSpan.Zero,  
        TimeSpan.FromMinutes(5)  
    );  
}

权衡:

  • 优点: 在现有代码库中易于实现,有效利用系统资源,无阻塞执行增强了用户体验。
  • 缺点: 仅限于支持的环境,不适合超大规模操作。async/await

何时选择:

在 C# 中使用 async 关键字可以提高应用程序的响应能力和效率,尤其是对于 I/O 绑定操作或后台处理。例如,在下订单后发送电子邮件时,它可以防止用户不必要地等待,并允许应用程序迅速进入下一步。但是,有效的实施应考虑特定于应用程序的需求和限制。

2. Background Job Scheduler (Hangfire)

Hangfire 是用于 .NET 中后台作业调度的常用库。它允许您轻松创建和管理后台作业,并与各种存储后端(如 SQL Server)无缝集成。

Hangfire 示例:

public void ConfigureServices(IServiceCollection services)  
{  
    services.AddHangfire(x => x.UseSqlServerStorage("YourConnectionString"));  
    services.AddHangfireServer();  
}  
  
public void Configure(IApplicationBuilder app, IBackgroundJobClient backgroundJobs)  
{  
    app.UseHangfireDashboard();  
    backgroundJobs.Enqueue(() => Console.WriteLine("Background job started"));  
    RecurringJob.AddOrUpdate(() => ProcessPendingRecords(), Cron.MinuteInterval(5));  
}  
public void ProcessPendingRecords()  
{  
    var records = GetPendingRecords();  
    if (records.Any())  
    {  
        ProcessRecords(records);  
        Console.WriteLine("Records processed");  
    }  
}

权衡:

  • 优点: 自动化和可靠的执行,非常适合定期任务,可扩展以适应中等数据负载。
  • 缺点: 需要其他库或工具,可能需要手动干预才能进行错误处理和恢复。

何时选择:

Hangfire 为定期任务提供自动化和可扩展性。但是,它引入了额外的依赖项,并且可能需要手动操作才能进行高级错误处理和恢复方案。

3. Windows Task Scheduler

Windows 任务计划程序允许您在指定的时间或间隔自动执行程序或脚本。此方法简单明了,可用于运行.exe文件或批处理脚本。

使用 Windows 任务计划程序的示例:

  1. 打开任务计划程序。
  2. 创建新的基本任务。
  3. 将触发器设置为“每日”并指定间隔。
  4. 将操作设置为“启动程序”,然后浏览到.exe文件或脚本。
  5. 完成并保存任务。

权衡:

  • 优点: 设置简单,无需额外编码,执行可靠。
  • 缺点: 仅限于 Windows 环境,对于复杂的作业定义不太灵活。

何时选择:

Windows 任务计划程序是在 Windows 系统上自动执行日常任务的有效选择,无需编程专业知识即可提供简单性和可靠性。但是,它可能无法满足需要跨平台兼容性或复杂作业调度功能的环境的需求。

**4. Cron Jobs **

利用 cron 作业在类 Unix 系统上调度任务是定期批处理的一种简单方法。在 .NET 上下文中,可以使用 Quartz.NET(一个功能强大且灵活的作业计划库)来实现这一点。

Quartz.NET 示例:

public class BatchJob : IJob  
{  
    public Task Execute(IJobExecutionContext context)  
    {  
        return ProcessPendingRecords();  
    }  
}  
  
public void ConfigureServices(IServiceCollection services)  
{  
    services.AddQuartz(q =>  
    {  
        q.UseMicrosoftDependencyInjectionScopedJobFactory();  
        var jobKey = new JobKey("BatchJob");  
        q.AddJob<BatchJob>(opts => opts.WithIdentity(jobKey));  
        q.AddTrigger(opts => opts  
            .ForJob(jobKey)  
            .WithIdentity("BatchJob-trigger")  
            .WithCronSchedule("0 */5 * * * ?")); // Every 5 minutes  
    });  
    services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);  
}

权衡:

  • 优点: 简单可靠,适合定期任务,非常适合类 Unix 环境。
  • 缺点: 作业定义的灵活性有限,错误处理和作业恢复方面的潜在挑战。

何时选择:

Quartz.NET with cron 作业是 .NET 环境中简单定期批处理任务的可靠选择,特别适用于类 Unix 系统。但是,在某些复杂的用例中,它可能需要额外的工作来管理错误场景,并且缺乏更高级的作业调度框架的灵活性。

5. Asynchronous Queues (Azure Service Bus)

使用 Azure 服务总线等异步消息队列是处理高吞吐量后台处理任务的绝佳方法。这些系统将任务生产者和使用者解耦,从而实现高效可靠的消息处理。

Azure 服务总线示例:Example with Azure Service Bus:

Producer:

var client = new QueueClient(connectionString, queueName);  
var message = new Message(Encoding.UTF8.GetBytes("Task data"));  
await client.SendAsync(message);  
Console.WriteLine("Sent message");

Consumer:

var client = new QueueClient(connectionString, queueName);  
client.RegisterMessageHandler(  
    async (message, token) =>  
    {  
        var data = Encoding.UTF8.GetString(message.Body);  
        await ProcessDataAsync(data);  
        await client.CompleteAsync(message.SystemProperties.LockToken);  
        Console.WriteLine("Processed message");  
    },  
    new MessageHandlerOptions(ExceptionHandler) { MaxConcurrentCalls = 1, AutoComplete = false }  
);  
  
Task ExceptionHandler(ExceptionReceivedEventArgs exceptionReceivedEventArgs)  
{  
    Console.WriteLine($"Message handler encountered an exception {exceptionReceivedEventArgs.Exception}.");  
    return Task.CompletedTask;  
}

权衡:

  • 优点: 高扩展性和可靠性,适用于分布式系统,提供容错和负载均衡。
  • 缺点: 需要设置和维护额外的基础设施,增加了系统设计的复杂性。这还需要 Azure 付费订阅。

何时选择:

Azure 服务总线,它擅长于需要分布式系统的高可伸缩性、可靠性、容错性和负载均衡的方案。这使得它对于在 Azure 本机环境中处理高吞吐量后台处理任务特别有效。但是,采用 Azure 服务总线确实需要 Azure 付费订阅,并且涉及设置和维护其他基础结构,这可能会增加系统设计的复杂性。

6. 使用 Kafka

Apache Kafka 是一个高度可扩展的分布式流式处理平台。它是构建实时数据管道和流式处理应用程序的理想选择,使您能够高效地处理高吞吐量后台处理任务。

Using Kafka:

制作人:

var config = new ProducerConfig { BootstrapServers = "localhost:9092" };  
using (var producer = new ProducerBuilder<Null, string>(config).Build())  
{  
    var result = await producer.ProduceAsync("task-topic", new Message<Null, string> { Value = "Task data" });  
    Console.WriteLine($"Sent message to {result.TopicPartitionOffset}");  
}

消费者:

var config = new ConsumerConfig  
{  
    GroupId = "task-group",  
    BootstrapServers = "localhost:9092",  
    AutoOffsetReset = AutoOffsetReset.Earliest  
};  
  
using (var consumer = new ConsumerBuilder<Ignore, string>(config).Build())  
{  
    consumer.Subscribe("task-topic");  
    while (true)  
    {  
        var consumeResult = consumer.Consume();  
        await ProcessDataAsync(consumeResult.Message.Value);  
        Console.WriteLine($"Processed message: {consumeResult.Message.Value}");  
    }  
}

权衡:

  • 优点: 扩展性高、容错性高、可靠性高,适合数据实时处理。
  • 缺点: 需要设置和维护 Kafka 基础架构,增加了系统设计的复杂性。

何时选择:

当您需要强大的可扩展性、容错能力和可靠的实时数据处理时,请选择 Kafka。它擅长处理高吞吐量数据管道和分布式流应用,非常适合需要强大数据完整性和连续数据流的场景。但是,实施 Kafka 需要仔细设置和持续维护其基础架构,这可能会给系统架构和操作带来复杂性。

7. Azure Functions

Azure Functions 是一种无服务器计算服务,可用于按需运行代码,而无需预配或管理基础结构。它非常适合由各种事件或计划触发的后台处理任务。

Azure Functions 示例:Example with Azure Functions:

public static class TimerFunction
{
    [FunctionName("TimerFunction")]
    public static async Task Run([TimerTrigger("*/5 * * * *")]TimerInfo myTimer, ILogger log)
    {
        await ProcessPendingRecordsAsync();
        log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
    }
}

权衡:

  • 优点: 无服务器且可缩放,易于设置和维护,可与各种 Azure 服务集成。
  • 缺点: 潜在的冷启动延迟,取决于 Azure 基础结构。这需要付费的 Azure 订阅。

何时选择:

Azure Functions 对于在特定时间执行精确的后台作业特别有效,尤其是在 Azure 本机环境中。但是,如果还没有 Azure 设置,则采用它们可能会带来额外的复杂性。

8. Database Triggers

数据库触发器可用于根据数据库中的特定更改或事件启动批处理任务。此方法可确保在触发事件后立即处理任务。

SQL Server 触发器示例:

CREATE TRIGGER ProcessRecordsTrigger  
ON YourTable  
AFTER INSERT, UPDATE  
AS  
BEGIN  
    -- Call your batch processing logic here  
    EXEC dbo.ProcessRecords;  
END;

权衡:

  • 优点: 即时响应数据库更改,与数据操作紧密集成。
  • 缺点: 数据库逻辑的复杂性增加,对数据库操作的潜在性能影响。

何时选择:

数据库触发器最适合需要根据更新或删除更改记录的场景,或者管理依赖记录的场景。例如,您可以使用触发器将每个已删除的清单项目记录到专用历史记录表中。

结论

后台批处理对于优化业务运营和提高系统性能至关重要。通过选择适当的方法(无论是使用关键字、后台作业计划程序、Windows 任务计划程序、cron 作业、异步队列、Kafka、Azure Functions 还是数据库触发器),企业都可以有效地管理其处理需求,并确保高效可靠的任务执行。每种方法都有其权衡取舍,因此在做出决策时必须考虑业务方案的特定要求和约束。

阅读排行