kafka晋升之路-理论+场景

kafka晋升之路

  • 一:故事背景
  • 二:核心概念
    • 2.1 系统架构
    • 2.2 生产者(Producer)
      • 2.2.1 生产者分区
      • 2.2.2 生产者分区策略
    • 2.3 经纪人(Broker)
      • 2.3.1 主题(Topic)
      • 2.3.2 分区(Partition)
      • 2.3.2 消息
    • 2.4 消费者(Consumer)
      • 2.4.1 消费者组(ConsumerGroup)
      • 2.4.2 协调者(Coordinator)
      • 2.4.3 消费者策略
      • 2.4.4 重平衡 Rebalance
  • 三:进阶概念
    • 3.1 消息幂等
    • 3.2 事务
    • 3.3 拦截器
    • 3.4 控制器(Controller)
    • 3.4 日志存储
    • 3.5 常用参数配置
      • 3.5.1 broker.id
      • 3.5.2 port
      • 3.5.3 zookeeper.connect
      • 3.5.4 log.dirs
      • 3.5.5 auto.create.topics.enable
      • 3.5.6 num.partitions
      • 3.5.7 default.replication.factor
      • 3.5.8 log.retention.ms
      • 3.5.9 message.max.bytes
  • 四:常见问题
    • 4.1 消息丢失问题
      • 4.1.1 生产者消息丢失
      • 4.1.2 消费者消息丢失
    • 4.2 重复消费问题
    • 4.3 消息顺序问题
  • 五:总结提升

一:故事背景

一直在使用消息队列中间件,今天进行梳理其对应的知识。本篇文章将会带你系统梳理常用消息中间件kafka。主要侧重于核心知识、应用场景、常见问题。希望读者能够通过本篇文章系统了解,应用kafka。

二:核心概念

Kafka是一种分布式的,基于发布/订阅的消息系统。消息系统的作用,我们就不在这里讲了,大家可以网上自行查阅。接下来我们主要讲一讲kafka的系统架构,整个架构的各个角色。

2.1 系统架构

通常情况下,一个kafka体系架构包括 「多个Producer」、「多个Consumer」、「多个broker」以及「一个Zookeeper集群」。
一张图胜过千言万语,首先让我们开看一下,kafka的基本的架构。
在这里插入图片描述

这里我们列出了kafka的基本架构,整张图宏观看下来分为了四大部分,Zookeeper是用来做集群管理、元数据以及控制器选择的,抛出它以外剩下的三部分分别是:

  • 生产者
  • 队列
  • 消费者
    这三部分其实就是kafka的核心逻辑,生产、暂存、消费。
    接下来我会围绕这张基本架构的图,详细展开讲解kafka架构的各个部分。

2.2 生产者(Producer)

生产者,负责将消息发送到kafka中。生产者是整个流程的起始位置,如果没有生产者,就没有接下来的流程。针对生产者我们只需要考虑以下两个问题。

  1. 谁来生产
  2. 生产出来放在那

谁来进行消息的生产呢?在kafka中没有对谁来进行生产进行限制,也就是说我不用关注这条消息是谁生产的,我们只需要关注,生产出来的数据应该放在哪里,这就引入了生产者分区的概念

2.2.1 生产者分区

Kafka的消息组织方式实际上是三级结构:主题-分区-消息。主题下的每条消息只会保存在某一个分区中,而不会在多个分区中被保存多份。
在逻辑上一个Topic就是一个队列、但是实际上一个Topic内分了多个区,每个区都是一个队列。生产者生产的数据也都是放到分区内的。
在这里插入图片描述
实际上的消息是放到分区的某个块上的,读写操作是针对分区的粒度上进行的。这样每个节点下每个分区都能独立的处理各自的读写请求、增加了系统的效率。

2.2.2 生产者分区策略

