【Kafka 消息队列深度解析与应用】

Kafka 消息队列深度解析与应用

一、Kafka 概述

(一)产生背景

  • Kafka 最初是由 LinkedIn 开发,旨在解决其内部海量数据的实时传输问题。在现代大数据环境下,企业需要处理海量的数据流入和流出,包括用户的行为数据、系统日志、业务数据等,传统的消息队列系统在处理这些大数据量、高并发的数据时,面临着诸多挑战,如性能瓶颈、扩展性差、数据一致性难以保证等。Kafka 应运而生,它为大规模数据处理和实时数据传输提供了一个高性能、高可靠的分布式消息队列解决方案。

(二)特点

1. 高吞吐量
  • Kafka 能够处理海量的数据,支持每秒百万级别的消息传输,这得益于其高效的存储和网络 I/O 设计。从源码角度来看,在 Kafka 的存储层,使用了日志追加的存储方式,将消息顺序追加到磁盘上,避免了随机写操作,减少了磁盘寻道时间。例如,在 Log 类中,append() 方法负责将消息追加到日志文件中,其实现利用了操作系统的页缓存机制,使得写入操作可以在内存中完成,之后再由操作系统将数据异步刷到磁盘,提高了写入性能。在网络 I/O 方面,通过使用 Selector 类进行网络通信,采用了非阻塞式的 I/O 操作,结合零拷贝技术(FileChannel.transferTo() 方法的使用),减少了数据在用户态和内核态之间的拷贝次数,提高了数据传输效率,使 Kafka 可以高效地处理大量并发的生产者和消费者请求。
2. 可扩展性
  • Kafka 是分布式的,通过增加 Kafka 集群中的 Broker 节点可以轻松扩展系统的存储和处理能力。在源码中,KafkaController 类负责集群的管理和协调,当新节点加入时,会触发相应的负载均衡操作,如 onBrokerStartup() 方法会根据新节点的加入重新分配分区和副本,将部分分区的数据迁移到新节点上,确保数据分布的均匀性和负载的均衡,使 Kafka 可以灵活应对数据量的增长和并发的提高。
3. 持久性
  • Kafka 会将消息持久化存储在磁盘上,这确保了消息的可靠性,即使在消息被消费后,也可以根据配置的保留时间进行存储,以备后续的分析或重新消费。LogSegment 类负责存储消息的逻辑片段,它将消息存储在磁盘上的文件中,同时会根据配置的日志段大小和保留时间对消息进行清理或滚动,保证了消息存储的有序性和持久性。
4. 高可用性
  • Kafka 通过多副本机制来保证高可用性,每个主题的分区可以有多个副本,分布在不同的 Broker 节点上。在 ReplicaManager 类中,会对副本进行管理,通过 makeFollowers() 和 makeLeaders() 等方法实现副本的角色转换,当一个 Broker 出现故障时,其副本可以继续提供服务,保证了数据的可用性。

(三)核心架构

1. 生产者(Producer)
  • 生产者负责将消息发送到 Kafka 主题中。在 KafkaProducer 类中,会使用 RecordAccumulator 类来缓存消息,根据分区策略(如轮询、按关键字等)将消息分配到不同的分区,使用 Sender 类将消息发送到相应的 Broker。生产者可以配置一些重要的参数,如 acks 用于确定消息的确认机制(表示需要多少个副本确认收到消息才认为发送成功),batch.size 用于设置消息的批次大小,linger.ms 用于设置发送消息的延迟时间,以优化发送性能。
2. 消费者(Consumer)
  • 消费者从 Kafka 主题中订阅消息。在 KafkaConsumer 类中,使用 ConsumerCoordinator 类来协调消费者组内的消费者,使用 Fetcher 类从 Broker 中拉取消息。消费者可以配置 group.id 表示其所属的消费者组,通过 subscribe() 方法订阅主题,使用 poll() 方法拉取消息,还可以使用 commitSync() 或 commitAsync() 方法来提交消费偏移量,以便在下次消费时从正确的位置开始。
