快手:从 Clickhouse 到 Apache Doris,实现湖仓分离向湖仓一体架构升级

news2024/11/16 11:54:33

导读:快手 OLAP 系统为内外多个场景提供数据服务,每天承载近 10 亿的查询请求。原有湖仓分离架构,由离线数据湖和实时数仓组成,面临存储冗余、资源抢占、治理复杂、查询调优难等问题。通过引入 Apache Doris 湖仓一体能力,替换了 Clickhouse ,升级为湖仓一体架构,并结合 Doris 的物化视图改写能力和自动物化服务,实现高性能的数据查询以及灵活的数据治理。

作者快手大数据架构师 李振炜、曾斯维、周思闽

在当今这个数据洪流的信息时代下,数据已跃升为企业不可或缺的核心资产。深度挖掘并提炼数据内在价值,成为支撑企业战略决策的重要依据。在此背景下,快手建立了 OLAP 系统,该系统在快手应用极为广泛,每天承载近 10 亿的查询请求,为内外多个业务场景提供数据服务。具体场景包括:

  • ToB 系统:商业化报表引擎、商业化 DMP、商业化磁力金牛、电商选品等

  • 内部系统:KwaiBI、春节/活动大屏、APP 分析、数据同步、用户理解中心、APM、CDN 监控、雷达监控系统等

存在的问题

最初,快手 OLAP 系统整体技术架构由离线数据湖和实时数仓这两部分组成,离线数据湖核心引擎为 Hive/Hudi,实时数仓核心引擎为 ClickHouse。OLAP 系统数据源种类非常丰富,全面覆盖结构化、半结构化、非结构化的数据类型,这些数据同步到到数据湖进行 ODS 、 DWD、DWS、ADS 层处理,处理后的数据同步至实时数仓,由数仓对外提供 BI、报表、查询等数据服务。

存在的问题.png

虽然这套架构已在快手内部稳定运行许久,但随着需求的变化、数据的不断累积,湖仓分离这一架构带来的问题逐渐显现:

  • 冗余存储:虽然将数据入仓到 ClickHouse 能够提高查询性能,但同时导致了数据冗余存储,影响数据就绪时间和存储效率。
  • 资源占用: to ClickHouse 过程也会占用 ClickHouse 集群资源,不仅体现在 Clickhouse 中数据同步系统的资源消耗,且在数据写入后,ClickHouse 内部也有 Compaction 等计算资源的消耗,在高并发查询的时候,并行读写带来更显著的资源抢占问题,可能影响其他查询任务的执行效率和集群的整体性能。
  • 治理复杂:数据工程师需要投入大量人力建立 ADS 层模型,以支持 to ClickHouse 导入工作,并需要投入额外的精力维护导入任务。此外,当报表看板下线后,对应 ADS 层和 to ClickHouse 任务还在运行,造成计算和存储资源的不必要浪费,大部分情况下需要依赖人工介入判断并终止这些任务,这无疑增加了运维管理的复杂度。

此外,随着 ClickHouse 在业务中使用越来越深,查询性能出现瓶颈。排序字段、二级索引、物化视图以及哈希字段的选择和创建对 Clickhouse 查询性能有显著影响,但局限于 Clickhouse 的语言、系统适配性等因素,开发人员的学习及操作门槛都比较高,查询调优的难度比较高。

升级目标及选型

在上述问题驱使下,快手希望引入湖仓一体架构来解决上述问题,希望数仓可直接分析湖中数据,而不需要进行繁琐复杂的数据传输,避免传输及传输过程中引发的数据问题。在该目标的指引下,快手快速锁定 Apache Doris,尽管 Apache Doris 定位于实时数据仓库,但在过去版本中 Apache Doris 一直不拘于数据仓库的能力边界,在湖仓一体方向进行了诸多探索,逐步形成了湖仓一体解决方案:

  • 极致分析性能、助力湖仓查询加速 : 借助强大的分布式 SQL 查询引擎,Apache Doris 对 Parquet、ORC 等开发格式进行了深度适配。凭借灵活的缓存策略和物化视图能力,用户可直接在湖仓数据之上架设 Apache Doris,从而实现高吞吐和低延迟的数据分析能力。
  • 多源联邦分析、消除数据孤岛 : Apache Doris 提供丰富的数据源连接器,可以对各种异构数据源如 Hive、Iceberg、Hudi、关系型数据库进行统一的元数据管理和映射,并可通过标准 SQL 语言进行联邦分析。
  • 湖仓数据无缝集成、自由流转 : 结合 Doris 异步物化视图能力和内置作业调度功能,用户可以便捷的基于 Doris 对湖仓数据进行分层加工处理,从而简化湖仓数据处理的复杂度。
  • 统一数据湖的构建和计算引擎 : Apache Doris 支持主流湖仓的数据写入能力,用户可以基于 Doris 进行统一的数据写入、处理及分析,形成湖仓一体架构下的链路闭环。同时,基于 Arrow Flight 协议的高速数据通道,也进一步提升了 Doris 数据格式的开放性,用户可以在 Doris 上使用其他计算引擎支撑更丰富的计算负载。