分区策略指的就是生产者生产出来的消息要放到具体的topic的哪一个分区下的策略,主要有以下三种:

  1. 轮询策略(Round-robin)
    顺序分配,例如一个topic下有3个分区,第一条消息发送到分区0,第二条发送到1,第三条发送到2。第四条又会重新开始。是kafka默认的分区策略
  2. 随机策略
    将消息放到任意一个分区上,一般是先算出topic的总分区数,返回一个小于它的随机数即可,但是可能会造成数据分布不均匀的情况。
  3. 按消息键保存策略
    Kafka允许为每条消息定义消息键,简称为Key。一旦消息被定义了Key,那么你就可以保证同一个Key的所有消息都进入到相同的分区里面,由于每个分区下的消息处理都是有顺序的,故这个策略被称为按消息键保序策略
    如果没有指定key的话,会走默认的轮询策略。

2.3 经纪人(Broker)

Kafka服务节点,一个或多个Broker组成了一个Kafka集群。每一个broker都是一个单独提供服务的节点,每个broker内可以放置多个topic。

2.3.1 主题(Topic)

Topic是Producer和Consumer订阅的对象,可以为每个业务、每个应用、每类数据创造相应的Topic。我们可以把一个topic看成一个逻辑上的队列,Produce生产消息放入队列,Consumer从队列取出消息进行消费。
在这里插入图片描述

2.3.2 分区(Partition)

kafka支持分区机制,所谓分区指的就是一个Topic内可以有多个分区,虽然这些消息同属一个Topic,但是却有不同的分区,并且只会存在一份。通过分区设置,等于一个Topic内拥有了多个队列,这些Partition可以进行单独支持接收消息,取消息。

2.3.2 消息

在 Kafka 中,“消息”(Message)是指一段数据,它可以是任何形式的信息,例如文本、图像、日志记录等。消息一般包含以下几个关键部分:

  • 主题(Topic): 主题是消息的分类标签。消息会被发布到一个特定的主题中,而消费者可以订阅这些主题来接收消息。主题可以看作是消息的逻辑容器,帮助对消息进行组织和分区。

  • 消息键(Message Key): 每条消息可以有一个可选的键,它用于在发布消息时指定分区。如果消息键被提供,Kafka 会使用哈希算法将所有具有相同键的消息分配到同一个分区中,以确保具有相同键的消息始终位于同一个分区内。

  • 消息值(Message Value): 消息值是实际的数据内容,它可以是任何字节序列,通常是文本或二进制数据。

  • 时间戳(Timestamp): 每条消息可以有一个时间戳,表示消息的创建时间。时间戳可以用于数据处理和分析,以及确保消息的顺序性。

  • 分区(Partition): 主题可以被分成多个分区,每个分区是一个有序、不可变的消息序列。分区可以帮助实现消息的水平扩展,使 Kafka 集群能够处理大量消息。

  • 偏移量(Offset): 每条消息在其所属分区内都有一个唯一的偏移量,用于标识消息在分区中的位置。消费者可以根据偏移量来跟踪已经处理过的消息。

2.4 消费者(Consumer)

消费者Consumer是一种应用程序,它订阅一个或多个 Kafka 主题并从这些主题中拉取消息进行处理
消费者通常的工作流程如下:
在这里插入图片描述
我们可以根据需求,创建多个消费者实例进行并行消费,以实现并行处理。
偏移量(offset)指的是队列中的一个标记变量,其记录了某个消费者组消费到了什么位置,每个消费者组都在其订阅的主题的分区内有对应的偏移量。

2.4.1 消费者组(ConsumerGroup)

  • Consumer Group是Kafka提供的可扩展且具有容错性的消费者机制。一个组内可以有多个消费者实例,他们共享同一个公共的GroupID。
  • 组内的所有消费者一起消费组订阅的主题内的所有分区。每个分区只能由消费者组内一个Consumer实例进行消费。
  • Consumer Group之间彼此独立,互不影响,它们能够订阅相同的一组主题而互不干涉。这就是上文所讲每个消费者组都在其订阅的主题的分区内有对应的偏移量

2.4.2 协调者(Coordinator)

  • 协调者,它专门为Consumer Group服务,负责为Group执行Rebalance以及提供位移管理和组成员管理等。
  • Consumer端应用程序在提交位移时,其实是向Coordinator所在的Broker提交位移,同样地,当Consumer应用启动时,也是向Coordinator所在的Broker发送各种请求,然后由Coordinator负责执行消费者组的注册、成员管理记录等元数据管理操作。
  • 所有Broker都有各自的Coordinator组件。

