Java 开发面试题精选:Kafka 一篇全搞定

前言

在Java开发工程师面试中,特别是涉及到Apache Kafka的部分,面试官可能会从基础知识、架构理解、实际应用、故障排查和性能优化等多个维度来考察您的能力。这篇文章会将一些大概率被问到的面试题目梳理出来,并且告诉应该怎么回答它,不管你求职者在准备面试,还是面试官在准备招聘,这篇文章都非常值得一读,感觉还不错,别忘了收藏起来,以防迷路找不到。

核心内容

这篇文章的核心内容涵盖了Kafka的核心知识点,并且能够较好地评估候选人对于Kafka技术的掌握程度,从理论基础到实际应用,再到性能优化和故障处理能力。希望你在阅读这篇文章的同时,能够结合自己的实际工作经验和项目案例来理解,这样更能在面试的时候体现出你的实战能力,且忌死记硬背。

  • Kafka的基础知识与概念;
  • Kafka的架构与设计;
  • Kafka的消费者与生产者;
  • Kafka的性能与优化;
  • Kafka的故障排查与安全性;

基础知识与概念

简要介绍Apache Kafka是什么,它的主要用途是什么?

Apache Kafka是一个开源的分布式事件流平台,最初由LinkedIn公司开发,现为Apache软件基金会的顶级项目。Kafka的设计初衷是作为一个高性能的实时数据处理与传输系统,特别适用于构建实时数据管道和流式应用。它支持发布-订阅模式的消息传递,允许消息生产者发布消息到不同的主题(Topics)上,而多个消息消费者可以按照自己的需求订阅这些主题来接收消息。

Kafka的主要用途包括但不限于:

  • 大数据实时处理:由于其高吞吐量和低延迟的特性,Kafka常被用于实时数据流处理场景,作为数据源接入层,对接各种数据处理框架如Apache Storm、Spark Streaming或Flink,用于实时分析和处理海量数据流。
  • 日志聚合与传输:Kafka能够高效收集应用程序日志,作为集中式日志系统,为日志分析和监控提供数据源,支持如ELK Stack(Elasticsearch, Logstash, Kibana)的日志处理流程。
  • 消息队列与微服务集成:在分布式系统和微服务架构中,Kafka作为消息中间件,实现服务间的异步解耦通信,提高系统的可扩展性和容错性。
  • 网站活动追踪与用户行为分析:通过捕获并处理用户在网站上的点击流数据,为个性化推荐、用户行为分析等提供数据支持。
  • 数据集成:Kafka可以作为不同数据存储和处理系统之间的桥梁,实现数据的实时同步和迁移,支持数据湖、数据仓库的构建与维护。

总的来说,Kafka的核心价值在于提供了一种高效、可扩展、耐用的实时数据流处理基础设施,广泛应用于大数据、实时分析、日志处理、消息传递等众多现代数据密集型应用领域。

解释一下Kafka中的Producer、Broker、Consumer以及Topic的概念?

在Apache Kafka中,几个核心概念构成了其基础架构模型,分别是Producer(生产者)、Broker(代理服务器)、Consumer(消费者)以及Topic(主题)。这些组件共同工作,使得Kafka能够高效、可靠地处理大规模的消息流,支持高吞吐量、低延迟的数据处理场景。

  • Producer(生产者):生产者是向Kafka集群发布消息的应用程序。它们负责将消息发送到指定的Topic中。生产者可以选择将消息发送到特定的Partition(分区),或者让Kafka根据内置的分区策略(如轮询、哈希等)来决定。生产者还可以设置消息的传递保证级别,比如最多一次、至少一次或精确一次,以适应不同的业务需求。
  • Broker(代理服务器):Broker是Kafka集群中的一个服务器节点,负责存储和转发消息。每个Broker都可以管理多个Topic的多个分区。Brokers构成了Kafka集群的基础,它们保存所有消息数据,并处理来自生产者的消息发布请求以及消费者的拉取消息请求。Kafka的高可用性设计依赖于多个Broker组成的集群,即使部分Broker发生故障,系统仍能继续运行。
  • Consumer(消费者):消费者是应用程序的一部分,用于从Kafka中读取消息并进行处理。消费者通过订阅Topic来获取消息。Kafka支持两种类型的消费者组(Consumer Group)模式:一种是每个消费者实例独立处理全部消息(独占消费);另一种是多个消费者实例组成一个组,每个分区的消息只被该组内的一个消费者消费(分区共享消费),这是更常见的使用方式,它允许实现消息的并行处理和负载均衡。
  • Topic(主题):Topic是Kafka中消息的逻辑分类或通道名称。每个发布到Kafka的消息都属于一个特定的Topic。Topic可以看作是消息的分类标签,生产者向Topic发送消息,而消费者则订阅这些Topic来接收消息。为了实现水平扩展和提高并发处理能力,每个Topic可以被划分为多个Partition(分区),这些分区分布在不同的Broker上。

Kafka的消息是如何保证顺序性的?

Kafka在设计上通过以下几个关键机制来保证消息的顺序性:

  • 分区(Partitions):Kafka中的每个Topic可以被划分为多个Partition。消息在写入时,会根据分区规则(如基于键的哈希值)分配到特定的Partition中。由于每个Partition内部的消息是有序的(按顺序追加写入),只要生产者发送到同一Partition的消息,Kafka就能保证这些消息的顺序。因此,如果需要全局顺序,可以设计系统使所有相关消息仅发布到单个Partition中。
  • 单生产者到单Partition:当只有一个生产者向一个特定的Partition写入消息时,因为这个Partition内部的消息是严格有序的,所以消息的顺序性自然得到保证。生产者应该控制消息的发送顺序,以确保相同逻辑单元的消息被一起发送。
  • 同步发送:Kafka生产者可以通过配置消息发送确认模式为acks=all来确保消息被写入所有 ISR(In-Sync Replicas)之前,生产者不会认为消息发送成功。这种方式虽然牺牲了部分吞吐量,但增强了消息的持久性和顺序性。
  • 消息偏移量(Offsets):Kafka中的每个消息都有一个唯一的偏移量,该偏移量在每个Partition内是连续且递增的,消费者通过维护自己读取的偏移量来记录消费进度。消费者按照偏移量顺序读取消息,从而保持消息的消费顺序。

