Flink Batch SQL Improvements on Lakehouse

news2024/11/19 20:40:23

本文整理自阿里云研发工程师刘大龙(风离),在 Streaming Lakehouse Meetup 的分享。内容主要分为三个部分:

  1. Flink Batch on Paimon 挑战
  2. Flink Batch 核心优化
  3. 后续规划

点击查看原文视频 & 演讲PPT

一、Flink Batch on Paimon 挑战

众所周知,Paimon 在创立之初就是为了解决流式数仓场景的问题。从下面的架构图里我们可以看到,这里有 Flink CDC 的高效入湖,Flink SQL 进行流式、批式的 ETL、Ad-hoc 分析,用一套引擎完成数据的入湖、分析与查询,整个架构上非常简洁,语义统一,解决了传统 lambda 架构下实时离线的数据一致性问题。

1

Flink 作为一个流批一体的计算引擎,天生就具备上述能力。

作为流计算引擎,Flink 已经是业界的事实标准;在批处理领域,Spark 是业界的事实标准,Flink Batch 虽然整体能力上不差,但是如果想在数据湖分析场景占据一席之地,确实还面临一些挑战。针对 Flink + Paimon 构建流式数仓场景的需求,我们对 Flink Batch 可能存在的问题进行了总结,主要有如下几个方面:

  • Flink 如果作为一个流计算引擎,对于 Schema 变更是没有强需求的,但是和存储结合之后,就需要不断完善这类 API,补齐相关能力;
  • 在数据湖场景,会存在行级的数据更新、删除等需求;
  • 一般湖上的数据都是有版本的,每次的写入与更新,可能都会产生一个新的 Snapshot,因此我们也需要对 Sanpshot 进行管理,比如通过 CALL 命令清理过期 Snapshot,时间旅行查询;
  • 除了数据管理方面的需求,另外一个重要的挑战就是如何通过 Flink Batch 对湖上数据进行高效的 ETL&Ad-hoc 分析,同时还要保证稳定性。

针对这些挑战,从 1.16 版本社区开始投入大量精力对 Flink Batch 做了诸多方面的优化。

二、Flink Batch 核心优化

在介绍 Flink Batch 核心优化之前,首先我们按版本主线回顾一下过去三个版本分别做了哪些重要的功能。

2

  • Flink 1.16 从易用性、稳定性、性能方面做了诸多改进,包括 SQL Gateway、统计信息增强、Join Hint、动态分区裁剪等,该版本是 Flink 批处理里程碑式的版本,也是走向成熟的重要一步。
  • Flink 1.17 持续在批处理方面对性能、稳定性和可用性方面做了显著的改进,包括 Update&Delete API 完善,引入新的 Join Reorder 算法改进 Join 性能,自适应的批处理调度器成为默认的调度器,用户不再需要关心作业并行度等。
  • Flink 1.18 社区继续投入大量精力优化 Batch,完整的支持了湖存储上需要的各类 API,Gateway 支持 JCBC Driver,在执行层面做了 Runtime Filter,多算子融合 CodeGen 等持续优化算子性能。

2.1 Lakehouse API 增强

Flink SQL 在 API 设计这块之前更多的是面向流场景,批场景或数据分析场景的很多 API 都没有考虑也没有去做。从 1.16 版本开始增强这方面的 API,以提供更好的数据管理能力。

3

在数据湖场景中,Schema Evolution 是一个比较常见的需求。于是,我们在 API 层面增强了这些方面的能力,包括支持了各类变更 Schema 的 DDL。在建表方面,我们也支持了 Create/Replace Table As Select 语法,可以直接基于源表简单高效的创建目标表,同时把数据导入到目标表里。

4

其次,增强了数据湖的数据管理相关 API,在时间旅行查询、数据更新和删除、CALL 命令等方面都有所加强。综上所述,Lakehouse API 主要是围绕着数据湖分析场景做了完善了诸多功能。

下面是 Flink 和 Spark 在 API 方面的对比图,这里把其分为 DDL、DML 和 Auxlilary Statements 三类,从图中可以看出,Flink Batch 已经基本追平 Spark。API 上已经比较完善,用户可以尽情的把 Flink Batch 用起来。

5

2.2 Join 优化

当 Flink Batch 易用性方面比较完善之后,那么用的好不好、稳不稳、快不快,就是下一个需要关注的点。