2.4.3 消费者策略

上文我们说到,一个消费者组内有多个消费者实例,这些实例一起消费订阅的主题内的所有分区。那么这些分区应该怎么分呢?一个实例具体应该去消费那个或那几个分区呢?针对这个问题,kafka有3种对应的消费者策略。

  1. Round
    默认的轮循方式、决定消费者分区。假设有7个分区,分区将会如下分配:
    在这里插入图片描述

  2. Range
    对一个消费者组来说决定消费方式是以分区总数除以消费者总数来决定,一般如果不能整除,往往是从头开始将剩余的分区分配开。
    在这里插入图片描述
    一个分区放两个,剩下的轮循。

  3. Sticky
    它是在Range上的一种升华,且前面两个当同组内有新的消费者加入或者旧的消费者退出的时候,会从新开始决定消费者消费方式,但是Sticky,在同组中有新的新的消费者加入或者旧的消费者退出时,不会直接开始新的Range分配,而是保留现有消费者原来的消费策略,将退出的消费者所消费的分区平均分配给现有消费者,新增消费者同理,同其他现存消费者的消费策略中分离。

2.4.4 重平衡 Rebalance

上文说了消费者的分配策略,但是我们的消费者往往都不是静态的,会有消费者上线、下线的情况。这时候就引入了Rebalance机制,Rebalance触发的条件有3个分别是:

  1. 组成员数发生变更。比如有新的Consumer实例加入组或者离开组,或是有Consumer实例崩溃被踢出组。
  2. 订阅主题数发生变更。Consumer Group可以使用正则表达式的方式订阅主题,比如consumer.subscribe(Pattern.compile(“t.*c”))就表明该Group订阅所有以字母t开头、字母c结尾的主题,在Consumer Group的运行过程中,你新创建了一个满足这样条件的主题,那么该Group就会发生Rebalance。
  3. 订阅主题的分区数发生变更。Kafka当前只能允许增加一个主题的分区数,当分区数增加时,就会触发订阅该主题的所有Group开启Rebalance。

三:进阶概念

3.1 消息幂等

在Kafka中,Producer默认不是幂等性的,但我们可以创建幂等性Producer。
设置方法:

props.put(“enable.idempotence”, ture);
或
props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIGtrue);

通过设置幂等,kafka会自动对你的消息进行去重,确保重复的消息只会有一条。
一个幂等性Producer能够保证某个主题的一个分区上不出现重复消息,它无法实现多个分区的幂等性。它只能实现单会话上的幂等性,不能实现跨会话的幂等性

3.2 事务

事务型Producer能够保证将消息原子性地写入到多个分区中。这批消息要么全部写入成功,要么全部失败。
设置方式:
和幂等性Producer一样,开启enable.idempotence = true。
设置Producer端参数transactional. id,最好为其设置一个有意义的名字。

producer.initTransactions();
try {producer.beginTransaction();producer.send(record1);producer.send(record2);producer.commitTransaction();
} catch (KafkaException e) {producer.abortTransaction();
}

3.3 拦截器

拦截器一共有两类四种,分别是:

  1. onSend:该方法会在消息发送之前被调用。
  2. onAcknowledgement:该方法会在消息成功提交或发送失败之后被调用。
  3. onConsume:该方法在消息返回给Consumer程序之前调用。
  4. onCommit:Consumer在提交位移之后调用该方法。

3.4 控制器(Controller)

在kafka中,控制器会由某个Broker节点担任,每个Broker启动时,都会尝试成为控制器,但是只有第一个会成为控制器,当运行中的控制器宕机或中止的时候,kafka会进行Failover(故障转移),选择新的控制器。
控制器主要有以下几个职责:

  • 主题管理(创建、删除、增加分区)
  • 分区重分配
  • Preferred领导者选举
  • 集群成员管理(新增Broker、Broker主动关闭、Broker宕机)
  • 数据服务

3.4 日志存储

Kafka中的消息是以主题为基本单位进行归类的,每个主题在逻辑上相互独立。
每个主题又可以分为一个或多个分区,在不考虑副本的情况下,一个分区会对应一个日志。
在kafka中引入的日志分段的概念,默认最大是1G,超过1G,日志文件就会分出一个新的段。