需要注意的是,虽然Kafka可以在单个Partition级别保证消息顺序,但在多Partition或跨Partition的场景下,全局顺序只能通过设计上的限制(如单一Partition策略)来间接实现。因此,在设计Kafka应用时,明确消息顺序的需求并据此选择合适的分区策略至关重要。

Kafka中的消息是如何存储的?

在Kafka中,消息是以高度优化的日志形式存储在磁盘上的。每个Topic被分成多个Partition,每个Partition都是一个有序的、不可变的消息序列,这些消息序列被进一步细分为多个Log Segments来管理。

Log Segments

Log Segments是Kafka存储机制的核心组件之一,它们是用来物理存储消息的文件。每个Partition由多个Log Segments组成,每个Segment包含一个.log文件用于存储消息数据,以及一个可选的.index文件用于快速查找消息。.log文件中存储的是实际的消息内容,而.index文件则存储了消息的偏移量到文件位置的映射,以便快速定位消息。

  • Segment命名与滚动:Log Segments通过其起始偏移量命名(例如,00000000000000000000.log),当达到预设的大小(如1GB)或时间阈值(如7天)时,当前活跃的Segment会被关闭,并开启一个新的Segment来接收新的消息,这样可以避免单个文件过大导致的性能问题。
  • 删除策略:Kafka会根据配置的保留策略(如基于时间或大小)定期删除旧的Segment以释放磁盘空间。这种机制允许Kafka在有限的存储资源下保持较高的消息持久性。

Offset

Offset是Kafka中用于标识每条消息在Partition中唯一位置的数字。每个Partition的偏移量都是从0开始递增的,每个新的消息都会获得比前一个消息更高的偏移量。

  1. 消费者跟踪:消费者使用Offset来记录它在每个Partition中已经读取到的位置。消费者可以自己管理Offset(比如存储在外部数据库中),也可以利用Kafka自带的Offset管理机制(默认存储在__consumer_offsets Topic中)。
  2. 顺序保证:通过Offset,Kafka能够保证在同一个Partition内部消息的顺序性。消费者可以根据Offset顺序读取消息,确保消息按照生产时的顺序被处理。

总的来说,Kafka通过Log Segments高效地在磁盘上存储大量消息,同时利用Offset机制维持消息的顺序和消费者的消费进度,实现了既高效又灵活的消息存储和消费模型。

解释Kafka的高可用性和分区(Partitions)机制?

Kafka的高可用性和分区机制是其设计中两个核心的特性,它们共同确保了消息的可靠传递、系统的扩展性和数据处理的灵活性。

高可用性

Kafka的高可用性主要通过以下几个方面实现:

  • 副本机制:每个Partition在Kafka集群中都有多个副本(Replicas),默认配置通常为3。这些副本分布在不同的Broker上,以此来防止单点故障。当某个Broker失效时,Kafka可以自动将领导权(Leader)转移到其他副本上,确保消息的持续可访问性。
  • ISR列表:In-Sync Replicas(ISR)列表维护了一个分区的当前活跃副本集,这些副本与Leader保持同步,即它们落后Leader不超过一定配置的偏移量。只有ISR列表中的副本才有资格成为新的Leader,这确保了数据的一致性和完整性。
  • 控制器Broker:Kafka集群中有一个特殊的Broker称为控制器(Controller),它负责管理集群的元数据,比如Partition的分配、副本状态的管理等。当集群状态变化时,控制器会触发必要的Rebalance操作,以维护系统的稳定性和可用性。

分区(Partitions)机制

  • 数据并行处理:每个Topic可以被划分为多个Partition,每个Partition都是有序且不可变的消息队列。通过分区,Kafka能够并行处理消息,提高了系统的吞吐量和处理能力。
  • 负载均衡:分区分布在不同的Broker上,这不仅增加了系统的可扩展性,还能实现负载均衡。随着数据量的增长,只需添加更多的Broker即可水平扩展系统。
  • 消息顺序性:虽然整个Topic的消息全局顺序不能保证,但每个Partition内部的消息是有序的。生产者可以选择基于消息键(Key)将消息发送到特定的Partition,以此来保证特定Key的消息顺序。
  • 高可用性支持:每个Partition的多个副本提供了数据冗余,确保了即使某个Broker发生故障,消息仍然可以从其他副本中读取,从而增强了系统的高可用性。

总的来说,Kafka的高可用性设计确保了即使在硬件故障或网络问题的情况下也能持续提供服务,而分区机制则在保证数据处理的顺序性和一致性的同时,提供了水平扩展的能力,使得Kafka成为许多大规模数据处理场景的理想选择。

架构与设计

Kafka集群是如何工作的?如何设计一个高可用的Kafka集群?

Kafka集群的工作原理

Kafka集群是由一组被称为Broker的服务器节点组成,这些节点共同协作来处理消息的发布和订阅。Kafka的工作流程大致可以概括为以下几个步骤:

  • 生产者发送消息:生产者应用程序将消息发送到指定的Topic。Kafka集群根据预定义的分区策略(如轮询、随机或基于消息键的哈希)将消息分配到该Topic的不同Partition中。
  • Broker存储消息:每个Broker负责一部分Partition,将接收到的消息追加到相应的Partition日志中。每个Partition是一个有序的、不可变的消息队列,且被分割成多个Log Segment存储在硬盘上。
  • 消费者订阅和消费消息:消费者通过订阅Topic来消费消息。消费者可以属于不同的消费者组,同一个组内的消费者通过协调避免重复消费(即每个Partition的消息只会被组内的一个消费者消费),不同组则可以独立消费全部消息。
  • 副本和故障转移:每个Partition有多个副本,其中一个是Leader,其余为Follower。Leader负责处理所有的读写请求,Follower则同步Leader的数据。当Leader故障时,Kafka会自动从ISR列表中选择一个新的Leader以保证服务连续性。

设计高可用的Kafka集群