基于 Apache Doris 的湖仓一体架构

快手基于 Apache Doris 升级为湖仓一体分析平台,新架构如图所示:

基于 Apache Doris 的湖仓一体架构.png

从下至上,主要分为以下几个层级:

  • 数据加工层:数据源数据同步到数据湖仓(Hive/Hudi),并在湖仓系统中完成从 ODS 层到 DWS 层的加工处理, DWS 层到 ADS 层依赖自动物化服务实现(后文详细介绍)。

  • 数据缓存层:ADS 层数据缓存到 Alluxio 中,以提供高性能的数据缓存访问能力。同时,元数据也缓存到元数据管理服务中,以提供统一的、稳定的元数据访问服务。

  • 数据查询层:基于 Apache Doris 提供对 ADS 层数据的高性能查询服务。

另外,快手还开发了两个服务,使得整个分析平台更加智能化和自动化:

  • 查询路由服务:通过分析和预估查询的数据扫描量,将超大查询自动路由到 Spark 引擎,以避免大查询占用过多的 Doris 资源。
  • 自动物化服务:提供 DWS 层到 ADS 层按需自动化加工,智能选择排序字段、哈希字段以及更合理的物化,从而实现对复杂查询或高优看板数据的智能查询加速

在数据查询层中,使用 Apache Doris 替换原先的 Clickhouse,为快手带来了如下收益:

  • 统一存储、简化链路: Doris 可以直接访问湖仓数据。Hive ADS 层的数据不再需要额外导入和存储在 OLAP 系统中,降低了数据维护和存储的成本,同时缩短了数据链路,提升了数据时效性。
  • 查询性能提升: Apache Doris 本身作为高性能的计算引擎,查询性能已有较大的提升。同时结合 Doris 自身的物化视图透明改写能力,以及基于代价的查询优化器能力,可以满足不同数据分析场景下的查询加速需求。
  • 更灵活的数据治理:结合 Doris 的物化视图改写能力和自动物化服务,可以更方便的在 ADS 层进行视图建模,对业务层屏蔽屏蔽复杂的底层实现逻辑。

接下来重点介绍整个湖仓一体架构中,缓存服务和自动物化服务方面的功能和实践经验。

缓存服务与优化

湖仓一体架构下,缓存层主要用于避免远程数据访问可能发生的网络延迟高、网络抖动、带宽不足等问题,提升数据访问的性能和稳定性。缓存的内容大致可以分为元数据缓存数据缓存。针对这两种缓存,快手结合 Doris 的系统架构和特性做了适配和优化。

01 元数据缓存

元数据缓存的内容包括库、表、列、分区、文件等元信息。而且元数据缓存服务,除了对缓存信息的存储外,更重要的是能够及时感知元数据的变化,如 Schema 的变化、分区的增删,文件的变更等等。通过实时的变化感知,才能保证元数据的一致性和查询的时效性。

Apache Doris 内置支持了元数据的缓存能力,支持基于 Hive Metastore Event 的元数据增量同步能力,能够很方便的提供高性能、高时效性的元数据缓存服务。然而,由于快手的元数据服务需要与除 Hive Metastore 外的其他系统(如 Alluxio)进行交互,因此无法单纯依赖 Doris 内置的元数据缓存能力。为此,快手基于 Doris 的内置方案自主研发了 Meta Server,作为统一的元数据服务。

元数据缓存.png