3.5 常用参数配置

3.5.1 broker.id

每个 kafka broker 都有一个唯一的标识来表示
这个唯一的标识符即是 broker.id,它的默认值是 0
这个值在 kafka 集群中必须是唯一的,可以任意设定

3.5.2 port

默认为9092端口,可以修改

3.5.3 zookeeper.connect

用来指定zookeeper的连接,其中有如下几个指定参数

  • hostname 是 Zookeeper 服务器的机器名或者 ip 地址。
  • port 是 Zookeeper 客户端的端口号
  • /path 是可选择的 Zookeeper 路径,Kafka 路径是使用了 chroot 环境,如果不指定默认使用跟路径。

3.5.4 log.dirs

Kafka 把所有的消息都保存到磁盘上,存放这些日志片段的目录是通过 log.dirs 来指定的

3.5.5 auto.create.topics.enable

自动创建主题、默认情况下,kafka自动创建主题

3.5.6 num.partitions

num.partitions 参数指定了新创建的主题需要包含多少个分区,该参数的默认值是 1。

3.5.7 default.replication.factor

kafka保存消息的副本数。

3.5.8 log.retention.ms

决定数据可以保留多久,默认是 168 个小时,也就是一周

3.5.9 message.max.bytes

限制单个消息的大小,默认是 1000 000, 也就是 1MB,如果生产者尝试发送的消息超过这个大小,不仅消息不会被接收,还会收到 broker 返回的错误消息。

四:常见问题

4.1 消息丢失问题

4.1.1 生产者消息丢失

问题描述:
Kafka Producer是异步发送消息的,也就是说如果你调用producer.send(msg)这个API,那么它通常会立即返回。实际上消息并没有发送成功,消息有可能因为网络抖动、消息过大、等原因没有实际发送成功。
解决方式:
**不要使用producer.send(msg),而要使用producer.send(msg, callback)。**通过回调确认消息是否真正发送成功

4.1.2 消费者消息丢失

问题描述:
Consumer端丢失数据主要体现在Consumer端要消费的消息不见了。Consumer程序从Kafka获取到消息后开启了多个线程异步处理消息,而Consumer程序自动地向前更新位移。假如其中某个线程运行失败了,它负责的消息没有被成功处理,但位移已经被更新了,因此这条消息对于Consumer而言实际上是丢失了。
解决方案:
这里问题的关键存在于kafka的自动提交。如果是多线程异步处理消费消息,Consumer程序不要开启自动提交位移,而是要应用程序手动提交位移线程执行失败了,不提交位移,将这组消息视为失败。
但这里有另外一个问题,**可能一组50条的数据,已经成功处理了20条,但是我们又无法去提交成功了20条,位移20条的信息。**我们可以在每个消费者的处理逻辑中,根据业务去验证拿到的消费是否已经消费过,避免重复消费。

4.2 重复消费问题

问题描述:
上文已经提到一种重复消费问题,还有另外一种场景即:
消费者消费时间过长
max.poll.interval.ms参数定义了两次poll的最大间隔,它的默认值是 5 分钟,表示你的 Consumer 程序如果在 5 分钟之内无法消费完 poll 方法返回的消息,那么 Consumer 会主动发起离开组的请求,Coordinator 也会开启新一轮 Rebalance。
解决方案:

  1. 提高消费能力,提高单条消息的处理速度;根据实际场景可讲max.poll.interval.ms值设置大一点,避免不必要的rebalance;可适当减小max.poll.records的值,默认值是500,可根据实际消息速率适当调小。
  2. 生成消息时,可加入唯一标识符如消息id,在消费端,保存最近的1000条消息id存入到redis或mysql中,消费的消息时通过前置去重。

4.3 消息顺序问题

问题描述
由于kafka的设计中一个Topic可以包含多个Partition,每个parttition内部是有序的,kafka只能保证partition内部有序,所以业务设计到需要有序的情况时,需要在parttition层面上进行控制,已达到有序。
解决方案

  1. 可以设置topic,有且只有一个partition
  2. 根据业务需要,需要顺序的 指定为同一个partition
  3. 根据业务需要,比如同一个订单,使用同一个key,可以保证分配到同一个partition上