要设计一个高可用的Kafka集群,需要考虑以下关键要素:

  • 多Broker部署:至少部署三个或更多Broker以确保即使部分Broker失败,集群仍然可以正常运行。增加Broker数量可以提高系统的整体容量和容错性。
  • 合理分区:正确配置Topic的分区数,以平衡吞吐量和负载。分区数量应该足够大以支持所需的吞吐量,但也不能过多,以免增加管理和协调的复杂度。
  • 副本策略:为每个Topic的Partition设置合适的副本因子(replication.factor),一般建议至少为3。这保证了即使有Broker故障,数据也不会丢失,并且服务可以迅速恢复。
  • ISR管理:通过调整min.insync.replicas配置,确保消息至少被ISR列表中的一定数量的副本确认才认为是已提交,这样可以在数据一致性和可用性之间找到平衡。
  • 监控与告警:实施有效的监控和告警系统,跟踪Broker的健康状态、磁盘使用情况、 ISR状态变化等,及时发现并响应潜在问题。
  • 硬件和网络冗余:确保所有Broker部署在不同的物理机器上,使用高质量的网络连接,并考虑使用冗余的网络设备来减少单点故障。
  • Zookeeper配置:Kafka依赖Zookeeper进行元数据管理,因此也需要确保Zookeeper集群本身的高可用性,通常也是通过部署奇数个节点的集群来实现。

通过上述策略,可以构建出一个能够承受各种故障、保证消息不丢失、且能持续提供服务的高可用Kafka集群。

Kafka中的副本(Replication)是如何实现的?它如何保证数据不丢失?

Kafka中的副本(Replication)机制是其高可用性和数据持久性的重要组成部分,它通过在多个Broker上维护每条消息的多个副本,确保即使某个Broker发生故障,消息也不会丢失。以下是副本机制的实现细节及其如何保证数据不丢失的概述:

副本实现

  • 分区副本:在Kafka中,每个Topic被划分为多个Partition,每个Partition都有一个或多个副本。这些副本分布在不同的Broker上,形成数据冗余,以提高系统的可靠性和容错性。
  • Leader与Follower:在每个Partition的多个副本中,有一个被选举为Leader副本,其余的是Follower副本。Leader副本负责处理所有的读写请求,而Follower副本则从Leader副本同步数据以保持与Leader的数据一致。
  • ISR列表:In-Sync Replicas (ISR) 是一个动态维护的集合,包含了与Leader副本保持同步的Follower副本。Kafka通过检查Follower副本与Leader副本之间的滞后程度(由replica.lag.time.max.ms和replica.lag.max.messages配置控制),来确定哪些Follower副本处于ISR中。只有ISR内的副本才被认为是“活”的,有资格在Leader故障时接管并成为新的Leader。

数据不丢失保证

  • 生产者确认策略:生产者在发送消息时可以配置确认策略(如acks),如acks=all意味着消息必须被所有ISR列表中的副本确认接收后,才会被认为发送成功。这种策略确保了即使Leader在确认后立即失败,至少还有一个Follower拥有这条消息,从而避免了数据丢失。
  • 副本故障处理:当Leader副本所在Broker发生故障时,Kafka会从ISR列表中选举一个新的Leader,由于ISR内的副本都与原Leader保持同步,新Leader能立即提供服务,保证数据的连续性。
  • 最小ISR配置:通过配置min.insync.replicas参数,可以设定消息被确认的最少副本数。这意味着只有当消息被至少这么多副本确认后,才会被标记为已提交,从而在系统层面确保了数据的持久性。
  • 副本恢复与重新同步:当一个Follower副本由于各种原因暂时脱离ISR(如网络波动、长时间未同步),Kafka会在条件允许时尝试将其重新同步到最新的数据状态,确保数据的最终一致性。

总的来说,通过上述机制,Kafka不仅保证了消息的高可用性,也确保了在面对单点故障时数据不会丢失,从而满足了大部分应用场景对数据可靠性的要求。

解释一下Kafka的ISR(In-Sync Replica)列表及其重要性?

在Apache Kafka中,ISR(In-Sync Replica)列表是每个Partition的一个重要概念,它代表了一组与Leader副本保持同步的Follower副本集合。这个列表对于理解Kafka的复制机制、数据一致性和高可用性策略至关重要。

ISR的构成与更新

  1. 构成:当一个Partition的Leader接收一条消息并写入其本地日志后,Follower副本开始从Leader复制这些消息。那些能够及时跟随Leader更新,并且其落后于Leader的距离在可接受范围内的Follower副本,会被加入到ISR列表中。
  2. 更新机制:ISR列表不是静态不变的,而是动态调整的。Kafka通过监控每个Follower副本的复制进度和延迟来维护ISR。如果Follower副本落后太多(超过replica.lag.time.max.ms或replica.lag.max.messages配置的限制),它会被移出ISR列表。相反,如果一个Follower副本赶上了Leader,并且其复制延迟在可接受范围内,它会被重新加入到ISR中。

ISR的重要性

  1. 数据一致性和可靠性:ISR机制确保了消息至少被ISR列表中的所有副本确认接收,这在一定程度上保证了消息的持久性和一致性。当生产者配置acks=all时,消息只有在被ISR中所有副本确认后才会被认为已提交,从而降低了数据丢失的风险。
  2. 故障恢复速度:当Leader副本发生故障时,Kafka会从ISR列表中选择一个新的Leader。因为ISR中的副本已经几乎与原Leader同步,所以新的Leader可以迅速接管并继续服务,大大缩短了故障恢复的时间,提升了系统的可用性。
  3. 控制数据延迟:通过调节ISR列表的大小,可以在数据一致性与延迟之间找到平衡。较大的ISR列表意味着更多的副本需要等待确认,可能增加消息的总延迟;较小的ISR列表则可以更快地确认消息,但降低了数据的持久性保证。
  4. 资源与性能管理:ISR列表也是资源管理和性能优化的一个工具。通过监控哪些副本频繁进出ISR,可以识别出网络不稳定或性能较低的Broker,进而采取措施优化集群性能。

总的来说,ISR列表是Kafka复制机制的核心组成部分,它直接影响着数据的一致性、系统的高可用性和消息的延迟,是设计和运维Kafka集群时需要重点关注的指标之一。

Kafka支持的几种消息传递语义有哪些?