Join 是我们在业务中遇到的最多的场景,尤其是数仓大宽表的场景,可能存在几十个表进行 Join。根据笔者之前做业务的经验来看,很多时候报表出不来,都是因为上游的 Join 太慢。因此对于很多的计算引擎,Join 算子是重点优化的部分。

6

如果想让 Join 执行的快,前提是需要有丰富的统计信息。统计信息对优化器来说非常重要,只有拥有足够丰富的统计信息,它才能优化出高效的执行计划来。所以,我们首先要做的是针对统计信息的优化,这可以通过两步完成。

  • 第一,通过 Analyze Table 语法来做,用户写一个分析统计信息的 SQL,其会转化成 Flink Batch 作业,查询物理存储生成所需的统计信息,然后写回到 Catalog 中。
  • 第二,通过 SuppotReportStatistics 接口来获取,由 Format 或是湖存储来实现这个接口,优化器优化的过程中如果从 Catalog 中拿不到统计信息,那么就可以通过这个接口实时收集统计信息,然后再基于收集到的统计信息进行执行计划的优化。在 Flink 内置的 Format 中,Parquet 和 ORC 等列存格式已支持,另外 Paimon 也已支持。

如果遇到无论用以上哪种方式都拿不到统计信息时,该如何让优化器给出一个合理的 Join 策略呢?这种情况下,在业界也有成熟的解决方案,那就是 Join Hint。

在介绍 Join Hint 之前,先介绍下 Flink Batch Join 底层的算子实现策略。

7

如上图所示,一共有四种 Join 策略,也是业界主流计算引擎采用的 Join 策略。

当统计信息准确的时候,基于 CBO 的优化器是可以给出比较优的执行计划。但是在无统计信息或者统计信息不准时,优化器可能选择出错误的 Join 策略,导致 Join 执行的很慢,或者无法执行成功。针对这种情况,一种解决办法是 Join Hint。在 FLIP-229 中 Flink 提供了 4 种 Join Hint,与上文提到的四种 Join 策略一一对应,每种 Join 策略都有对应的 Hint 策略。具体如下:

  • BROADCAST
  • SHUFFLE_HASH
  • SHUFFLE_MERGE
  • NEST_LOOP

8

介绍完 Join Hint 之后,来介绍下 Join 可能存在的另外一个问题,即多表 Join。针对多表 Join,需要优化器能选择出一个比较优的执行计划,这样才能提高执行效率。

9

以上图 TPC-DS q18 为例,它涉及到了 6 张表的 Join,大表是 catalog_sales 和 customer 相关的一些表,除此之外还有一些小维表等。我们的目标是针对这几张表,通过 Join Reorder 算法,让 Join 顺序相对合理,从而使得 Query 的执行效率最高。

目前,Flink 默认采用了基于左深树的 Join Reorder 算法。针对 q18 这个例子,其优化出来的执行计划如下图所示。

10

什么是左深树呢?左深树如上图所示是二杈树,它的右侧是叶子节点。也就是说先用 catalog_sales 和 date_dim 两个小表进行 Join,输出的 Row Count 是最小的,然后再和剩余的表一一进行比较,然后再选出输出 Row Count 最小的表进行 Join,以此类推。

这是一种贪心的算法,也就是每次 Join 都只看到当前最优的 Join 顺序,然后再继续往后 Join。左深树算法虽然搜索空间小,优化速度很快,但是存在几个问题:首先是很容易陷入局部最优,二是只能按顺序执行,一定只能从左侧最小面的 Join 开始执行。所以当资源比较充足的时候,导致资源利用率不高。另外,左深树算法还会对动态分区裁剪有一定影响,导致某些表无法应用上动态分区裁剪。

基于以上存在的问题,我们在 Flink Batch 1.17 中引入了基于稠密树的 Join Reorder 算法,如下图所示。

11

针对 Q18 这个例子,基于稠密树算法优化出来的执行计划树已经比较平衡了。在 Join 的过程中,catalog_sales 表并不是先和 date_dim 这个维表做 Join,因为它采用的是动态规划的算法,也就是全局枚举,不会只考虑当前的最优,而是全局最优,这就大大提高了 Join 的效率,Q18 的性能提升了一倍以上。

总结来讲,左深树算法是贪心的,不用枚举所有的执行计划,所以速度比较快;稠密树算法基于动态规划,搜索的空间更大,也更费时间。这两种算法分别适用于不同复杂度的业务场景,也各有优缺点,目前优化器会综合考虑 Query 复杂度和优化耗时,在两个算法之间做自适应的切换。

