BufferQueue的试用笔记
简介
BufferQueue 是一个用 .NET 编写的高性能的缓冲队列实现,支持多线程并发操作。
源码网站:https://github.com/eventhorizon-cli/BufferQueue
功能设计
-
支持创建多个 Topic,每个 Topic 可以有多种数据类型。每一对 Topic 和数据类型对应一个独立的缓冲区。
-
支持创建多个 Consumer Group,每个 Consumer Group 的消费进度都是独立的。支持多个 Consumer Group 并发消费同一个 Topic。
-
支持同一个 Consumer Group 创建多个 Consumer,以负载均衡的方式消费数据。
-
支持数据的批量消费,可以一次性获取多条数据。
-
支持 pull 模式和 push 模式两种消费模式。
-
pull 模式下和 push 模式下都支持 auto commit 和 manual commit 两种提交方式。auto commit 模式下,消费者在收到数据后自动提交消费进度,如果消费失败不会重试。manual commit 模式下,消费者需要手动提交消费进度,如果消费失败只要不提交进度就可以重试。
安装
Install-Package BufferQueue
示例代码
BufferQueue 支持两种消费模式:pull 模式和 push 模式。
builder.Services.AddBufferQueue(options =>
{
options.UseMemory(bufferOptions =>
{
// 每一对 Topic 和数据类型对应一个独立的缓冲区,可以设置 partitionNumber
bufferOptions.AddTopic<Foo>("topic-foo1", partitionNumber: 6);
bufferOptions.AddTopic<Foo>("topic-foo2", partitionNumber: 4);
bufferOptions.AddTopic<Bar>("topic-bar", partitionNumber: 8);
})
// 添加 push 模式的消费者
// 扫描指定程序集中的标记了 BufferPushCustomerAttribute 的类,
// 注册为 push 模式的消费者
.AddPushCustomers(typeof(Program).Assembly);
});
// 在 HostedService 中使用 pull模式 消费数据
builder.Services.AddHostedService<Foo1PullConsumerHostService>();
pull 模式的消费者示例:
public class Foo1PullConsumerHostService(
IBufferQueue bufferQueue,
ILogger<Foo1PullConsumerHostService> logger) : IHostedService
{
private readonly CancellationTokenSource _cancellationTokenSource = new();
public Task StartAsync(CancellationToken cancellationToken)
{
var token = CancellationTokenSource
.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token)
.Token;
var consumers = bufferQueue.CreatePullConsumers<Foo>(
new BufferPullConsumerOptions
{
TopicName = "topic-foo1", GroupName = "group-foo1", AutoCommit = true, BatchSize = 100,
}, consumerNumber: 4);
foreach (var consumer in consumers)
{
_ = ConsumeAsync(consumer, token);
}
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_cancellationTokenSource.Cancel();
return Task.CompletedTask;
}
private async Task ConsumeAsync(IBufferPullConsumer<Foo> consumer, CancellationToken cancellationToken)
{
await foreach (var buffer in consumer.ConsumeAsync(cancellationToken))
{
foreach (var foo in buffer)
{
// Process the foo
logger.LogInformation("Foo1PullConsumerHostService.ConsumeAsync: {Foo}", foo);
}
}
}
}
push 模式的消费者示例:
通过 BufferPushCustomer 特性注册 push 模式的消费者。
push consumer 会被注册到 DI 容器中,可以通过构造函数注入其他服务,可以通过设置 ServiceLifetime 来控制 consumer 的生命周期。
BufferPushCustomerAttribute 中的 concurrency 参数用于设置 push consumer 的消费并发数,对应 pull consumer 的 consumerNumber。
[BufferPushCustomer(
topicName: "topic-foo2",
groupName: "group-foo2",
batchSize: 100,
serviceLifetime: ServiceLifetime.Singleton,
concurrency: 2)]
public class Foo2PushConsumer(ILogger<Foo2PushConsumer> logger) : IBufferAutoCommitPushConsumer<Foo>
{
public Task ConsumeAsync(IEnumerable<Foo> buffer, CancellationToken cancellationToken)
{
foreach (var foo in buffer)
{
logger.LogInformation("Foo2PushConsumer.ConsumeAsync: {Foo}", foo);
}
return Task.CompletedTask;
}
}
[BufferPushCustomer(
"topic-bar",
"group-bar",
100,
ServiceLifetime.Scoped,
2)]
public class BarPushConsumer(ILogger<BarPushConsumer> logger) : IBufferManualCommitPushConsumer<Bar>
{
public async Task ConsumeAsync(IEnumerable<Bar> buffer, IBufferConsumerCommitter committer,
CancellationToken cancellationToken)
{
foreach (var bar in buffer)
{
logger.LogInformation("BarPushConsumer.ConsumeAsync: {Bar}", bar);
}
var commitTask = committer.CommitAsync();
if (!commitTask.IsCompletedSuccessfully)
{
await commitTask.AsTask();
}
}
}
Producer 示例:
通过 IBufferQueue 获取到指定的 Producer,然后调用 ProduceAsync 方法发送数据。
[ApiController]
[Route("/api/[controller]")]
public class TestController(IBufferQueue bufferQueue) : ControllerBase
{
[HttpPost("foo1")]
public async Task<IActionResult> PostFoo1([FromBody] Foo foo)
{
var producer = bufferQueue.GetProducer<Foo>("topic-foo1");
await producer.ProduceAsync(foo);
return Ok();
}
[HttpPost("foo2")]
public async Task<IActionResult> PostFoo2([FromBody] Foo foo)
{
var producer = bufferQueue.GetProducer<Foo>("topic-foo2");
await producer.ProduceAsync(foo);
return Ok();
}
[HttpPost("bar")]
public async Task<IActionResult> PostBar([FromBody] Bar bar)
{
var producer = bufferQueue.GetProducer<Bar>("topic-bar");
await producer.ProduceAsync(bar);
return Ok();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2018-08-22 C#调用Python代码
2017-08-22 NAudio的使用说明
2017-08-22 IT回忆录-2