Kafka支持多种消息传递语义,主要涉及消息的可靠性和重复处理问题。在不同的应用场景中,开发者可以根据业务需求选择最合适的语义来平衡消息的可靠性和性能。以下是Kafka中常见的几种消息传递语义:

  1. At-Least-Once(至少一次):
  • 这是最基本的可靠性保证,意味着每条消息至少会被处理一次,但可能在某些情况下被处理多次。
  • 实现这一语义通常通过设置生产者的acks参数为acks=1或acks=all,确保消息至少被一个副本或所有ISR副本确认。然而,如果消息在被确认后、但在消费者确认消费之前Broker发生故障,消息可能会在恢复后被再次发送给消费者。
  • At-Least-Once适合于能够容忍重复处理且更重视消息不丢失的场景。
  1. At-Most-Once(至多一次):
  • 这种语义下,每条消息最多被处理一次,但也可能因为网络错误等原因根本没有被处理。
  • 实现At-Most-Once通常通过设置生产者的acks参数为acks=0,即消息发送后不等待任何确认就认为发送成功,这种方式速度最快但牺牲了可靠性。
  • 适用于对消息丢失不敏感或能够通过其他机制补充丢失消息的场景。
  1. Exactly-Once(精确一次):
  • 这是最强的保证,每条消息恰好被处理一次,无论发生何种故障。
  • Kafka从0.11版本开始引入了幂等性生产者和事务支持,使得在特定条件下可以实现Exactly-Once语义。幂等性生产者确保了相同的消息(基于相同的键和分区)被发送多次,Broker也只会处理一次。
  • 而事务机制则允许一系列消息操作(生产或消费)要么全部成功要么全部失败,从而在跨Partition或跨Topic的操作中实现端到端的Exactly-Once。
  • Exactly-Once适用于对数据准确性和一致性要求极高的场景,如金融交易、计费系统等,但可能牺牲一定的性能。

如何在Kafka中实现消息的持久化和缓存策略?

在Apache Kafka中,消息的持久化和缓存策略是通过精心设计的架构和配置选项来实现的,以确保消息的可靠存储和高效访问。下面详细介绍这些策略的实施方法:

消息持久化

  • 日志分段(Log Segmentation):Kafka将每个Partition的数据分成多个日志段(Log Segments),每个段包含一个.log文件存储消息数据和一个可选的.index文件帮助快速定位消息。当一个日志段达到预设的大小或时间限制时,Kafka会关闭当前段并开始一个新的日志段。这种机制允许旧的日志段在达到保留策略后被清理,从而管理磁盘空间。
  • 副本机制(Replication):通过配置Partition的副本数量,Kafka可以在多个Broker之间复制数据,提高消息的持久性和可用性。每个Partition有一个Leader副本负责读写操作,其它Follower副本异步地从Leader同步数据。当Leader失败时,一个Follower会被提升为新的Leader,确保服务不中断。
  • 日志清理策略(Log Retention Policy):Kafka支持两种日志清理策略:“删除”(delete)和“压缩”(compact)。删除策略基于时间和/或大小删除旧消息,而压缩策略则是为了维护每个键的最新消息,常用于事件流处理场景。这些策略通过log.cleanup.policy配置项设置。

缓存策略

虽然Kafka本身没有直接的内存缓存机制,但它利用了操作系统的Page Cache(文件系统缓存)来加速读取操作:

  • Page Cache利用:Kafka的顺序写磁盘和批量读取模式天然适合于利用Page Cache。操作系统会自动缓存频繁访问的文件数据到内存中,因此即使消息存储在磁盘上,连续的读取也能实现接近内存的速度。
  • 生产者缓冲(Producer Buffering):生产者客户端可以通过配置buffer.memory参数设置缓冲区大小,积累消息后再批量发送,减少了网络交互次数,提高了发送效率,同时也是一种缓存策略。
  • 消费者端缓存:虽然Kafka不直接管理消费者端缓存,但消费者可以实现自己的缓存策略,比如利用Kafka的offset管理机制来控制消息的消费进度,或者在应用层缓存最近消费的消息以供重试或重放。

综合策略

实现有效的持久化和缓存策略,还需要考虑以下方面:

  • 监控与调优: 定期监控集群的性能指标,如磁盘使用率、I/O吞吐量等,并根据业务需求调整配置参数,如日志段大小、副本数量、保留策略等。

  • 资源规划: 确保Kafka集群有足够的磁盘空间和内存资源来支撑消息的持久化和缓存需求。

  • 生产者与消费者优化配置: 合理配置生产者和消费者的参数,如批次大小、发送确认模式、拉取消息频率等,以优化整体的性能和可靠性。

  • Broker 优化配置:合理配置 Broker 和 Topic 的参数,如日志段文件大小(log.segment.bytes)、日志清理策略的详细参数(如log.retention.hours、log.retention.bytes),以及消息确认策略(acks),以满足特定的持久性和性能需求。

消费者与生产者

Kafka消费者如何消费消息?特别是谈论消费者组的概念及其作用。

Kafka消费者消费消息的过程基于消费者组(Consumer Group)的概念,这是Kafka实现消息分发、负载均衡和容错的关键机制。下面是Kafka消费者消费消息的具体流程,以及消费者组的作用:

消费者如何消费消息

  • 订阅主题(Topic):消费者首先向Kafka集群订阅他们感兴趣的Topic。一个消费者可以订阅一个或多个Topic。
  • 分配Partition:在消费者组内,Topic的Partition会被均匀地分配给组内的消费者。每个Partition在同一时刻只能被消费者组内的一个消费者消费,从而确保了消息不会被重复消费。Kafka使用分区分配策略(如round-robin、range或StickyAssignor)来决定哪些消费者消费哪些分区。
  • 拉取(Pull)消息:Kafka采用拉取(Pull)模式,消费者主动从Broker拉取消息。消费者定期向Kafka Broker发送请求,询问是否有新的消息可供消费。这种模式允许消费者按需获取消息,有助于控制流量和提高效率。
  • 偏移量(Offset)管理:消费者在消费消息时会记录每个Partition的偏移量,这是消费位置的标识。消费者可以决定是否提交偏移量到Kafka,以表明消息已被消费。偏移量的管理允许消费者在重启后从上次停止的地方继续消费,而不是从头开始。
  • 再均衡(Rebalance):当消费者组成员发生变化(如消费者加入或离开)时,Kafka会触发再均衡过程。这个过程会重新分配Partition给组内的消费者,确保每个Partition仍然只有一个消费者在消费,同时避免了消息被漏消费或重复消费。