3. Broker
  • Broker 是 Kafka 集群中的服务节点,负责存储和处理消息。KafkaServer 类是 Broker 的核心,它包含多个组件,如 LogManager 负责日志存储管理,ReplicaManager 负责副本管理,SocketServer 负责网络通信,KafkaApis 类处理来自生产者和消费者的请求。
4. 主题(Topic)
  • 主题是消息的类别,生产者将消息发送到特定的主题,消费者从主题中消费消息。每个主题可以划分为多个分区,分区可以分布在不同的 Broker 上,这样可以提高并行处理能力。在 TopicConfig 类中可以对主题的各种属性进行配置,如分区数量、副本数量、消息保留时间等。

(四)应用场景

  • 大数据流处理:Kafka 可以作为大数据处理的数据源,将实时的数据流(如用户的点击流、传感器数据等)发送给下游的处理系统,如 Apache Spark 或 Apache Flink。这些大数据处理系统可以通过 Kafka 的消费者 API 实时消费数据,进行数据清洗、转换和分析。例如,在实时推荐系统中,用户的行为数据通过 Kafka 持续流入,Spark Streaming 可以实时消费这些数据,为用户提供实时的推荐内容。
  • 日志收集:在分布式系统中,不同的服务可以将日志信息发送到 Kafka,通过 Kafka 作为日志收集的中央枢纽,然后再将日志发送给日志存储和分析系统(如 Elasticsearch 和 Kibana 组合)。多个服务作为生产者将日志信息发送到 Kafka 主题,日志存储和分析系统作为消费者从 Kafka 中拉取日志信息进行存储和分析,实现了日志的集中管理和分析。

二、Kafka 的安装与配置

(一)安装过程

  • 下载 Kafka 软件包:
    首先,从 Kafka 官方网站下载适合你系统的 Kafka 软件包。
  • 解压和配置文件修改:
    解压后,进入 Kafka 的配置文件目录,主要修改 server.properties 文件。需要设置 broker.id 为每个 Broker 节点分配唯一的 ID,设置 listeners 以确定 Kafka 监听的网络地址和端口,设置 log.dirs 确定日志存储的目录,设置 zookeeper.connect 来指定 ZooKeeper 的连接地址(Kafka 依赖 ZooKeeper 进行集群管理)。

详细安装过程请参考这篇文章 Kafka实战

(二)代码示例:消息的生产和消费

1. 生产者代码示例
java 复制代码
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;

public class KafkaProducerExample {
    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put("bootstrap.servers", "localhost:9092");
        properties.put("acks", "all");
        properties.put("retries", 0);
        properties.put("batch.size", 16384);
        properties.put("linger.ms", 1);
        properties.put("buffer.memory", 33554432);
        properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        Producer<String, String> producer = new KafkaProducer<>(properties);
        for (int i = 0; i < 100; i++) {
            ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", Integer.toString(i), "message " + i);
            producer.send(record);
        }
        producer.close();
    }
}

代码解释:

  • properties 中设置了生产者的各种配置,包括 bootstrap.servers 指定 Kafka 集群的地址,acks 确定消息确认机制,batch.size 决定消息的批次大小,linger.ms 决定消息的延迟发送时间,buffer.memory 是消息缓冲区的大小。

KafkaProducer 类是 Kafka 的生产者类,通过 send() 方法发送 ProducerRecord 消息,消息包含主题、键和值。这里将消息发送到 test-topic 主题,键为 i 的字符串表示,值为 message + i。

2. 消费者代码示例
java 复制代码
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Collections;
import java.util.Properties;

public class KafkaConsumerExample {
    public static void main(String[] args) {
        Properties properties = new org.apache.kafka.clients.consumer.Properties();
        properties.put("bootstrap.servers", "localhost:9092");
        properties.put("group.id", "test-group");
        properties.put("enable.auto.commit", "true");
        properties.put("auto.commit.interval.ms", "1000");
        properties.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        properties.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        Consumer<String, String> consumer = new KafkaConsumer<>(properties);
        consumer.subscribe(Collections.singletonList("test-topic"));

        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            records.forEach(record -> System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value()));
        }
    }
}