上述只能从生产的过程中保证生产消息是有序的,但是如果消费者是通过多线程进行消息消费的,任然可能出现顺序不符问题。如果这种情况我们可以在消费者内部,使用队列维护从kafka获得的消息,然后通过锁的方式,控制消息的取出。

五:总结提升

本文讲解了kafka的基本概念、常见问题、通过此篇文章,相信你对kafka已经有了一定的了解,赶紧实验起来吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/45213.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPS-RCE

版本&#xff1a; WPS Office 2023 个人版 < 11.1.0.12313 WPS Office 2019 企业版 < 11.8.2.12085 原理&#xff1a; Office 中的 WebExtension&#xff08;通常称为 Office 插件或 Office 应用程序&#xff09;是一种用于扩展 Microsoft Office 功能的技术。Office …

回归预测 | MATLAB实现CSO-SVM布谷鸟优化算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现CSO-SVM布谷鸟优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现CSO-SVM布谷鸟优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一…

FPGA应用学习笔记-----布线布局优化

优化约束&#xff1a; 设置到最坏情况下会过多 布局和布线之间的关系&#xff1a; 最重要的是与处理器努力的&#xff0c;挂钩允许设计者调整处理器努力的程度 逻辑复制&#xff1a; 不能放置多个负载&#xff0c;只使用在关键路径钟 减少布线延时&#xff0c;但会增加面积&a…

阿里云故障洞察提效 50%,全栈可观测建设有哪些技术要点?

本文根据作者在「TakinTalks 稳定性社区 」公开分享整理而成 #一分钟精华速览# 全栈可观测是一种更全面、更综合和更深入的观测能力&#xff0c;能协助全面了解和监测系统的各个层面和组件&#xff0c;它不仅仅是一个技术上的概念&#xff0c;更多地是技术与业务的结合。在“…

SpringBoot + MyBatis-Plus构建树形结构的几种方式

1. 树形结构 树形结构&#xff0c;是指&#xff1a;数据元素之间的关系像一颗树的数据结构。由树根延伸出多个树杈 它具有以下特点&#xff1a; 每个节点都只有有限个子节点或无子节点&#xff1b;没有父节点的节点称为根节点&#xff1b;每一个非根节点有且只有一个父节点&a…

整理mongodb文档:批量操作

个人博客 整理mongodb文档:批量操作 个人公众号&#xff0c;求关注&#xff0c;文章如有不明&#xff0c;请指出。 文章概叙 本文讲的是关于bulkwrite的用法&#xff0c;依旧是在shell下使用。 关于批量操作 Performs multiple write operations with controls for order …

【Linux命令详解 | wget命令】 wget命令用于从网络下载文件,支持HTTP、HTTPS和FTP协议

文章标题 简介一&#xff0c;参数列表二&#xff0c;使用介绍1. 基本文件下载2. 递归下载整个网站3. 限制下载速率4. 防止SSL证书校验5. 断点续传6. 指定保存目录7. 自定义保存文件名8. 增量下载9. 使用HTTP代理10. 后台下载 总结 简介 在编程世界中&#xff0c;处理网络资源是…

Unity C# 引用池 ReferencePool

Unity C# 引用池 ReferencePool 1.目的 对于多次创建的数据使用new 关键字是十分消耗性能的&#xff0c;使用完成后由GC去自动释放&#xff0c;当一个类型的数据频繁创建可以使用引用池进行管理。 2.实现 项目目录 IReference 接口 要放入引用池的数据只需要继承这个接口…

如何使用CSS实现一个渐变背景效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用CSS实现渐变背景效果⭐ 线性渐变&#xff08;Linear Gradient&#xff09;⭐ 径向渐变&#xff08;Radial Gradient&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订…

unity 之 Vector 数据类型

文章目录 Vector 1Vector 2Vector 3Vector 4 Vector 1 在Unity中&#xff0c;Vector1 并不是一个常见的向量类型。 如果您需要表示标量&#xff08;单个值&#xff09;或者只需要一维的数据&#xff0c;通常会直接使用浮点数&#xff08;float&#xff09;或整数&#xff08;in…