消费者组的作用

  • 负载均衡:消费者组允许将Topic的Partition在多个消费者之间进行分配,从而实现消息处理的负载均衡,提高了消息处理的效率和系统吞吐量。
  • 容错性:如果消费者组内的某个消费者失败,其负责的Partition会自动分配给组内的其他消费者,确保消息仍然能够被持续消费,增强了系统的可靠性。
  • 广播与单播模式:通过创建不同的消费者组,可以实现消息的广播(每个消费者组独立消费全部消息)或单播(每个Topic的消息仅被一个消费者组消费)。
  • 灵活性和扩展性:消费者组机制使得添加或移除消费者变得简单,可以根据需求动态调整消息处理能力,实现水平扩展。
  • 顺序保证:在一个消费者组内,如果一个Topic的Partition只分配给一个消费者,则可以在一定程度上保证消息的顺序消费。

如何在Kafka生产者中配置消息发送的可靠性保障?

在Kafka生产者中配置消息发送的可靠性保障,主要涉及到以下几个关键配置项和策略:

  1. acks配置:
  • acks=0:生产者在成功写入消息之前不会等待任何来自服务器的响应,这意味着消息可能丢失但发送速度最快。
  • acks=1(默认值):生产者只需等待Leader副本收到消息的确认即可,这种设置提供了基本的可靠性保证,但如果Leader在确认后立即崩溃,消息可能会丢失。
  • acks=all 或 acks=-1:生产者需要等待所有参与副本(包括Leader和ISR中的所有Follower)都确认接收到消息才会认为发送成功,这是最安全但也是最慢的选项,因为它确保了消息至少被写入一个备份。
  1. 重试机制(retries配置):设置retries参数来定义生产者在遇到发送失败时的重试次数。结合retry.backoff.ms配置可以设定两次重试之间的延迟,以避免短时间内对Broker造成过大的压力。
  2. 消息时间戳:通过设置消息的时间戳,可以在消息过期或需要基于时间的顺序处理时提供额外的保障。
  3. 幂等性(enable.idempotence配置):开启幂等性(enable.idempotence=true)可以确保在启用重试的情况下,即使消息被多次发送,Kafka也只会存储一份,避免了重复消息的问题。这通常与acks=all一起使用以提供最高的消息可靠性。
  4. 最大 inflight 请求(max.in.flight.requests.per.connection):限制生产者同时发送但未确认的消息数量,可以减少网络拥塞时的消息乱序问题,提高消息的顺序性,特别是在启用幂等性时应当设置为1。
  5. Batching(batch.size和linger.ms配置):通过设置合适的批处理大小和延迟时间,生产者可以收集多条消息一起发送,减少网络请求次数,提高吞吐量的同时,间接提升了消息发送的可靠性,因为单个批次的成功或失败作为一个整体被处理。

综上所述,通过精细调整这些配置项,可以显著提升Kafka生产者发送消息的可靠性,同时在可靠性与性能之间找到平衡点。正确的配置取决于具体的应用场景和对消息丢失、延迟、吞吐量的容忍度。

Kafka消费者如何处理消息的偏移量(Offsets)管理?手动提交与自动提交的区别?

Kafka消费者通过管理消息的偏移量(Offsets)来追踪消息消费的状态,确保消息被恰当地消费且不会遗漏或重复。Kafka提供了两种偏移量管理方式:手动提交(manual commit)和自动提交(auto commit)。

手动提交偏移量(Manual Commit)

  • 控制权:在手动提交模式下,消费者拥有偏移量提交的完全控制权。这意味着开发者必须在代码中显式地调用提交偏移量的API,通常是在消息被成功处理之后。
  • 精确控制:这种方式提供了更高的灵活性和精确性,因为开发者可以选择在任何合适的时机提交偏移量,例如,可以确保只有在消息被持久化到数据库后才提交偏移量。
  • 复杂性:增加了实现的复杂性,因为开发者需要处理提交逻辑,包括异常处理和重试机制,以防止偏移量提交失败或重复提交。
  • 提交类型:手动提交支持同步提交和异步提交。同步提交会等待Broker确认后才继续,确保偏移量已成功记录;异步提交则不会阻塞,但可能会有提交确认的延迟。

自动提交偏移量(Auto Commit)

  • 便捷性:自动提交模式简化了偏移量管理,因为消费者会按照配置的间隔(如通过auto.commit.interval.ms参数)自动提交当前消费到的最大偏移量。
  • 配置驱动:开启自动提交只需设置enable.auto.commit为true,并可配置提交间隔时间。Kafka会自动处理偏移量的后台提交。
  • 潜在风险:自动提交可能导致消息被重复消费或丢失,尤其是在短暂的网络故障或消费者处理逻辑中止时,因为偏移量可能在消息实际处理完成之前就被提交了。
  • 适用场景:适用于对消息精确一次处理要求不高的场景,或者处理逻辑简单、快速,且能容忍一定比例的消息重复。

总结

选择手动提交还是自动提交偏移量,取决于应用对消息处理准确性的要求、系统的复杂度以及对开发者管理开销的接受程度。手动提交提供了更多的控制和精确性,但实现起来更为复杂;自动提交简化了管理,但牺牲了一定的可靠性。在设计Kafka消费者时,应根据实际需求权衡这两种方式的利弊。

如何实现Kafka的 Exactly-Once 消息传递语义?

Kafka 实现 Exactly-Once(精确一次)消息传递语义依赖于幂等性(Idempotence)和事务(Transactions)两种机制的组合,确保消息在生产和消费过程中即使面对网络故障、重复请求或其他异常情况也只被处理一次。以下是实现 Exactly-Once 的关键步骤和原理:

  1. 生产者幂等性(Idempotent Producers)
  • 启用幂等性:通过在生产者配置中设置 enable.idempotence=true,Kafka会自动处理消息的去重,确保即使同一条消息因网络重传等原因被发送多次,Kafka也只会将其存储一次。这背后是通过生产者发送请求时携带序列号和PID,Kafka利用这些信息去重。
  1. 事务(Transactions)
  • 事务开启与提交:生产者可以开启一个事务(通过调用 initTransactions()),然后在事务上下文中发送消息。一系列消息被看作一个原子操作,要么全部成功,要么全部失败。事务通过调用 commitTransaction() 提交,或在出现错误时通过 abortTransaction() 回滚。
  • 跨分区操作:事务机制允许生产者在多个Topic的多个分区上执行原子操作,这对于实现跨分区的Exactly-Once语义至关重要。
  1. 消费者偏移量管理
  • 精确的偏移量控制:消费者在Exactly-Once语义下需要精确控制偏移量的提交。通常,这与事务性生产者结合使用,确保消费和处理的逻辑在事务范围内完成后再提交偏移量,避免偏移量提前提交导致的消息丢失或重复处理。
  1. 消费者端的幂等性
  • 虽然通常关注点在于生产者,但在某些场景下,确保消费者端逻辑的幂等性也很重要,以应对消息重传或重复消费的情况。
  1. 综合应用
  • 在流处理场景中,例如结合Kafka Streams或Flink等框架,可以进一步利用两阶段提交协议等高级特性,确保从读取Kafka消息到最终状态更新的整个过程满足Exactly-Once语义。