如上图所示,Meta Server 负责监听其他服务中的元数据变化,如 Hive Metastore 中的 Schema 变化,Alluxio 中的缓存变化等,并将这些信息持久化到后端的 Meta Store 中。同时,Meta Server 会将元数据定期的推送给 Doris FE 的 Catalog 中,并通过元数据校验服务来保证两边数据得一致性。

此外,针对分区信息缓存策略,快手也结合 Alluxio 的缓存能力进行了改造。

元数据缓存-2.png

如上图所示。Meta Server 监听到分区变化后,从访问 HDFS 获取最新的文件(Split)列表,持久化存储到 Meta Store 中,并通知 Alluxio 进行缓存预热。而 Doris 在查询时,可以直接访问 Meta Store 获取文件列表。

通过 Meta Server 服务,实现了查询引擎(Doris)、元数据服务(Hive Metastore)、数据缓存服务(Alluxio) 三方联动,在提供高效的元数据访问的同时,也提升了数据缓存的时效性。

02 数据缓存

数据缓存服务支持数据内容以文件形式存储在缓存系统中,以提供本地化的数据访问性能。

Doris 支持内置和外置两种数据缓存服务。内置数据缓存不依赖第三方系统,可以提供开箱即用的缓存能力。而快手为了能够将缓存服务能够和公司内部的其他业务系统更灵活的对接,采用了基于 Alluxio 的外置数据缓存服务,其对外提供 HDFS 兼容的 API,使得 Doris 可以很方便的对接到 Alluxio 文件系统上,像访问 HDFS 一样访问 Alluxio 中的文件。

同时,为了减少数据访问的延迟,快手在上述基础上重点开发了缓存预热功能。缓存预热是非常重要的步骤,预热后的数据存储在 Alluxio 中,提高了查询响应速度。

数据缓存.png

上一节已经介绍了缓存的元信息如何存储到 Meta Store 中。Doris 会根据查询语句中的分区条件,从 Meta Store 中获取文件列表,并通过 is_cached 字段判断数据是否已经被缓存,并自动选择从 Alluxio 或者 HDFS 中读取。

03 优化效果

通过元数据缓存,与直接从 Hive Metastore 和 HDFS 中获取相比,平均耗时由 800 毫秒降低至约 50 毫秒 ,并且查询耗时并未出现较大波动。

优化效果.png

自动物化系统

物化视图是数据仓库系统中的一项重要能力,不仅能够提供数据的分层加工功能,还可通过透明改写实现智能查询加速。快手在内部一直使用物化视图,但初期面临数据加工链路复杂和治理成本高等问题。经过深入分析,发现根本原因在于 ADS 模型的生产和消费由不同角色负责:

  • ADS 模型消费:主要由运营、产品、数据分析和业务研发团队使用,这些需求与业务场景深度耦合,呈现出多样化的特点。
  • ADS 模型生产:由数据工程师负责,他们需要深入理解业务需求,设计相应的 ADS 模型并进行生产加工,这给工程师带来了较大的理解成本。

因此在数据的分层加工上,快手自研了自动物化服务,实现消费驱动生产,主要流程如下:

  • 数据工程师将所有数据直接交付至 DWS 层。
  • 消费者访问 DWS 层数据表,并基于 DWS 层进行看板和报表的配置。
  • ADS 层实现自动物化,提供实际的数据访问,物化视图的生产逻辑对数据工程师屏蔽,全部托管在计算引擎 中。
  • Doris 根据查询自动选择最优的物化视图,从而实现查询加速。

自动物化系统.png

物化视图包括构建、刷新和改写流程,Doris 本身支持相对完善的物化视图功能。但快手选择在外部系统(自研自动物化服务)中实现构建和刷新操作,由 Doris 支持透明改写能力,而非全部采用 Doris 能力,主要原因如下:

  • 物化视图的生成需要大量计算资源。快手每天处理的数据量庞大,涉及数十万张表、数百 PB 的数据增量。如果全部由 Doris 处理,将消耗大量计算资源。因此,利用现有的计算集群资源(如 Spark)可以有效降低计算成本。
  • 高优看板数据就绪需要 SLA 保障,因此物化视图的调度必须和其他系统交互,使用 Doris 内置调度方案需要对内核修改,具有较高的侵入性。
  • 出于整体系统设计考虑,物化视图必须统一闭环到数据湖上,因此其数据必须保存在外表中。而 Doris 的物化视图目前是通过内表形式存储,以确保最佳查询效率。
  • Doris 内置的物化视图透明改写能力在未命中物化视图时,会降级到原表查询。然而,快手的降级策略要求将这类查询转向 Spark,以避免占用过多的 Doris 计算资源,因此需要引入额外的代码逻辑。