代码解释:

  • properties 中设置了消费者的各种配置,包括 bootstrap.servers 用于连接 Kafka 集群,group.id 表示消费者组的 ID,enable.auto.commit 表示是否自动提交消费偏移量,auto.commit.interval.ms 表示自动提交的时间间隔。

KafkaConsumer 类是消费者类,通过 subscribe() 方法订阅主题,使用 poll() 方法拉取消息,拉取到的消息存储在 ConsumerRecords 中,然后遍历并打印消息的偏移量、键和值。

(三)分区机制

1. 概念

分区是 Kafka对主题的进一步划分,将主题的数据分布在多个分区中,提高了并行处理能力。每个分区内的消息是有序的,但不同分区之间的消息顺序不保证。在DefaultPartitioner 类中,会根据不同的分区策略(如轮询、按消息键的哈希值等)将消息分配到不同的分区。

2. 实现原理

  • 在 ProducerRecord 中,如果没有指定分区,会使用 partitioner 类进行分区分配,例如,在 DefaultPartitioner 中,当使用轮询策略时,会根据递增的计数器将消息分配到不同分区;当使用哈希策略时,会根据消息键的哈希值对分区数取模来分配分区。

3. 性能

  • 分区可以提高 Kafka 的并行处理能力,多个生产者可以同时向不同的分区发送消息,多个消费者可以同时从不同的分区消费消息,提高了系统的吞吐量。在性能测试中,增加分区数可以在一定程度上提高系统的并发处理能力,但也会增加管理成本,过多的分区可能导致性能下降,需要根据实际情况进行调整。

(四)副本机制

1. 概念

  • 副本是为了保证数据的高可用性,每个分区可以有多个副本,分布在不同的 Broker上,其中一个是领导者(Leader),其余为跟随者(Follower)。

2. 实现原理

  • 在 ReplicaManager 类中,当消息发送到 Leader 副本时,Leader 会将消息复制给 Follower 副本,Follower 副本会不断从 Leader 副本同步消息。当 Leader 副本不可用时,会从 Follower 副本中选举出一个新的 Leader 副本。在 Partition 类中,makeLeader() 和 makeFollower() 方法负责角色的转换,确保消息的一致性和可用性。

3. 性能

  • 副本机制提高了 Kafka 的可用性,但也会增加网络和存储的开销,因为需要将消息复制到多个副本上。不过,在实际使用中,合理设置副本数可以在性能和可用性之间取得平衡,一般副本数为 2 或 3 比较常见。
    (五)消息的顺序性和高可用性
1. 消息顺序性
  • 在同一个分区内,Kafka 可以保证消息的顺序性,因为消息是按顺序追加存储的。生产者发送消息时,尽量将有顺序要求的消息发送到同一个分区,例如,在日志收集场景中,同一个服务的日志可以发送到同一个分区,保证日志的时间顺序。
  • 从源码角度,在 RecordBatch 类中,会将同一批次的消息存储在一个逻辑单元中,在发送到分区时会按顺序存储,保证了分区内消息的顺序性。
2. 高可用性
  • 高可用性通过副本机制、Broker 的故障转移和 ZooKeeper 的协调来保证。当 Broker 出现故障时,ZooKeeper 会通知 Kafka 集群,Kafka 会从 Follower 副本中选举新的 Leader,在 KafkaController 类中,onBrokerFailure() 方法会触发故障处理流程,确保服务的正常运行。

三、Kafka 的性能优化

(一)调整参数

1. 生产者参数优化
batch.size 和 linger.ms
  • 增大 batch.size 可以将更多的消息打包成批次发送,减少网络请求次数,提高网络 I/O 效率;增加 linger.ms 可以延迟发送消息,让生产者有更多的时间收集消息形成批次。但如果设置过大,会增加消息的延迟,需要根据消息的流量和实时性要求进行调整。在 RecordAccumulator 类中,会根据这些参数来决定何时发送消息批次。