总的来说,Kafka通过生产者的幂等性特性避免消息重复发送,利用事务机制确保跨分区操作的原子性,同时结合消费者精确的偏移量管理和潜在的消费者端幂等性逻辑,共同实现了端到端的Exactly-Once消息传递语义。

性能与优化

影响Kafka性能的因素有哪些?如何进行性能调优?

Kafka的性能受到多个因素的影响,对其进行性能调优通常需要综合考虑以下几个方面:

影响因素:

  1. 硬件资源:
  • 磁盘:读写速度直接影响消息的存储和检索效率,尤其是对于I/O密集型操作。使用SSD相较于HDD能显著提升性能。
  • 内存:影响消息缓存和处理速度,足够的内存对维持高吞吐量至关重要。
  • 网络:网络带宽和延迟会影响消息传输速度,尤其是在分布式部署中。
  • CPU:影响消息压缩/解压缩、加密/解密等处理速度。
  1. 配置参数:
  • batch.size:生产者发送消息时的批次大小,增大可以减少请求次数,提升吞吐量,但可能会增加延迟。
  • linger.ms:生产者等待更多消息加入批次的时间,平衡吞吐量与延迟。
  • buffer.memory:生产者可用的总缓冲区大小,影响消息积压能力。
  • acks:控制消息确认级别,影响消息的可靠性和吞吐量。
  • compression.type:消息压缩类型,减少网络传输量但可能增加CPU负担。
  • fetch.min.bytes/fetch.max.bytes:消费者拉取消息时的最小/最大字节数,影响拉取效率。
  • consumer.auto.offset.reset:消费者首次读取或找不到偏移量时的行为,影响消费逻辑。
  1. 架构设计:
  • 分区:合理设置分区数可以平衡负载,提高并行处理能力,但过多的分区也会增加管理和协调开销。
  • 副本:副本数量影响数据冗余和可用性,同时也会影响写操作的性能。
  • 集群规模:集群中Broker的数量和它们之间的网络状况影响整体的吞吐量和容错能力。

性能调优方法:

  1. 硬件优化:根据业务需求选择高性能硬件,特别是针对I/O密集型操作,考虑使用更快的存储介质。
  2. 配置调优:
  • 根据业务负载测试不同配置组合,如调整batch.size和linger.ms以找到最佳的吞吐量与延迟平衡点。
  • 合理设置缓冲区大小,避免生产者因缓冲区不足而阻塞。
  • 根据可靠性需求选择合适的acks级别。
  1. 消息压缩:根据网络条件和消息内容选择合适的压缩算法,平衡压缩带来的好处和CPU消耗。
  2. 分区策略:合理规划分区策略,确保负载均衡,避免热点问题。
  3. 消费者优化:适当配置消费者参数,如fetch.min.bytes和fetch.max.bytes,以及合理安排消费者组的大小和分配策略。
  4. 监控与测试:持续监控Kafka集群的性能指标,如CPU使用率、磁盘I/O、网络流量等,使用工具进行基准测试和压力测试,根据测试结果不断调优。
  5. 零拷贝与页缓存:确保Kafka能够利用操作系统提供的零拷贝技术和页缓存,减少数据复制,提高I/O效率。
  6. 幂等性和事务:在需要精确一次语义的场景下,合理使用幂等性生产和事务功能,但要注意它们可能对性能的潜在影响。

解释Kafka的批处理机制及其对性能的影响?

Kafka的批处理机制是其高吞吐量和低延迟性能的关键特性之一。在生产者和消费者两端,Kafka都支持将多条消息聚合为一批次进行处理,以此来减少网络通信的开销和提高处理效率。

生产者的批处理

在生产者端,Kafka允许生产者不是即时发送每一条消息,而是累积一定数量的消息或等待特定时间(由linger.ms配置控制)后再发送。当达到batch.size配置的大小,或者超过linger.ms指定的等待时间,或者缓冲区即将填满时,生产者会将这批消息作为一个整体发送给Kafka的Broker。这样做有几个好处:

  • 减少网络请求:由于多条消息被打包在一起,因此减少了网络往返的次数,降低了网络延迟。
  • 提高资源利用率:每个网络请求和磁盘写入操作都有固定的开销,批处理减少了这些开销相对于实际数据的比例。
  • 优化序列化和压缩:批处理中的多条消息可以一起进行序列化和压缩,相比单独处理每条消息,可以更有效地利用压缩算法,减少消息的总体大小。

消费者的批处理

在消费者端,Kafka允许消费者一次性从Broker拉取多个消息,而不是每次只拉取一条。通过设置fetch.min.bytes和fetch.max.bytes参数,可以控制每次拉取的最小和最大数据量。消费者批处理同样有助于:

  • 减少网络往返:每次拉取更多的消息减少了与服务器的交互次数,从而降低网络延迟。
  • 提高处理效率:减少消息处理的上下文切换开销,特别是在处理消息需要一定初始化成本的场景下。

对性能的影响

批处理机制显著提高了Kafka的整体性能,特别是在高吞吐量的场景下。通过减少网络和磁盘I/O操作的次数,Kafka能够实现非常高的吞吐量,同时保持较低的延迟。批处理还使得Kafka能够更有效地利用系统资源,比如CPU和网络带宽,进一步优化了资源使用效率。不过,批处理参数的选择需要根据具体应用场景来权衡,比如延迟敏感的应用可能需要更小的批处理大小以减少处理延迟。正确配置批处理参数是实现Kafka性能优化的关键步骤之一。

Kafka如何处理大量消息积压的情况?