对于 Hive 数仓或是数据湖分析场景,很多时候我们会遇到分区表 Join。对于该类场景,我们是可以在执行层进行优化,比如少读一些不必要的分区,这样就可以大大减少 Join 所需的数据量。

12

下面介绍如何减少无效分区数据读取。

13

对于分区表裁剪,有两种方法,分别是静态分区裁剪和动态分区裁剪。静态分区裁剪要求在 Query 里面一定要指定分区的过滤条件,这样才能在优化阶段裁剪掉。另外一种情况是,没有具体指定哪个分区,但是在 Join 过程中,可以根据维表里数据动态确定要读取的分区,从而动态的进行分区裁剪。

在 FLIP-248 中,提出并引入了动态分区裁剪优化。如下图所示,sold_date 是分区表的分区字段,但是并没有指定读哪些分区。但是在 date_dim 维表中,有“year=2000”这个过滤条件,通过这个条件,在运行时就可以确定需要读取的分区信息,对于不需要读取的分区可以直接过滤掉,减少无效数据量。

14

前面是针对分区表 Join 的优化,那么如果 Join 条件中没有带分区字段,是否也可以减少 Join 需要处理的数据量?事实上针对这个问题也有成熟的解决方案 Runtime Filter,其核心思路是减少 Join 大表侧需要 Shuffle 的数据量。

15

如上图所示,sales 表 Join date_dim 表,item_id 字段是 Join 的等值条件,但是其并不是分区字段,那我们是没法做动态分区裁剪的。虽然没法做动态分区裁剪,但在运行时读取完维表的数据后,我们是可以拿到 item_id 的集合,通过其来减少大表侧需要 Shuffle 的数据量。

16

在 Flink 1.18 版本中,该功能默认是关闭的,大家可以通过 table.optimizer.runtime-filter.enabled 参数打开。

2.3 Runtime 优化

除了上文介绍的 Join 层面的优化,在执行层面也进行了一些优化。这里介绍两个核心的优化,第一个是 Operator Fusion CodeGen,第二个是 Adaptive Batch Scheduler。

(1)Operator Fusion CodeGen

首先我们从一个具体问题切入,来看一下为什么要做 Operator Fusion CodeGen。在跑 TPC-DS 的过程中,对相关 Query 进行 profie 分析的时候,我们从中发现了一些问题。下图是 Q99 的火焰图,通过该图可知,在多次 Join 的过程中,CPU 时间消耗的很分散,有很多无效的 CPU 计算,主要包括下面几个方面:

  • 虚函数调用开销;
  • 中间数据物化到内存的开销;
  • Source Iterator 开销;
  • 多个算子之间的通过 collector 传递数据的开销;
  • 其他无效计算开销。

17

这些框架和算子层面的开销其实是可以省掉的,从而提升 Query 的执行效率。因此我们可以从下面几点进行优化:

  • 尽量避免内存访问,数据驻留在寄存器中;
  • 消除虚函数调用;
  • 编译执行,面向每个 Query 生成最优的代码,执行效率会更高;
  • 从 Source 读完数据之后,用一个 For 循环去处理;
  • 延迟计算。

针对上述优化点,一种成熟的解决方案是 Operator Fusion CodeGen。那什么是 Operator Fusion CodeGen 呢,简称多算子融合 CodeGen,来自于托马斯-诺依曼的论文,其核心思路是把多个算子的代码通过 produce-consume 接口融合到一起,每个算子只生成一部分代码片段,最后把所有算子的代码片段拼接组装在一起,最终只生成一个算子,该算子包含了原来所有算子处理数据逻辑的代码。

18

Operator Fusion CodeGen 核心目标就是尽量把整个 Query 的多个算子通过 CodeGen 的方式编译组装到一个函数或是一个算子里,这样就能尽可能的消除一些冗余的代码和计算,让整个 Pipeline 的数据处理更加高效。

在 FLIP-315 中,我们为 Flink 引入了这个优化,目前支持了 Calc、HashJoin、HashAgg 算子。当前还是个实验性质的功能,默认是关闭的,用户可以通过参数 table.exec.operator.fusion.codegen 打开。

(2)Adaptive Batch Scheduler

Adaptive Batch Scheduler 是另外一个优化,这个在 Flink 1.15 版本中就已经引入了,它解决的是批作业并行度设置的问题。