基于以上考虑,快手结合 Doris 的物化视图透明改写能力和自研的物化服务,实现了 KwaiMTMV 自动物化系统。该方案的优势如下:

  • 充分利用 Doris 优化器的视图改写能力,实现灵活的查询改写功能。
  • 利用外部系统实现物化视图生产、管理等过程,使得 Doris 能够更合理的利用计算资源,灵活对接内部服务。

自动物化系统-2.png

接下来分别从物化发现、物化生产和物化消费这三个方面,系统的介绍 Apache Doris 和物化视图的结合使用。

01 物化发现

物化发现旨在利用不同方式,为用户推荐合理的物化视图。这里采用了如下两种方式:

  • 专家规则:用户主动提供一些维度、指标列的定义,或通过 SQL 样例推导指标列和维度列。

    • 维度定义,如 citygender等。
    • 指标定义,如 sum(time)count(distinct uid)等。
    • SQL 样例,如 select sum(time),count(distinct uid) from db.tbl group by city, gender
  • 分析历史查询:基于历史查询,自动发现物化定义。

    • 识别出全局高频查询算子进行物化,尽可能提高物化复用率。
    • 除了聚合指标维度,还可以自动设置索引、引利分桶字段等。

通过人工和系统自动分析两种方式,可以得到合理的物化视图定义。同时也会将这些物化视图定义存储在 Meta Server 中,并和对应的基础表做关联,以便后续的物化生产和消费。

02 物化生产

基于物化发现得到的物化视图定义,将提交至作业调度平台进行构建。调度平台会根据基表数据的变化和血缘关系,自动调度物化生产任务。同时,它还会自动调整物化生产作业的优先级,确保高优先级任务按时完成。

此外,调度平台中实现了一批 Java UDF,能够将某些指标的聚合中间结果序列化为二进制格式并写入数据文件(如 Parquet/ORC)。Doris 还可以复用这些 UDF,在查询时对二进制数据进行反序列化,从而完成对指标列的上卷运算。

03 物化消费

物化消费,主要分为物化视图注册和物化视图改写阶段。

物化消费.png

如上图所示,在物化视图注册阶段,Doris 会定期从 Meta Store 中同步生成的物化视图信息,并在 Doris 中注册类型为 KwaiMTMV的物化视图对象。在查询改写阶段,扩展了 Doris 的物化视图改写能力,使其能够识别KwaiMTMV类型的物化视图,并进行查询改写。

如下是对 author_id指标进行去重的外表查询的改写结果示例。可以看到 Doris 将 count distinct算子改写为了更高效的 Bitmap 算子,并将目的表改写到了合适的物化视图表上。

物化消费-2.png

04 使用效果

引入自动物化系统后,不仅加快了数据模型的交付速度,还显著提升了查询效率。以下是实际测试 SQL 的提升效果:

使用效果.png

上图直观展示“数据行数”和“查询耗时”这两个维度在物化前后的对比。百万到百亿级别的数据经过物化处理后,行数压缩至少达 11 倍。在查询耗时方面,针对百亿级别以下的数据,物化后均可实现毫秒级响应,查询性能相比物化前提升至少 6 倍。

湖仓数据查询优化

除缓存服务和物化视图服务外,快手在实际使用过程中总结了一些湖仓查询的优化经验:

  • 外表统计信息:统计信息对查询规划尤为重要,尤其是在复杂关联查询中。然而,外表统计信息存在收集成本较高,各数据源的统计信息类型和统计口径各不相同的问题。为解决该问题,可在 Spark 进程处理湖仓数据时,同步收集统计信息并将其存储在 Meta Server 中,Doris 可以直接访问这些统计信息,从而为查询优化器提供最优的查询计划。
  • 有序文件和合适的 RowGroup 大小:在构建 Parquet 数据时,按主键排序可以确保文件数据有序。这使得谓词下推时能够最大程度地过滤无用的 RowGroup。同时,指定合适的 RowGroup 大小可以有效提高 RowGroup 的过滤率。
  • 使用 Bucket 表:湖中的表可以按规则生成分桶(Bucket)表。Doris 利用分桶信息生成 Colocation Agg 和 Colocation Join 等优化的分布式执行逻辑,避免大量的数据 Shuffle,从而提高查询效率。