Kafka在面对大量消息积压的情况时,可以通过以下几种策略进行处理和优化:

  • 增加分区(Partition)数量:如果消费能力不足,可以考虑增加主题(Topic)的分区数量。更多的分区意味着可以有更多并行的消费者工作,从而提高消费速率。

  • 增加消费者数量:提升消费者组中的消费者数量,确保每个分区都有至少一个消费者在处理消息。理想情况下,消费者的数量应该等于分区的数量,以充分利用并行处理能力。

  • 提高消费批次大小:如果下游数据处理不及时,可以通过增加每次拉取的消息批次大小来提高消费效率。这减少了拉取操作的频率,从而减少了处理时间与生产速度之间的差距。

  • 优化消费逻辑:检查并优化消费者端的处理逻辑,减少处理每条消息所需的时间,比如减少数据库访问、外部服务调用等耗时操作,或者采用异步处理机制。

  • 调整消费者参数:如调整fetch.min.bytes和fetch.max.bytes等参数,以更高效地拉取消息。合理设置这些参数可以减少不必要的网络交互,提高消费效率。

  • 使用幂等性消费:确保消费者幂等性处理,避免重复消费导致的处理延迟。

  • 监控与报警:实施实时监控,当消息积压超过阈值时触发报警,以便及时发现并处理问题。

  • 排查和优化网络:检查网络延迟和带宽,优化网络配置,确保消息传输的高效。

  • 资源升级:如果硬件成为瓶颈,考虑升级服务器硬件,如使用更高性能的CPU、增加内存、升级到更快的存储设备等。

  • 考虑数据过期与清理:根据业务需求,合理设置Kafka的消息保留策略,让旧消息自动过期并被清理,避免无限积压。

谈谈Kafka的延时问题以及可能的解决方案?

Kafka作为一种高吞吐量的分布式消息队列系统,在某些场景下可能会遇到延迟问题,这主要受制于网络、硬件、配置以及应用逻辑等因素。下面是一些常见的延迟原因及相应的解决方案:

延迟原因分析:

  • 网络延迟:数据在网络中的传输时间,特别是在地理分布较远的集群中更为明显。
  • 硬件限制:如磁盘I/O速度慢、CPU处理能力不足等。
  • 消息批处理策略:虽然批处理能提高吞吐量,但过大的批处理时间(linger.ms设置过大)会导致消息发送延迟。
  • 消费者处理能力:消费者处理消息的速度跟不上生产速度,导致消息堆积。
  • 配置不当:如缓冲区大小设置不合理、消息确认模式(acks)设置过于严格等。
  • 资源竞争:在同一台物理机上的多个服务或进程竞争CPU、内存、磁盘等资源。
  • JVM垃圾回收:频繁的Full GC操作会暂停应用,影响消息处理速度。

解决方案:

  1. 优化网络:使用高性能网络硬件,优化网络配置,如减少网络跳数,使用RDMA(Remote Direct Memory Access)技术减少网络延迟。
  2. 升级硬件:使用高速SSD、增加内存容量、升级CPU等,特别是对于I/O密集型操作,硬件升级效果显著。
  3. 调整批处理策略:合理设置batch.size和linger.ms,在保证吞吐量的同时尽量减少延迟。
  4. 增强消费者能力:增加消费者数量,优化消费者代码逻辑,提升消息处理速度。
  5. 配置调优:
  • 增大buffer.memory以容纳更多待发送消息,减少生产者阻塞。
  • 适当调整acks设置,如非关键场景可设置为1,以减少确认等待时间。
  • 考虑使用更快的消息压缩算法,如LZ4,减少消息在网上传输的时间。
  1. 资源隔离与优化:使用容器技术(如Docker、Kubernetes)进行资源隔离,确保Kafka及其依赖服务有足够的资源运行。优化JVM配置,减少GC压力。
  2. 监控与告警:实施全面的监控,包括但不限于网络延迟、CPU使用率、磁盘I/O、消息堆积情况等,及时发现问题并采取措施。
  3. 负载均衡:确保Kafka集群内的负载均衡,避免单点过载。使用Kafka自带的分区再均衡机制,合理分配分区到不同的Broker上。

总的来说,解决Kafka延迟问题需要综合考虑各种因素,通过软硬件优化、配置调整、代码优化等手段,结合实际情况制定合适的策略。同时,持续的监控和维护也是确保系统低延迟运行的关键。

故障排查与安全性

如果Kafka Broker宕机了,会有什么影响?如何恢复?

当Kafka集群中的某个Broker宕机时,可能会产生以下影响:

  • 不可用性:如果宕机的Broker是某些分区的领导者(Leader),这些分区将暂时变得不可用,无法接收新消息或处理消费者请求,导致生产者和消费者操作延迟或出错。
  • 数据丢失风险:如果宕机的Broker上有未完全复制到其他Broker的独有数据,且副本数量不足以保障数据持久性,这部分数据可能面临丢失的风险。

为了最小化故障对Kafka集群的影响并进行恢复,可以采取以下措施:

  • 配置多个副本:确保每个分区配置了足够多的副本(推荐至少3个),这样即使有一个Broker宕机,其他副本可以接管领导权,保证数据的可用性。
  • 监控与警报:实施有效的监控和警报机制,以便在Broker发生故障时迅速发现并响应,减少业务中断时间。
  • 自动故障转移:Kafka本身不自动进行数据的重新复制,但通过监控和管理工具(如Kafka Manager、Kafka Cruise Control等)可以在检测到Broker故障后触发手动或自动的重分配操作,将原本位于故障Broker上的分区领导者转移到健康的Broker上。
  • 手动干预:在一些情况下,可能需要手动介入,如使用Kafka的管理工具或命令行接口来重新分配分区的领导者,或者修复元数据问题。
  • 定期备份与恢复:虽然不是直接的故障恢复步骤,但定期备份Kafka数据并在必要时从备份中恢复可以帮助保护数据免受意外损失。
  • 跨机架部署:确保Kafka Brokers部署在不同的物理机架或云的可用区中,可以增加容错能力,防止单点故障影响整个集群。

综上所述,Kafka集群在Broker宕机后的恢复是一个涉及监控响应、手动或自动故障转移、以及可能的数据恢复的综合过程。正确的配置和管理策略是减轻影响的关键。

如何监控和诊断Kafka集群的健康状况?