在流场景中,设置并行度是很正常的事情。但是对于批作业来讲,每天的数据量都可能在变化,而且批作业的数量相比流作业会多很多,这就导致我们无法 case by case 的对每个批作业进行并行度调优,因此也就需要具备自动设置并行度的能力。

19

在 Flink 1.17 版本中,我们将 Adaptive Batch Scheduler 设置为批作业默认的 Scheduler,也就是说用户不需要额外去打开这个功能。除了动态设置并发,后续可能会做更深入的 Adaptive Query Execution,可以动态的调整 Join 策略,以及解倾斜等。

基于上述我们在 QO 和 QE 层面做的优化,Flink Batch 过去几个版本在 TPC-DS 10T 数据集场景下,性能一直在提升,整体时间也已追平主流批计算引擎。

20

2.4 稳定性优化

除了性能方面的优化,我们也在持续优化 Flink Batch 的稳定性。在稳定性方面,做的第一个优化是 Adaptive Hash Join。

21

由于一些历史原因,Flink 的 HashJoin 没有选择纯内存版的 Join 算法,而是选择了 Hybird HashJoin 算法。算法的基本思路是根据 Join key 对 build 端先划分 Partition,当内存不够时,会选择当前占用内存最大的 Partition 进行落盘,释放一部分内存;接着构建新的分区。当 probe 端数据来的时候,会判断当前数据对应的 build 端的 Partition 是否在内存中,如果在内存中,则直接 Join。如果不在内存中,则会把 probe 端数据同样落盘,等前面所有内存中的 Partition 处理完之后再来处理,依次递归处理下去。该算法虽然可以避免 OOM,但也存在一个问题,当 Join key 数据倾斜严重,也就是当某个 Partition 数据量特别大的话,递归会无限循环下去,导致 Join 永远都无法结束。

针对这个问题,在 Flink 1.16 版本对倾斜分区进行了优化,即当它的递归次数大于 3 次之后,说明该 Partition 倾斜已经非常严重了,这个时候可以自适应的 fallback 到 Sort Merge Join 策略来处理,我们把这个过程称作 Adaptive Hash Join。Adaptive Hash Join 的核心思路是把内存中可以放的下的 Partition 用 Hash Join 来处理,内存中放不下的 Partition 用 Sort Merge Join 来处理,这样既保证了性能,又提升了稳定性。

22

Speculative Execution 推测执行

在生产中,很多时候作业是共享集群的,不同的业务跑在同一个集群上,这都可能导致机器热点,使得上面运行的 Flink 任务异常缓慢。这些缓慢的任务会影响整个作业的执行时间,使得作业的产出基线无法得到保障,成为了部分用户使用 Flink 来进行批处理的阻碍。

23

Speculative Execution,也叫推测执行,是一种已经得到普遍的认可、用来解决这类问题的方法,因此我们也在 Flink 1.16 中引入了这套机制。

推测执行方案的整体架构如下图所示,在 FLIP-168 中框架层面对内部算子支持了推测执行,在 FLIP-245 里对 Source 实现了支持;在 FLIP-281 中,对 Sink 实现了支持。总而言之,经过多个版本的迭代,推测执行在 Flink Batch 中的支持已经比较完善,用户可以放心的用起来。

24

2.5 SQL 服务化

25

Flink 是一个流批一体计算引擎,Flink SQL 可以满足 Streaming/Batch/OLAP 三类场景的需求。面对这么多不同类的需求,如果有一个统一的 SQL 服务化组件,可以很方便我们提交 SQL、管理作业,不用每个用户都自己去搭一套服务化组件,避免重复开发。另外,其实最早社区在 Github Ververica 组织下提供了 SQL Gateway,后来由于一些原因就没有再持续开发,但社区一直有用户在用。考虑到 Flink Batch 的需求,以及社区用户的呼声,因此在 1.16 版本社区在 Flink 主仓库引入了 SQL Gateway 组件。

SQL Gateway 是一种支持远程多个客户端并发执行 SQL 的服务化网关,其在架构设计上由可插拔的 Endpoint 和 SQLGatewayService 组成,可以支持不同协议,包括 HTTPS REST 协议、HiveServer2 协议,可以兼容不同 SQL 的语法。