acks 和 retries:
  • acks 决定了消息发送的确认机制,设置为 all 可以保证消息的可靠性,但会增加发送延迟,可根据对消息可靠性的要求进行调整;retries 决定了发送失败时的重试次数,可根据网络状况和服务器的稳定性设置。
2. 消费者参数优化
fetch.min.bytes 和 fetch.max.wait.ms
  • fetch.min.bytes 规定了消费者每次拉取的最小字节数,fetch.max.wait.ms 规定了消费者拉取消息的最大等待时间,合理设置可以提高消费者的拉取效率。在 Fetcher 类中,会根据这些参数来拉取消息,平衡消息的延迟和吞吐量。
3. Broker 参数优化
num.io.threads 和 num.replica.fetchers:
  • num.io.threads 决定了 Broker 处理网络 I/O 请求的线程数量,num.replica.fetchers 决定了副本同步的线程数量,根据服务器的 CPU 核心数和负载,可以调整这些参数以优化性能。在 KafkaServer 类中,会根据这些参数启动相应的线程。

(二)优化网络

  • 调整网络缓冲区:
    可以调整 Kafka 的网络缓冲区大小,在 SocketServer 类中,通过设置 socket.send.buffer.bytes 和 socket.receive.buffer.bytes 来优化网络发送和接收缓冲区的大小,提高网络传输效率。
  • 使用压缩:
    可以使用压缩算法(如 GZIP、Snappy 等)对消息进行压缩,在 ProducerConfig 中设置 compression.type 参数,减少网络传输的数据量,提高性能。

(三)与其他大数据组件的集成

1. 与 Spark 的集成

可以使用 Spark Streaming 从 Kafka 中消费数据,以下是一个简单的代码示例:

java 复制代码
import org.apache.spark.SparkConf;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka010.ConsumerStrategies;
import org.apache.spark.streaming.kafka010.KafkaUtils;
import org.apache.spark.streaming.kafka010.LocationStrategies;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class SparkKafkaIntegration {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("SparkKafkaIntegration").setMaster("local[2]");
        JavaStreamingContext jssc = new JavaStreamingContext(conf, Durations.seconds(1));

        Map<String, Object> kafkaParams = new HashMap<>();
        kafkaParams.put("bootstrap.servers", "localhost:9092");
        kafkaParams.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        kafkaParams.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        kafkaParams.put("group.id", "spark-group");
        kafkaParams.put("auto.offset.reset", "latest");
        kafkaParams.put("enable.auto.commit", false);

        JavaDStream<String> stream = KafkaUtils.createDirectStream(
                jssc,
                LocationStrategies.PreferConsistent(),
                ConsumerStrategies.Subscribe(Collections.singletonList("test-topic"), kafkaParams)
        ).map(record -> record.value());

        stream.foreachRDD(rdd -> {
            rdd.foreach(record -> {
                // 在这里对从 Kafka 中获取的数据进行处理,例如打印或其他计算操作
                System.out.println(record);
            });
        });

        jssc.start();
        try {
            jssc.awaitTermination();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

代码解释:

  • SparkConf 用于配置 Spark 应用程序,这里设置了应用程序名称和运行模式(local[2] 表示本地模式,使用 2 个线程)。
  • JavaStreamingContext 是 Spark Streaming 的上下文,设置了批处理的时间间隔为 1 秒。
  • kafkaParams 包含了连接 Kafka 所需的参数,如 Kafka 集群地址、键和值的反序列化器、消费者组 ID 等。
  • KafkaUtils.createDirectStream 方法创建了一个直接从 Kafka 接收数据的流,使用LocationStrategies.PreferConsistent() 表示数据在可用执行器之间均匀分配,使用 ConsumerStrategies.Subscribe 方法订阅 test-topic 主题。
  • map 操作将从 Kafka 获取的 ConsumerRecord 转换为消息的值。
  • foreachRDD 操作在每个 RDD 上执行操作,这里简单地将消息打印出来。
2. 与 Fluentd 的集成

Fluentd 是一个日志收集工具,可以将收集到的日志发送给 Kafka。

首先需要在 Fluentd 的配置文件中添加 Kafka 的输出插件,如下是一个简单的配置示例:

lua 复制代码
<source>
  @type forward
  port 24224
</source>

<match kafka.**>
  @type kafka
  brokers localhost:9092
  topic_key topic
  default_topic logs
  output_data_type json
  required_acks 1
  <buffer>
    flush_interval 5s
  </buffer>
</match>

解释:

  • 部分配置了 Fluentd 接收日志的源,这里使用 forward 类型接收来自其他服务的日志。
  • <match kafka.**> 部分配置了将日志发送到 Kafka,指定了 Kafka 的 brokers 地址,default_topic 为 logs,表示将日志发送到 logs 主题,output_data_type 为 json 表示日志以 JSON 格式发送,required_acks 表示消息的确认机制, 部分设置了消息的刷新间隔。

四、实际项目案例演示 Kafka 在大规模数据处理场景中的应用

(一)案例背景

假设我们有一个大型电商平台,需要处理大量的用户行为数据,包括用户的浏览、点击、购买等行为。这些数据需要实时处理和分析,以便为用户提供个性化推荐、统计分析等功能。

(二)架构设计

  • 数据采集:在电商平台的各个服务中,使用 Kafka 的生产者将用户行为数据发送到 Kafka 的 user-behavior 主题,根据用户的 ID 或行为类型将数据发送到不同的分区,以保证同一用户或同一类型的行为数据在同一分区内,保证数据的局部顺序性。
  • 数据处理:使用 Spark Streaming 从 Kafka 中消费数据,将数据进行清洗、转换和分析。对于用户的浏览数据,可以计算用户的浏览偏好;对于购买数据,可以更新库存和统计销售额等。
  • 数据存储和展示:处理后的数据存储在数据库(如 HBase 或 Cassandra)中,同时使用可视化工具(如 Grafana)展示统计结果。

(三)代码示例

1. 生产者(在电商服务中)
java 复制代码
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;

public class EcommerceProducer {
    private static final String TOPIC = "user-behavior";
    private Producer<String, String> producer;

    public EcommerceProducer() {
        Properties properties = new Properties();
        properties.put("bootstrap.servers", "kafka-broker1:9092,kafka-broker2:9092");
        properties.put("acks", "all");
        properties.put("retries", 0);
        properties.put("batch.size", 16384);
        properties.put("linger.ms", 1);
        properties.put("buffer.memory", 33554432);
        properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        producer = new KafkaProducer<>(properties);
    }

    public void sendUserBehavior(String userId, String behavior, String data) {
        String key = userId; 
        String value = behavior + ":" + data;
        ProducerRecord<String, String> record = new ProducerRecord<>(TOPIC, key, value);
        producer.send(record);
    }

    public void close() {
        producer.close();
    }
}

代码解释:

该生产者类将用户行为数据发送到 user-behavior 主题,根据用户 ID 作为键,将用户行为和相关数据作为值发送消息。

配置参数同之前的生产者示例,确保消息的可靠性和发送性能。

2. 消费者(Spark Streaming)
java 复制代码
import org.apache.spark.SparkConf;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka010.ConsumerStrategies;
import org.apache.spark.streaming.kafka010.KafkaUtils;
import org.apache.spark.streaming.kafka010.LocationStrategies;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class EcommerceConsumer {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("EcommerceConsumer").setMaster("local[4]");
        JavaStreamingContext jssc = new JavaStreamingContext(conf, Durations.seconds(5));

        Map<String, Object> kafkaParams = new HashMap<>();
        kafkaParams.put("bootstrap.servers", "kafka-broker1:9092,kafka-broker2:9092");
        kafkaParams.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        kafkaParams.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        kafkaParams.put("group.id", "ecommerce-group");
        kafkaParams.put("auto.offset.reset", "latest");
        kafkaParams.put("enable.auto.commit", false);

        JavaDStream<String> stream = KafkaUtils.createDirectStream(
                jssc,
                LocationStrategies.PreferConsistent(),
                ConsumerStrategies.Subscribe(Collections.singletonList("user-behavior"), kafkaParams)
        ).map(record -> record.value());

        stream.foreachRDD(rdd -> {
            rdd.foreachPartition(partition -> {
                while (partition.hasNext()) {
                    String behaviorData = partition.next();
                    // 对用户行为数据进行处理,例如解析数据,进行统计分析等
                    processBehaviorData(behaviorData);
                }
            });
        });

        jssc.start();
        try {
            jssc.awaitTermination();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void processBehaviorData(String behaviorData) {
        // 这里可以根据具体业务需求进行数据的处理,例如解析数据,更新库存,计算用户偏好等
        System.out.println("Processing behavior data: " + behaviorData);
    }
}

代码解释:

  • EcommerceConsumer 从 user-behavior 主题中消费数据,使用 Spark Streaming 进行处理。
  • kafkaParams 包含了连接 Kafka 的参数,包括集群地址、反序列化器、消费者组等。
  • KafkaUtils.createDirectStream 创建了直接从 Kafka 接收数据的流,订阅了 user-behavior 主题。
  • foreachRDD 操作在每个 RDD 上进行处理,这里使用 foreachPartition 对每个分区的数据进行处理,processBehaviorData 方法可以根据具体业务需求进行用户行为数据的处理,如解析数据、更新库存、计算用户偏好等。

(四)性能优化和测试

性能测试:
  • 使用 JMeter 等工具模拟大量的用户行为数据发送,测试 Kafka 的生产者性能,观察消息发送的延迟和吞吐量。使用 Spark 的性能测试工具测试 Spark Streaming 的处理性能,观察数据处理的延迟和吞吐量。
性能优化:
  • 根据测试结果调整 Kafka 的生产者和消费者参数,如增加 batch.size 或 linger.ms 提高生产者性能,调整 fetch.min.bytes 等参数提高消费者性能。
  • 调整 Spark 的参数,如增加 spark.executor.instances 和 spark.executor.cores 提高 Spark 的处理能力。
(五)总结

通过上述的架构设计和代码实现,我们展示了 Kafka 在大规模数据处理场景中的应用。Kafka 作为一个强大的消息队列系统,通过其高吞吐量、可扩展性、高可用性等特点,结合 Spark 等大数据处理组件,可以有效地处理海量的实时数据。在实际应用中,需要根据具体的业务需求和性能测试结果,不断优化 Kafka 的参数和与其他组件的集成方式,以达到最佳的性能和数据处理效果。同时,需要关注 Kafka 的核心架构,如分区机制、副本机制,以保证数据的顺序性和可用性。

相关资料已更新

关注公众号:搜 架构研究站,回复:资料领取,即可获取全部面试题以及1000+份学习资料

相关推荐
Lee川4 小时前
深度拆解:基于面向对象思维的“就地编辑”组件全模块解析
javascript·架构
勤劳打代码4 小时前
Flutter 架构日记 — 状态管理
flutter·架构·前端框架
子兮曰10 小时前
后端字段又改了?我撸了一个 BFF 数据适配器,从此再也不怕接口“屎山”!
前端·javascript·架构
卓卓不是桌桌12 小时前
如何优雅地处理 iframe 跨域通信?这是我的开源方案
javascript·架构
Qlly12 小时前
DDD 架构为什么适合 MCP Server 开发?
人工智能·后端·架构
用户881586910911 天前
AI Agent 协作系统架构设计与实践
架构
鹏北海1 天前
Qiankun 微前端实战踩坑历程
前端·架构
货拉拉技术1 天前
货拉拉海豚平台-大模型推理加速工程化实践
人工智能·后端·架构
茶杯梦轩2 天前
从零起步学习RabbitMQ || 第三章:RabbitMQ的生产者、Broker、消费者如何保证消息不丢失(可靠性)详解
分布式·后端·面试
IvanCodes2 天前
一、消息队列理论基础与Kafka架构价值解析
大数据·后端·kafka