监控和诊断Kafka集群的健康状况是确保消息系统稳定运行的重要环节。以下是一些关键的监控和诊断步骤:

  1. 使用Kafka内置指标
  • Kafka Metrics: 利用Kafka提供的丰富指标来监控集群的内部状态,这些指标可通过JMX接口访问,也可以集成到Prometheus、Grafana等监控系统中。关注的指标包括但不限于吞吐量、消息延迟、分区状态、磁盘使用率等。
  1. 监控ZooKeeper
  • ZooKeeper Metrics: Kafka依赖ZooKeeper管理元数据,因此ZooKeeper的健康也至关重要。监控ZooKeeper的连接数、延迟、会话超时等指标,确保其稳定运行。
  1. Broker监控
  • Broker指标: 监控每个Broker的资源使用情况,如CPU使用率、内存使用率、网络流量、磁盘空间、日志大小等。确保Broker没有过载,并有足够的资源处理消息。
  1. 消费者和生产者监控
  • 生产者和消费者指标: 监控生产者发送速率、消息大小、失败率;消费者消费速率、偏移量、滞后量(lag)等。这些指标有助于发现消费速率过慢或生产异常的情况。
  1. 使用工具和平台
  • Kafka Healthcheck: 使用Kafka Healthcheck这样的工具进行快速诊断,检查网络延迟、磁盘空间、Zookeeper状态等问题。
  • 管理工具: 应用Kafka Manager、Confluent Control Center等管理工具,这些工具提供了Web界面来直观展示集群状态、主题、分区信息,以及进行问题诊断。
  • 日志与审计: 审查Kafka和相关组件的日志文件,查找错误信息或异常行为的线索。
  1. 分区和副本监控
  • ISR状态: 监视分区的ISR(In-Sync Replicas)列表,确保所有副本保持同步,防止数据丢失风险。
  1. 故障模拟与演练
  • 定期进行故障模拟和恢复演练,确保在真实故障发生时能够快速定位问题并恢复服务。
  1. 实施报警策略
  • 配置监控系统发出警报,当关键指标超出预设阈值时立即通知运维团队,以便及时介入处理。

Kafka提供了哪些安全特性来保护数据?如何实施认证和授权?

Apache Kafka提供了一系列安全特性来保护数据,确保消息在传输和存储过程中的安全性。这些特性主要包括:

  1. 连接认证(Authentication):确保客户端与Kafka集群之间的通信是经过验证的,确认请求发起者的身份。Kafka支持多种认证机制,包括但不限于:
  • SSL/TLS:使用SSL/TLS协议加密通信,并通过客户端证书进行身份验证。
  • SASL (Simple Authentication and Security Layer):支持多种认证机制,如:
    • SASL/PLAIN:基于明文的用户名和密码认证,适用于内部网络或配合TLS加密使用。
    • SASL/SCRAM:比PLAIN更安全,使用挑战响应机制,支持密码哈希。
    • SASL/GSSAPI:基于Kerberos的认证,适合企业环境,提供强身份验证和单点登录体验。
    • OAuth/OAuth2:通过外部认证服务验证用户身份,适合与现代Web服务集成。
  1. 授权(Authorization):控制认证用户或服务对Kafka资源(如主题、分区)的访问权限。Kafka使用ACL(Access Control Lists)机制来实现细粒度的授权控制,允许或拒绝特定用户或用户组对主题的读、写、创建、删除等操作。

实施认证和授权的步骤大致如下:

实施认证

  1. 配置SSL/TLS:生成和分发证书,配置Kafka Broker和客户端使用SSL/TLS进行加密通信。
  2. 配置SASL:
  • 选择合适的SASL机制,如PLAIN或SCRAM。
  • 在Kafka配置文件中启用SASL,配置认证器工厂和所需的属性。
  • 创建用户凭证,如在Kerberos中添加用户或配置PLAIN/SCRAM的用户名密码。

实施授权

  1. 启用ACLs:在Kafka配置中启用授权检查。
  2. 管理ACLs:
  • 使用Kafka的命令行工具kafka-acls.sh来添加、删除或列出ACL规则。
  • 规则定义了谁(principal,如用户名)可以对哪个资源(如特定主题)执行何种操作(如读、写)。
  1. 测试和验证:通过生产者和消费者尝试访问Kafka资源,验证认证和授权配置是否生效。

在多租户环境下,如何确保Kafka的安全隔离?

在多租户环境下确保Apache Kafka的安全隔离,主要涉及以下几个方面:

  1. 物理或逻辑集群隔离:
  • 物理隔离:为不同的租户部署独立的Kafka集群。这是最彻底的隔离方式,但成本较高,管理和维护复杂度也相应增加。
  • 逻辑隔离:在同一个Kafka集群中,通过配置和策略来实现租户间的逻辑隔离,比如使用不同的命名空间、主题前缀来区分不同租户的数据。
  1. 主题和分区的隔离:
  • 为每个租户创建独立的主题或者使用租户ID作为主题的前缀,确保数据在物理上分开存储。
  • 控制主题的访问权限,确保租户只能访问自己的主题。
  1. 认证与授权:
  • 实施SASL(如SCRAM、PLAIN)或使用SSL/TLS证书进行客户端认证,确保只有合法的租户能够连接到Kafka。
  • 利用Kafka的ACL(Access Control Lists)功能,精细化控制租户对主题的读写权限,确保租户只能访问和操作自己授权的主题。
  1. 网络隔离:
  • 使用网络策略(如VPC、网络ACL、安全组)限制不同租户间以及外部对Kafka集群的网络访问。
  • 可能还需要设置Kafka代理的监听地址和端口,仅允许特定源IP或网络范围内的连接。
  1. 加密:
  • 通过SSL/TLS加密Kafka的通信,确保数据在传输过程中不被窃听。
  • 考虑对敏感数据进行客户端加密,进一步增强数据安全性。
  1. 日志清理策略和保留策略:
  • 配置租户主题的清理策略和消息保留时间,确保数据合规性及存储资源的有效管理。
  1. 监控与审计:
  • 实施日志收集和分析,监控Kafka集群的运行状态,及时发现并处理异常情况。
  • 定期进行安全审计,记录并审查所有访问请求,确保没有未授权的访问行为。

作者:凡夫贩夫
链接:https://juejin.cn/post/7369884289712324659

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值