基于前置的工作,在 FLIP-275 中,社区对 SQL Client 也进行了重构,把底座统一架在 SQL Gateway 上,这样两者的能力是共享和对齐的,SQL Client 也就更加灵活。

另外社区提供了 Flink JDBC Driver,其兼容老的 SQL Gateway(底层基于 RestClient),并且可以支持用户以 JDBC 的方式提交 Flink 流作业和批作业,这对已有的批作业迁移到 Flink 上也很方便,客户端只需要把 JDBC Driver 换成 Flink 的即可,无需大的改动。

三、后续规划

上文介绍了 Flink Batch 过去三个版本做的一些核心优化,后续我们也会在 Flink Batch 上持续投入,主要会从两个方面去做。首先在引擎层面会持续进行优化,比如继续完善 OFCG、Runtime Filter 等,同时也会考虑去支持 Adaptive Query Execution。

26

其次,我们会花更多精力在用户落地方面,比如去对接数据湖存储 Paimon、Hudi、Iceberg 等,在新兴数据湖分析场景持续打磨 Flink Batch 引擎。

Q&A

Q:请问 SQL Gateway 在 Flink 社区是否有长线规划?未来是否会跟 Kyuubi 竞争?
A:目前没有这样的计划,因为 SQL Gateway 更多考虑还是面向 Flink 本身。Flink 是流批一体的计算引擎,Gateway 在设计上,更多的兼容了 Flink 流批两种模式。Kyuubi 是一个独立社区,它集成了 Flink SQL,但是主要面向 Hive/Spark 等 Batch 生态,在流模式的服务化上支持的不太完善。从长远来看,社区目前没有将 SQL Gateway 变成独立的外部 Service 组件的计划。

Q:请问通过优化器优化掉的数据,未来是否可以再恢复?
A:如果是基于 CBO 的优化,优化器在优化的过程中产生的 Plan 都是会保留的,只是它最终会根据不同的 Plan 计算 cost,哪个最小就会选哪个。

点击查看原文视频 & 演讲PPT


Flink Forward Asia 2023 正式启动

点击查看活动详情

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

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

相关文章

MySQL数据库入门到精通3--进阶篇(存储引擎,索引)

1. 存储引擎 1.1 MySQL体系结构 1). 连接层 最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认…

selenium自动化测试-获取黄金实时价格

最近黄金比较火爆,想要获取黄金实时价格,方便后续监控预警价格,一般实时刷新的网页数据都是动态加载的,需要用到selenium自动化测试获取动态页面数据。 昨天学会了获取动态网页小说内容,同理也可以获取动态网页的黄金…

头歌平台 | 逻辑函数及其描述工具logisim使用

文章目录 1、根据布尔表达式绘制电路2、根据真值表绘制电路3、根据简化真值表绘制电路4、根据波形图绘制电路5、根据卡诺图绘制电路 1、根据布尔表达式绘制电路 任务描述 本关任务:在Logisim中根据给定的布尔代数表达式(FABBCCA)绘制逻辑电路…

文案内容千篇一律,软文推广如何加深用户印象

随着互联网技术的发展,企业营销的方式逐渐转向软文推广,但是现在软文推广的内容同质化越来越严重,企业应该如何让自己的软文推广保持差异性,在用户心中留下独特的印象呢?下面就让媒介盒子告诉你。 一、 找出产品独特卖…

spring boot 时间格式化输出