结束语

引入 Apache Doris,使快手成功从湖仓分离架构升级到湖仓一体架构。通过 Apache Doris 替换 Clickhouse,实现了统一存储和链路简化,无需数据导入、Doris 能够直接访问湖仓数据。同时,结合 Doris 的物化视图改写能力和自动物化服务,可实现高性能的数据查询以及灵活的数据治理。后续,快手将会进一步探索 Doris 在湖仓一体下的应用实践。具体包括:

  • 公司内部的看板、报表场景将逐步由 Hive to Clickhouse 替换为 Doris 湖仓一体架构,以提升数据处理效率和查询性能。
  • 即席查询(AD-Hoc)场景将逐步从 Presto 迁移到 Doris,并将所有分析引擎统一为 Doris,以简化技术架构并增强数据分析能力。

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

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

相关文章

DAF-Net:一种基于域自适应的双分支特征分解融合网络用于红外和可见光图像融合

论文 DAF-Net: A Dual-Branch Feature Decomposition Fusion Network with Domain Adaptive for Infrared and Visible Image Fusion 提出了一种新的红外和可见光图像融合方法。该方法旨在结合红外图像和可见光图像的互补信息,以提供更全面的场景理解。红外图像在低…

另外知识与网络总结

一、重谈NAT(工作在网络层) 为什么会有NAT 为了解决ipv4地址太少问题,到了公网的末端就会有运营商路由器来构建私网,在不同私网中私有IP可以重复,这就可以缓解IP地址太少问题,但是这就导致私有IP是重复的…

【锁住精华】MySQL锁机制全攻略:从行锁到表锁,共享锁到排他锁,悲观锁到乐观锁

MySQL有哪些锁 1、按照锁的粒度划分 行锁 是最低粒度的的锁,锁住指定行的数据,加锁的开销较大,加锁较慢,可能会出现死锁的情况,锁的竞争度会较低,并发度相对较高。但是如果where条件里的字段没有加索引&…

【中级通信工程师】终端与业务(十):通信市场营销组合策略

【零基础3天通关中级通信工程师】 终端与业务(十):通信市场营销组合策略 本文是中级通信工程师考试《终端与业务》科目第十章《通信市场营销组合策略》的复习资料和真题汇总。本章的核心内容涵盖了市场营销组合策略的特点、产品策略、价格策略、渠道策略和促销策略…

2206. 将数组划分成相等数对(排序/哈希)

目录 一:题目: 二:代码: 三:结果: 一:题目: 给你一个整数数组 nums ,它包含 2 * n 个整数。 你需要将 nums 划分成 n 个数对,满足: 每个元素…

【开源项目】数字孪生智慧停车场——开源工程及源码

飞渡科技数字孪生停车场管理平台,基于国产数字孪生3D渲染引擎,结合数字孪生、物联网IOT,以及车牌自动识别、视频停车诱导等技术,实现停车场的自动化、可视化和无人化值守管理。 以3D可视化技术为基础,通过三维场景完整…

【原创】java+swing+mysql企业招聘管理系统设计与实现

个人主页:程序员杨工 个人简介:从事软件开发多年,前后端均有涉猎,具有丰富的开发经验 博客内容:全栈开发,分享Java、Python、Php、小程序、前后端、数据库经验和实战 文末有本人名片,希望和大家…

2024年9月第4周AI资讯

阅读时间:3-4min 更新时间:2024.9.23-2024.9.27 目录 o1 处于OpenAI的AGI5阶段的第2阶段 微软使用核燃料推动AI发展 阿里巴巴和英伟达在自动驾驶方向合作 Meta 推出 AR xAI 眼镜、新型号 o1 处于OpenAI的AGI5阶段的第2阶段 概要 OpenAI 首席执行官 …