基于51单片机直流电机转速数码管显示控制系统

一、系统方案 本文主要研究了利用MCS-51系列单片机控制PWM信号从而实现对直流电机转速进行控制的方法。本文中采用了三极管组成了PWM信号的驱动系统&#xff0c;并且对PWM信号的原理、产生方法以及如何通过软件编程对PWM信号占空比进行调节&#xff0c;从而控制其输入信号波形等…

c++如何解决内存泄漏

Linxu Linux系统下解决内存泄漏可以使用valgrind工具。 下载valgrind sudo apt-get install valgrind Linux下使用valgrind g -g -o app test.cpp valgrind --leak-checkfull ./app 代码如下 #include<iostream> using namesapce std; int main() {int i 0;int * …

记录一次arcgis engine开发版本引入问题

之前基于arcigs 10.1vs2013开发的程序&#xff0c;现在拿出来要改&#xff0c;但是目前版本是arcgis10.7vs2017/vs2019,打开后无论如何替换引用版本&#xff0c;都报错 &#xff08;具体版本对应可以看这&#xff1a;ArcGIS Engine 与 Visual Studio 版本对照表_vs2019对应啥版…

kafka--kafka基础概念-ISR详解

kafka基础概念-ISR详解 主要是讲 主 往 从同步中的问题 当绿色P1接收到写入的数据&#xff0c;要同步到紫色的P1S1和P1S2 如何保证一致性呢&#xff1f; 使用In Sync Replicas 也就是ISR概念 为什么不一致的&#xff1f; 因为P1S1同步数据 可能花费 50ms P1S2可能花费60ms…

【网络架构】华为hw交换机网络高可用网络架构拓扑图以及配置

一、网络拓扑 1.网络架构 核心层:接入网络----路由器 汇聚层:vlan间通信 创建vlan ---什么是vlan:虚拟局域网,在大型平面网络中,为了实现广播控制引入了vlan,可以根据功能或者部门等创建vlan,再把相关的端口加入到vlan.为了实现不用交换机上的相同vlan通信,需要配置中继,为了…

解决访问Github出现的Couldn‘t connect to server错误

文章目录 前言原因分析以及解决办法原因分析解决办法 参考 前言 在Github上面克隆代码仓库出现Failed to connect to 127.0.0.1 port 1080 after 2063 ms: Couldnt connect to server、Failed to connect to github.com port 443 after 21083 ms: Couldnt connect to server等…

贝叶斯公式

一、贝叶斯公式 贝叶斯公式是一种用于概率推断的重要数学工具&#xff0c;它描述了在观测到新信息后如何更新关于某个事件的概率分布。贝叶斯公式的一般形式如下&#xff1a; P(A∣B)P(B∣A)⋅P(A) ​/ P(B) 其中&#xff1a; P(A∣B) 表示在给定观测到事件 B 后&#xff0c…

【MySQL】好好学习一下InnoDB中的页

文章目录 一. 前言二. 从宏观层面看页三. 页的基本内容3.1 页的数据结构3.2 用户空间内的数据行结构3.3 页目录 四. 问题集4.1 索引 和 数据页 有什么区别4.2 页的大小是什么决定的4.3 页的大小对哪些情况有影响4.4 一般情况下说的链表有哪几个4.5 如果页的空间满了怎么办4.6 如…

CentOS 7 安装MySQL8.0.33

一、查看 CentOS 版本 要查看当前 CentOS 版本&#xff0c;你可以执行以下命令&#xff1a; cat /etc/centos-release 该命令将显示当前 CentOS 的版本信息&#xff0c;例如&#xff1a; CentOS Linux release 7.9.2009 (Core) 在这个示例中&#xff0c;CentOS 版本为 7.…

【Python从入门到进阶】32、bs4的基本使用

接上篇《31、使用JsonPath解析淘票票网站地区接口数据》 上一篇我们介绍了如何使用JSONPath来解析淘票票网站的地区接口数据&#xff0c;本篇我们来学习BeautifulSoup的基本概念&#xff0c;以及bs4的基本使用。 一、BeautifulSoup简介 1、bs4基本概念 BeautifulSoup是一个P…