目录标题 一、spring boot 序列化二、 JsonFormat(pattern "yyyy-MM-dd HH:mm:ss")和JSONField(format "yyyy-MM-dd HH:mm:ss")区别三、在实体类中序列化时间(格式化输出)(一)使用JsonFormat(二…

程序员自由创业周记#12:999%

下载量涨了999% 在此之前,我的Apple开发账号上只有一个产品-学伟扫描,因为没有推广,只靠自然流量,每天的下载量寥寥无几,这种稳定无人问津的状态断断续续保持了4年。 之前的周记里介绍了最近在做创业的第二个项目-学伟…

27 WEB漏洞-XSS跨站之代码及httponly绕过

目录 HttpOnly安全过滤测试HttpOnly安全过滤绕过思路 演示案例:Xsslabs关卡代码过滤绕过测试 HttpOnly安全过滤测试 防止xss攻击,指的是攻击手法,并不是能防止XSS漏洞,httponly阻止的仅仅只是cookie httponly在相关的脚本都是支持…

AMEYA360 | 罗姆ROHM面向工业设备应用的产品目录上线

作为半导体和电子元器件制造商,罗姆集团自成立后60多年以来,一直秉持“质量第一”的企业目的,为消费电子设备和IT设备、汽车以及工业设备等多个领域源源不断地提供高品质、可信赖的产品。 随着“节能”和“小型化”需求的不断高涨&#xff0c…

PLC项目调试常见的8种错误类型

各种品牌PLC都具有自我诊断功能,但PLC修理的技巧在于,充分运用该功能进行分析,然后精确寻找问题所在。整理了当PLC呈现反常报警时,PLC修理人员需要了解的8种常见错误类型。 CPU反常 CPU反常报警时,应查看CPU单元衔接于…

Qt中使用图像格式对QPainter绘制文字影响

图 1 是 QImage::Format_RGB888绘制效果,图二是QImage::Format_RGB32绘制效果,可见在使用QImage::Format_RGB32进行绘制文字效果更好,从现象提示我们,对QPainter在QImage改善文字绘制效果不仅可以设置抗锯齿,图像保存格…

STC15F104W控制3个74HC595芯片输出数码管显示

一、74HC595脚位图及说明 管脚说明: 14脚:DS(SER),串行数据输入引脚 13脚:OE,输出使能控制脚,它是低电才使能输出,所以接GND 12脚:RCK(STCP&…

C语言每日一题(10):无人生还

文章主题:无人生还🔥所属专栏:C语言每日一题📗作者简介:每天不定时更新C语言的小白一枚,记录分享自己每天的所思所想😄🎶个人主页:[₽]的个人主页🏄&#x1f…

Mojo编程语言是AI人工智能的新的编程语言

Mojo是Chris Lattner的创业公司Modular开发的一种新的编程语言,旨在统一AI基建和异构计算。Mojo被认为是Python的超集,兼容Python生态,但添加了系统编程和编译期优化的特性,以提高性能和部署效率。Mojo基于MLIR,可以支…

RockTree TOKEN2049 Party爆火,一场千亿规模的“超级聚会”

今年 9 月 11 日至 17 日期间,在新加坡举办的 TOKEN2049 大会,成为了今年同类活动中规模最大、最火爆的一次 Web3 行业盛会。据悉,本届 TOKEN2049 迎来了来自 3,500 多个组织超 10,000 名与会者,并有一众重磅加密行业嘉宾出席会议…

Android 混淆使用及其字典混淆(Proguard)

1.使用背景 ProGuard能够通过压缩、优化、混淆、预检等操作,检测并删除未使用的类,字段,方法和属性,分析和优化字节码,使用简短无意义的名称来重命名类,字段和方法。从而使代码更小、更高效、更难进行逆向工程。 Android代码混淆…

实时数仓混沌演练实践

一、背景介绍 目前实时数仓提供的投放实时指标优先级别越来越重要,不再是单独的报表展示等功能,特别是提供给下游规则引擎的相关数据,直接对投放运营的广告投放产生直接影响,数据延迟或者异常均可能产生直接或者间接的资产损失。…

【项目总结】C++ 云盘

项目介绍 本项目是一款分布式云存储软件,旨在提供强大的文件存储和共享功能。 因为要运行高并发量的访问,所以进行了服务器的集群,也就是要有多台web服务器,每台web服务器中部署相同的程序,为了让这几台web服务器的负…

【VSCode 插件商城无法搜索到插件的解决方法】

背景 因为本地电脑安装的开发软件较多,导致电脑变得很卡,所有申请一个虚拟机作为开发机,安装完VScode之后发现无法搜索到插件,于是便想把本地电脑上VScode装好的插件复制到虚拟机上。 实现 VSCode 的插件存在 【C/用户/用户名/…

关于ubuntu设置sh文件开机自启动python3和sudo python3问题

关于ubuntu设置sh文件开机自启动python3和sudo python3问题 说明系统为 ubuntu22.04python是python3.10.12ros系统为ros2 humble 背景解决方法补充 说明 系统为 ubuntu22.04 python是python3.10.12 ros系统为ros2 humble 背景 将一个py文件设置为开机自启动,服…

如何对pdf文件进行压缩?

如何对pdf文件进行压缩?一般来说,PDF文件里面一般会包含大量的图像、文本和其他类型的独裁,这使得它们的文件大小相对于其他文档要大得多(其实主要是pdf文件里面包含的大量图片,尤其是高清拖)。由于pdf文件…