怎么查看网站是否被谷歌收录,哪些因素影响着网站是否被谷歌收录

一、怎么查看网站是否被谷歌收录 查看网站是否被谷歌收录,有多种方法可供选择,以下是几种常用的方式: 1.使用“site:”指令: 在谷歌搜索引擎的搜索框中输入“site:你的域名网址”(注意使用英文冒号&#x…

【GUI设计】基于Matlab的图像去噪GUI系统(8),matlab实现

博主简介: 如需获取设计的完整源代码或者有matlab图像代码项目需求/合作,可联系主页个人简介提供的联系方式或者文末的二维码。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于Matlab的图像去噪GUI系统&am…

CUDA error: no kernel image is available for execution on the device

记录一下出现上述问题的一个原因: pytorch所依赖的cuda版本不满足显卡(GPU)的算力要求! 举例来说,显卡是3090,并按照以下命令安装Pytorch: conda install pytorch1.7.0 torchvision0.8.0 torchaudio0.7.0 cudatoolkit10.1 -c p…

STM32转AT32代码转换

1. 引言 在嵌入式开发中,我们经常会遇到更换单片机芯片的事情,若芯片是同一厂家的还好说,若是不同厂家的则需要重新写,重新调,重新去学习其底层驱动程序,比较费时费力。如:ST32转AT32、ST32转G…

数论——数数(找质因数个数),三位出题人(组合数学,快速幂)

数数&#xff08;找质因数个数&#xff09; 题目描述 登录—专业IT笔试面试备考平台_牛客网 运行代码&#xff08;通过率一半&#xff09; #include <iostream> #include <vector> using namespace std; const int N5e66; int n; vector<bool>vis; vo…

自定义认证过滤器和自定义授权过滤器

目录 通过数据库动态加载用户信息 具体实现步骤 一.创建数据库 二.编写secutity配置类 三.编写controller 四.编写服务类实现UserDetailsService接口类 五.debug springboot启动类 认证过滤器 SpringSecurity内置认证流程 自定义认证流程 第一步:自定义一个类继承Abstra…

AFSim仿真系统 --- 系统简解_01(任务模块)

任务 任务是AFSIM的基线可执行文件。通过任务&#xff0c;用户可以访问世界仿真框架&#xff08;WSF&#xff09;。该可执行文件&#xff08;mission.exe&#xff09;解释文本格式的仿真输入文件&#xff08;场景&#xff09;&#xff0c;以生成仿真&#xff0c;并可选择以多种…

c语言中的杨氏矩阵的介绍以及元素查找的方法

杨氏矩阵&#xff1a;是一个二维数组 特点&#xff1a;数组的每行从左到右都是递增的 数组的每列从上到下都是递增的 这种矩阵结构使得在查找特定元素时&#xff0c;可以利用其 递增性质来缩小范围&#xff0c;提高查找效率。 从杨氏矩阵中对元素进行查找 1&#xff0c;要求…

沟通技巧对班组长的工作效率有什么影响?

在企业管理的细微脉络中&#xff0c;班组长作为基层管理的中坚力量&#xff0c;其工作效率直接影响着整个生产线的流畅度与团队士气。而沟通技巧&#xff0c;作为人际交往的桥梁&#xff0c;不仅在日常交流中扮演着重要角色&#xff0c;更在班组管理中发挥着不可替代的作用。本…

Bigemap Pro首发(一款真正全面替代Arcgis的国产基础软件)

Bigemap Pro是一款功能强大的计算机数据要素辅助设计(Computer-Aided Data Elements Design CADED)软件&#xff0c;由成都比格图数据处理有限公司研发设计&#xff0c;主要应用在数据要素设计领域&#xff0c;为各行业提供安全可靠高效易用的数据要素设计类国产化基础软件。Bi…

2024年汉字小达人区级自由报名倒数4天:最新问题和今年比赛方式和题型解析

今天是2024年第十一届汉字小达人的区级自由报名活动的第三天&#xff0c;也是倒数第四天。 今天是星期五&#xff0c;通常孩子们放学会早一点。接下来是周六有一整天的时间可用&#xff0c;周日、周一又要上课了&#xff0c;所以实际上可用的较多的备考时间就是今天晚上和明天…

华为OD机试 - 西天取经 - 广度优先搜索BFS(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…