本系列文章的第一篇:使用Brighter连接和配置系统——集成Brighter与Apache Kafka
Kafka 快速介绍
Kafka 是一个用于高吞吐量、实时消息处理的分布式流式平台。核心概念包括:
- 流(Streams):逐条处理消息,吞吐量由主题分区数量限制。
- 核心组件
- 主题(Topic):消息发布的类别/订阅源。
- 分区(Partition):主题的分片,用于并行处理。
- 消费者组(Consumer Group):一组协作消费同一主题消息的消费者。
集成 Brighter 与 Kafka 所需配置:
- 主题名称:目标 Kafka 主题(例如 `greeting.topic`)。
- 分区数量:决定并发处理的限制。
- 消费者组 ID:确保消息在消费者间均匀分配。
环境要求
- .NET 8 或更高版本
- .NET 项目需引用以下 NuGet 包:
- Paramore.Brighter.MessagingGateway.Kafka:启用 Kafka 集成
- Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection:简化依赖注入
- Paramore.Brighter.ServiceActivator.Extensions.Hosting:将 Brighter 作为后台服务托管。
- Serilog.AspNetCore:结构化日志记录。
- Docker/podman:用于本地 Kafka 环境搭建。
使用 Docker/podman 搭建本地 Kafka 环境
通过以下 `docker-compose.yml` 启动 Kafka、Zookeeper 和 UI:
services:
zookeeper:
image: confluentinc/cp-zookeeper
ports:
- "2181"
environment:
ZOOKEEPER_CLIENT_PORT: 2181
kafka:
image: confluentinc/cp-kafka
depends_on:
- zookeeper
healthcheck:
test: kafka-topics --bootstrap-server kafka:29092 --list || exit 1
interval: 10s
timeout: 10s
retries: 5
ports:
- "9092:9092"
- "29092:29092"
- "9997:9997"
expose:
- "29092"
- "9092"
environment:
KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181"
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1"
KAFKA_INTER_BROKER_LISTENER_NAME: "PLAINTEXT"
KAFKA_MIN_INSYNC_REPLICAS: "1"
kafka-ui:
image: provectuslabs/kafka-ui
container_name: kafka-ui
depends_on:
- kafka
ports:
- "8088:8080"
environment:
KAFKA_CLUSTERS_0_NAME: kafka
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092
KAFKA_CLUSTERS_0_METRICS_PORT: 9997
DYNAMIC_CONFIG_ENABLED: "true"
步骤:
- 运行 `podman-compose -f docker-compose.yml up -d`(或 `docker-compose`)。
- 通过 http://localhost:8088 访问 Kafka UI。
注意:此配置使用 PLAINTEXT` 简化开发环境。生产环境应使用 SSL/SASL_SSL。
Brighter 快速回顾
在继续 Kafka 配置前,先回顾 Brighter 的核心概念:
请求(Command/Event
Brighter 使用 `IRequest` 标记需处理的对象,继承 `Command` 或 `Event`:
public class Greeting : Event(Guid.NewGuid())
{
public string Name { get; set; } = string.Empty;
}
消息映射器(Message Mapper)
在 Brighter 请求与 Kafka 消息之间进行转换:
public class GreetingMapper : IAmAMessageMapper<Greeting>
{
public Message MapToMessage(Greeting request)
{
var header = new MessageHeader();
header.Id = request.Id;
header.TimeStamp = DateTime.UtcNow;
header.Topic = "greeting.topic"; // 目标主题
header.MessageType = MessageType.MT_EVENT;
var body = new MessageBody(JsonSerializer.Serialize(request));
return new Message(header, body);
}
public Greeting MapToRequest(Message message)
{
return JsonSerializer.Deserialize<Greeting>(message.Body.Bytes)!;
}
}
请求处理器(Request Handler)
处理传入消息:
public class GreetingHandler(ILogger<GreetingHandler> logger) : RequestHandler<Greeting>
{
public override Greeting Handle(Greeting command)
{
logger.LogInformation("Hello {Name}", command.Name);
return base.Handle(command);
}
}
配置 Brighter 与 Kafka
Kafka 连接设置
var connection = new KafkaMessagingGatewayConfiguration
{
Name = "sample", // 应用名称
BootStrapServers = ["localhost:9092"], // Broker 地址
SecurityProtocol = SecurityProtocol.Plaintext, // 生产环境使用 SSL
SaslMechanisms = SaslMechanism.Plain,
SaslUsername = "admin", // SASL 认证用户名
SaslPassword = "admin-secret"
};
Kafka 消费者配置
.AddServiceActivator(opt =>
{
opt.Subscriptions =
[
new KafkaSubscription<Greeting>(
new SubscriptionName("kafka.greeting.subscription"), // 订阅名称(内部使用)
new ChannelName("greeting.topic"), // 主题名称
new RoutingKey("greeting.topic"), // 主题名称
groupId: "some-consumer-group", // 消费者组 ID
makeChannels: OnMissingChannel.Create, // 主题不存在时的处理方式
numOfPartitions: 2, // 分区数量(仅在代码中创建主题时有用)
noOfPerformers: 2, // 并行处理数量(不应超过分区数)
isAsync: false // 是否使用异步处理器
),
];
opt.ChannelFactory = new ChannelFactory(new KafkaMessageConsumerFactory(connection));
})
Kafka 生产者配置
.UseExternalBus(new KafkaProducerRegistryFactory(connection,
[
new KafkaPublication
{
MakeChannels = OnMissingChannel.Create,
NumPartitions = 2, // 分区数量(仅在代码中创建主题时有用)
Topic = new RoutingKey("greeting.topic"), // 主题名称
},
]).Create()
);
结论
将 Brighter 与 Kafka 集成可简化构建可扩展的消息驱动系统。
参考资料
完整代码:GitHub 仓库
751

被折叠的 条评论
为什么被折叠?



