Adaptive让 Spark SQL 更高效更智能

2023-11-12

本文转发自技术世界原文链接 http://www.jasongj.com/spark/adaptive_execution/

1 背景

前面《Spark SQL / Catalyst 内部原理 与 RBO》与《Spark SQL 性能优化再进一步 CBO 基于代价的优化》介绍的优化,从查询本身与目标数据的特点的角度尽可能保证了最终生成的执行计划的高效性。但是

  • 执行计划一旦生成,便不可更改,即使执行过程中发现后续执行计划可以进一步优化,也只能按原计划执行
  • CBO 基于统计信息生成最优执行计划,需要提前生成统计信息,成本较大,且不适合数据更新频繁的场景
  • CBO 基于基础表的统计信息与操作对数据的影响推测中间结果的信息,只是估算,不够精确

本文介绍的 Adaptive Execution 将可以根据执行过程中的中间数据优化后续执行,从而提高整体执行效率。核心在于两点

  • 执行计划可动态调整
  • 调整的依据是中间结果的精确统计信息

2 动态设置 Shuffle Partition

2.1 Spark Shuffle 原理

Spark Shuffle 一般用于将上游 Stage 中的数据按 Key 分区,保证来自不同 Mapper (表示上游 Stage 的 Task)的相同的 Key 进入相同的 Reducer (表示下游 Stage 的 Task)。一般用于 group by 或者 Join 操作。
Spark Shuffle 过程

如上图所示,该 Shuffle 总共有 2 个 Mapper 与 5 个 Reducer。每个 Mapper 会按相同的规则(由 Partitioner 定义)将自己的数据分为五份。每个 Reducer 从这两个 Mapper 中拉取属于自己的那一份数据。

2.2 原有 Shuffle 的问题

使用 Spark SQL 时,可通过 spark.sql.shuffle.partitions 指定 Shuffle 时 Partition 个数,也即 Reducer 个数

该参数决定了一个 Spark SQL Job 中包含的所有 Shuffle 的 Partition 个数。如下图所示,当该参数值为 3 时,所有 Shuffle 中 Reducer 个数都为 3
Spark SQL with multiple Shuffle

这种方法有如下问题

  • Partition 个数不宜设置过大
    • Reducer(代指 Spark Shuffle 过程中执行 Shuffle Read 的 Task) 个数过多,每个 Reducer 处理的数据量过小。大量小 Task 造成不必要的 Task 调度开销与可能的资源调度开销(如果开启了 Dynamic Allocation)
    • Reducer 个数过大,如果 Reducer 直接写 HDFS 会生成大量小文件,从而造成大量 addBlock RPC,Name node 可能成为瓶颈,并影响其它使用 HDFS 的应用
    • 过多 Reducer 写小文件,会造成后面读取这些小文件时产生大量 getBlock RPC,对 Name node 产生冲击
  • Partition 个数不宜设置过小
    • 每个 Reducer 处理的数据量太大,Spill 到磁盘开销增大
    • Reducer GC 时间增长
    • Reducer 如果写 HDFS,每个 Reducer 写入数据量较大,无法充分发挥并行处理优势
  • 很难保证所有 Shuffle 都最优
    • 不同的 Shuffle 对应的数据量不一样,因此最优的 Partition 个数也不一样。使用统一的 Partition 个数很难保证所有 Shuffle 都最优
    • 定时任务不同时段数据量不一样,相同的 Partition 数设置无法保证所有时间段执行时都最优

2.3 自动设置 Shuffle Partition 原理

Spark Shuffle 原理 一节图中所示,Stage 1 的 5 个 Partition 数据量分别为 60MB,40MB,1MB,2MB,50MB。其中 1MB 与 2MB 的 Partition 明显过小(实际场景中,部分小 Partition 只有几十 KB 及至几十字节)

开启 Adaptive Execution 后

  • Spark 在 Stage 0 的 Shuffle Write 结束后,根据各 Mapper 输出,统计得到各 Partition 的数据量,即 60MB,40MB,1MB,2MB,50MB
  • 通过 ExchangeCoordinator 计算出合适的 post-shuffle Partition 个数(即 Reducer)个数(本例中 Reducer 个数设置为 3)
  • 启动相应个数的 Reducer 任务
  • 每个 Reducer 读取一个或多个 Shuffle Write Partition 数据(如下图所示,Reducer 0 读取 Partition 0,Reducer 1 读取 Partition 1、2、3,Reducer 2 读取 Partition 4)
    Spark SQL adaptive reducer 1

三个 Reducer 这样分配是因为

  • targetPostShuffleInputSize 默认为 64MB,每个 Reducer 读取数据量不超过 64MB
  • 如果 Partition 0 与 Partition 2 结合,Partition 1 与 Partition 3 结合,虽然也都不超过 64 MB。但读完 Partition 0 再读 Partition 2,对于同一个 Mapper 而言,如果每个 Partition 数据比较少,跳着读多个 Partition 相当于随机读,在 HDD 上性能不高
  • 目前的做法是只结合相临的 Partition,从而保证顺序读,提高磁盘 IO 性能
  • 该方案只会合并多个小的 Partition,不会将大的 Partition 拆分,因为拆分过程需要引入一轮新的 Shuffle
  • 基于上面的原因,默认 Partition 个数(本例中为 5)可以大一点,然后由 ExchangeCoordinator 合并。如果设置的 Partition 个数太小,Adaptive Execution 在此场景下无法发挥作用

由上图可见,Reducer 1 从每个 Mapper 读取 Partition 1、2、3 都有三根线,是因为原来的 Shuffle 设计中,每个 Reducer 每次通过 Fetch 请求从一个特定 Mapper 读数据时,只能读一个 Partition 的数据。也即在上图中,Reducer 1 读取 Mapper 0 的数据,需要 3 轮 Fetch 请求。对于 Mapper 而言,需要读三次磁盘,相当于随机 IO。

为了解决这个问题,Spark 新增接口,一次 Shuffle Read 可以读多个 Partition 的数据。如下图所示,Task 1 通过一轮请求即可同时读取 Task 0 内 Partition 0、1 和 2 的数据,减少了网络请求数量。同时 Mapper 0 一次性读取并返回三个 Partition 的数据,相当于顺序 IO,从而提升了性能。
Spark SQL adaptive reducer 2

由于 Adaptive Execution 的自动设置 Reducer 是由 ExchangeCoordinator 根据 Shuffle Write 统计信息决定的,因此即使在同一个 Job 中不同 Shuffle 的 Reducer 个数都可以不一样,从而使得每次 Shuffle 都尽可能最优。

上文 原有 Shuffle 的问题 一节中的例子,在启用 Adaptive Execution 后,三次 Shuffle 的 Reducer 个数从原来的全部为 3 变为 2、4、3。

Spark SQL with adaptive Shuffle

2.4 使用与优化方法

可通过 spark.sql.adaptive.enabled=true 启用 Adaptive Execution 从而启用自动设置 Shuffle Reducer 这一特性

通过 spark.sql.adaptive.shuffle.targetPostShuffleInputSize 可设置每个 Reducer 读取的目标数据量,其单位是字节,默认值为 64 MB。上文例子中,如果将该值设置为 50 MB,最终效果仍然如上文所示,而不会将 Partition 0 的 60MB 拆分。具体原因上文已说明

3 动态调整执行计划

3.1 固定执行计划的不足

在不开启 Adaptive Execution 之前,执行计划一旦确定,即使发现后续执行计划可以优化,也不可更改。如下图所示,SortMergJoin 的 Shuffle Write 结束后,发现 Join 一方的 Shuffle 输出只有 46.9KB,仍然继续执行 SortMergeJoin
Spark SQL with fixed DAG

此时完全可将 SortMergeJoin 变更为 BroadcastJoin 从而提高整体执行效率。

3.2 SortMergeJoin 原理

SortMergeJoin 是常用的分布式 Join 方式,它几乎可使用于所有需要 Join 的场景。但有些场景下,它的性能并不是最好的。

SortMergeJoin 的原理如下图所示

  • 将 Join 双方以 Join Key 为 Key 按照 HashPartitioner 分区,且保证分区数一致
  • Stage 0 与 Stage 1 的所有 Task 在 Shuffle Write 时,都将数据分为 5 个 Partition,并且每个 Partition 内按 Join Key 排序
  • Stage 2 启动 5 个 Task 分别去 Stage 0 与 Stage 1 中所有包含 Partition 分区数据的 Task 中取对应 Partition 的数据。(如果某个 Mapper 不包含该 Partition 的数据,则 Redcuer 无须向其发起读取请求)。
  • Stage 2 的 Task 2 分别从 Stage 0 的 Task 0、1、2 中读取 Partition 2 的数据,并且通过 MergeSort 对其进行排序
  • Stage 2 的 Task 2 分别从 Stage 1 的 Task 0、1 中读取 Partition 2 的数据,且通过 MergeSort 对其进行排序
  • Stage 2 的 Task 2 在上述两步 MergeSort 的同时,使用 SortMergeJoin 对二者进行 Join

Spark SQL SortMergeJoin

3.3 BroadcastJoin 原理

当参与 Join 的一方足够小,可全部置于 Executor 内存中时,可使用 Broadcast 机制将整个 RDD 数据广播到每一个 Executor 中,该 Executor 上运行的所有 Task 皆可直接读取其数据。(本文中,后续配图,为了方便展示,会将整个 RDD 的数据置于 Task 框内,而隐藏 Executor)

对于大 RDD,按正常方式,每个 Task 读取并处理一个 Partition 的数据,同时读取 Executor 内的广播数据,该广播数据包含了小 RDD 的全量数据,因此可直接与每个 Task 处理的大 RDD 的部分数据直接 Join
Spark SQL BroadcastJoin

根据 Task 内具体的 Join 实现的不同,又可分为 BroadcastHashJoin 与 BroadcastNestedLoopJoin。后文不区分这两种实现,统称为 BroadcastJoin

与 SortMergeJoin 相比,BroadcastJoin 不需要 Shuffle,减少了 Shuffle 带来的开销,同时也避免了 Shuffle 带来的数据倾斜,从而极大地提升了 Job 执行效率

同时,BroadcastJoin 带来了广播小 RDD 的开销。另外,如果小 RDD 过大,无法存于 Executor 内存中,则无法使用 BroadcastJoin

对于基础表的 Join,可在生成执行计划前,直接通过 HDFS 获取各表的大小,从而判断是否适合使用 BroadcastJoin。但对于中间表的 Join,无法提前准确判断中间表大小从而精确判断是否适合使用 BroadcastJoin

Spark SQL 性能优化再进一步 CBO 基于代价的优化》一文介绍的 CBO 可通过表的统计信息与各操作对数据统计信息的影响,推测出中间表的统计信息,但是该方法得到的统计信息不够准确。同时该方法要求提前分析表,具有较大开销

而开启 Adaptive Execution 后,可直接根据 Shuffle Write 数据判断是否适用 BroadcastJoin

3.4 动态调整执行计划原理

如上文 SortMergeJoin 原理 中配图所示,SortMergeJoin 需要先对 Stage 0 与 Stage 1 按同样的 Partitioner 进行 Shuffle Write

Shuffle Write 结束后,可从每个 ShuffleMapTask 的 MapStatus 中统计得到按原计划执行时 Stage 2 各 Partition 的数据量以及 Stage 2 需要读取的总数据量。(一般来说,Partition 是 RDD 的属性而非 Stage 的属性,本文为了方便,不区分 Stage 与 RDD。可以简单认为一个 Stage 只有一个 RDD,此时 Stage 与 RDD 在本文讨论范围内等价)

如果其中一个 Stage 的数据量较小,适合使用 BroadcastJoin,无须继续执行 Stage 2 的 Shuffle Read。相反,可利用 Stage 0 与 Stage 1 的数据进行 BroadcastJoin,如下图所示
Spark SQL Auto BroadcastJoin

具体做法是

  • 将 Stage 1 全部 Shuffle Write 结果广播出去
  • 启动 Stage 2,Partition 个数与 Stage 0 一样,都为 3
  • 每个 Stage 2 每个 Task 读取 Stage 0 每个 Task 的 Shuffle Write 数据,同时与广播得到的 Stage 1 的全量数据进行 Join

**注:**广播数据存于每个 Executor 中,其上所有 Task 共享,无须为每个 Task 广播一份数据。上图中,为了更清晰展示为什么能够直接 Join 而将 Stage 2 每个 Task 方框内都放置了一份 Stage 1 的全量数据

虽然 Shuffle Write 已完成,将后续的 SortMergeJoin 改为 Broadcast 仍然能提升执行效率

  • SortMergeJoin 需要在 Shuffle Read 时对来自 Stage 0 与 Stage 1 的数据进行 Merge Sort,并且可能需要 Spill 到磁盘,开销较大
  • SortMergeJoin 时,Stage 2 的所有 Task 需要取 Stage 0 与 Stage 1 的所有 Task 的输出数据(如果有它要的数据 ),会造成大量的网络连接。且当 Stage 2 的 Task 较多时,会造成大量的磁盘随机读操作,效率不高,且影响相同机器上其它 Job 的执行效率
  • SortMergeJoin 时,Stage 2 每个 Task 需要从几乎所有 Stage 0 与 Stage 1 的 Task 取数据,无法很好利用 Locality
  • Stage 2 改用 Broadcast,每个 Task 直接读取 Stage 0 的每个 Task 的数据(一对一),可很好利用 Locality 特性。最好在 Stage 0 使用的 Executor 上直接启动 Stage 2 的 Task。如果 Stage 0 的 Shuffle Write 数据并未 Spill 而是在内存中,则 Stage 2 的 Task 可直接读取内存中的数据,效率非常高。如果有 Spill,那可直接从本地文件中读取数据,且是顺序读取,效率远比通过网络随机读数据效率高

3.5 使用与优化方法

该特性的使用方式如下

  • spark.sql.adaptive.enabledspark.sql.adaptive.join.enabled 都设置为 true 时,开启 Adaptive Execution 的动态调整 Join 功能
  • spark.sql.adaptiveBroadcastJoinThreshold 设置了 SortMergeJoin 转 BroadcastJoin 的阈值。如果不设置该参数,该阈值与 spark.sql.autoBroadcastJoinThreshold 的值相等
  • 除了本文所述 SortMergeJoin 转 BroadcastJoin,Adaptive Execution 还可提供其它 Join 优化策略。部分优化策略可能会需要增加 Shuffle。spark.sql.adaptive.allowAdditionalShuffle 参数决定了是否允许为了优化 Join 而增加 Shuffle。其默认值为 false

4 自动处理数据倾斜

4.1 解决数据倾斜典型方案

Spark性能优化之道——解决Spark数据倾斜(Data Skew)的N种姿势》一文讲述了数据倾斜的危害,产生原因,以及典型解决方法

  • 保证文件可 Split 从而避免读 HDFS 时数据倾斜
  • 保证 Kafka 各 Partition 数据均衡从而避免读 Kafka 引起的数据倾斜
  • 调整并行度或自定义 Partitioner 从而分散分配给同一 Task 的大量不同 Key
  • 使用 BroadcastJoin 代替 ReduceJoin 消除 Shuffle 从而避免 Shuffle 引起的数据倾斜
  • 对倾斜 Key 使用随机前缀或后缀从而分散大量倾斜 Key,同时将参与 Join 的小表扩容,从而保证 Join 结果的正确性

4.2 自动解决数据倾斜

目前 Adaptive Execution 可解决 Join 时数据倾斜问题。其思路可理解为将部分倾斜的 Partition (倾斜的判断标准为该 Partition 数据是所有 Partition Shuffle Write 中位数的 N 倍) 进行单独处理,类似于 BroadcastJoin,如下图所示
Spark SQL resolve joinm skew

在上图中,左右两边分别是参与 Join 的 Stage 0 与 Stage 1 (实际应该是两个 RDD 进行 Join,但如同上文所述,这里不区分 RDD 与 Stage),中间是获取 Join 结果的 Stage 2

明显 Partition 0 的数据量较大,这里假设 Partition 0 符合“倾斜”的条件,其它 4 个 Partition 未倾斜

以 Partition 对应的 Task 2 为例,它需获取 Stage 0 的三个 Task 中所有属于 Partition 2 的数据,并使用 MergeSort 排序。同时获取 Stage 1 的两个 Task 中所有属于 Partition 2 的数据并使用 MergeSort 排序。然后对二者进行 SortMergeJoin

对于 Partition 0,可启动多个 Task

  • 在上图中,启动了两个 Task 处理 Partition 0 的数据,分别名为 Task 0-0 与 Task 0-1
  • Task 0-0 读取 Stage 0 Task 0 中属于 Partition 0 的数据
  • Task 0-1 读取 Stage 0 Task 1 与 Task 2 中属于 Partition 0 的数据,并进行 MergeSort
  • Task 0-0 与 Task 0-1 都从 Stage 1 的两个 Task 中所有属于 Partition 0 的数据
  • Task 0-0 与 Task 0-1 使用 Stage 0 中属于 Partition 0 的部分数据与 Stage 1 中属于 Partition 0 的全量数据进行 Join

通过该方法,原本由一个 Task 处理的 Partition 0 的数据由多个 Task 共同处理,每个 Task 需处理的数据量减少,从而避免了 Partition 0 的倾斜

对于 Partition 0 的处理,有点类似于 BroadcastJoin 的做法。但区别在于,Stage 2 的 Task 0-0 与 Task 0-1 同时获取 Stage 1 中属于 Partition 0 的全量数据,是通过正常的 Shuffle Read 机制实现,而非 BroadcastJoin 中的变量广播实现

4.3 使用与优化方法

开启与调优该特性的方法如下

  • spark.sql.adaptive.skewedJoin.enabled 设置为 true 即可自动处理 Join 时数据倾斜
  • spark.sql.adaptive.skewedPartitionMaxSplits 控制处理一个倾斜 Partition 的 Task 个数上限,默认值为 5
  • spark.sql.adaptive.skewedPartitionRowCountThreshold 设置了一个 Partition 被视为倾斜 Partition 的行数下限,也即行数低于该值的 Partition 不会被当作倾斜 Partition 处理。其默认值为 10L * 1000 * 1000 即一千万
  • spark.sql.adaptive.skewedPartitionSizeThreshold 设置了一个 Partition 被视为倾斜 Partition 的大小下限,也即大小小于该值的 Partition 不会被视作倾斜 Partition。其默认值为 64 * 1024 * 1024 也即 64MB
  • spark.sql.adaptive.skewedPartitionFactor 该参数设置了倾斜因子。如果一个 Partition 的大小大于 spark.sql.adaptive.skewedPartitionSizeThreshold 的同时大于各 Partition 大小中位数与该因子的乘积,或者行数大于 spark.sql.adaptive.skewedPartitionRowCountThreshold 的同时大于各 Partition 行数中位数与该因子的乘积,则它会被视为倾斜的 Partition

5 Spark 系列文章

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Adaptive让 Spark SQL 更高效更智能 的相关文章

  • SparkStreaming知识总结

    一 流式计算的概述 1 1 什么是流式计算 1 数据流与静态数据的区别 数据流指的就是不断产生的数据 是源源不断 不会停止 静态数据指的就是存储在磁盘中的固定的数据 2 流式计算的概念 就是对数据流进行计算 由于数据是炼苗不断的产生的 所以
  • Spark(七)——累加器和广播变量

    5 累加器 通过在驱动器中调用SparkContext accumulator initialValue 方法 创建出存有初始值的累加器 返回值为org apache spark Accumulator T 对象 其中 T 是初始值 ini
  • Spark性能调优之Shuffle调优

    Spark性能调优之Shuffle调优 Spark底层shuffle的传输方式是使用netty传输 netty在进行网络传输的过程会申请堆外内存 netty是零拷贝 所以使用了堆外内存 shuffle过程中常出现的问题 常见问题一 redu
  • Spark基础知识(个人总结)

    声明 1 本文为我的个人复习总结 并非那种从零基础开始普及知识 内容详细全面 言辞官方的文章 2 由于是个人总结 所以用最精简的话语来写文章 3 若有错误不当之处 请指出 一 Spark概述 Spark模块 Core SQL Streami
  • Hudi 0.12.0 搭建——集成 Hive3.1 与 Spark3.2

    Hudi 搭建 https blog csdn net weixin 46389691 article details 128276527 环境准备 一 安装 Maven 1 解压 2 配置环境变量 3 修改 Maven 下载源 二 安装
  • Spark课程设计——电影推荐系统

    题目所需数据集及相应信息描述 数据集 1 用户评分数据集ratings dat 包含了大量用户的历史评分数据 2 样本评分数据集personalRatings dat 包含了少数几个用户的个性化评分数据 这些数据反映了某个用户的个性化观影喜
  • Spark DataFrame的Join操作和withColumn、withColumnRenamed方法实践案例(Scala Demo代码)

    import org apache log4j Level Logger import org apache spark sql SparkSession import org apache spark sql functions obje
  • Spark on Kubernetes 与 Spark on Yarn 不完全对比分析

    前言 Apache Spark 是目前应用最广泛的大数据分析计算工具之一 它擅长于批处理和实时流处理 并支持机器学习 人工智能 自然语言处理和数据分析应用 随着 Spark 越来越受欢迎 使用量越来越大 狭义上的 Hadoop MR 技术栈
  • 【Spark系列2】reduceByKey和groupByKey区别与用法

    在spark中 我们知道一切的操作都是基于RDD的 在使用中 RDD有一种非常特殊也是非常实用的format pair RDD 即RDD的每一行是 key value 的格式 这种格式很像Python的字典类型 便于针对key进行一些处理
  • 大数据相关常用软件下载地址集锦

    文章目录 每日一句正能量 前言 一 软件下载地址如下 二 文档地址如下 结语 每日一句正能量 生命中有一些人与我们擦肩了 却来不及遇见 遇见了 却来不及相识 相识了 却来不及熟悉 熟悉了 却还是要说再见 前言 由于大数据开发中经常需要用到Z
  • 深入理解 SQL 中的 Grouping Sets 语句

    前言 SQL 中 Group By 语句大家都很熟悉 根据指定的规则对数据进行分组 常常和聚合函数一起使用 比如 考虑有表 dealer 表中数据如下 id Int city String car model String quantity
  • 浅谈Hadoop体系和MPP体系

    浅谈Hadoop体系和MPP体系 引言 如题 在大数据发展至今 为了应对日益繁多的数据分析处理 和解决客户各种奇思妙 怪 想需求 形形色色的大数据处理的框架和对应的数据存储手段层出不穷 有老当益壮的Hadoop体系 依靠Hadoop巨大的社
  • dolphinschedule使用shell任务结束状态研究

    背景 配置的dolphin任务 使用的是shell shell里包含了spark submit 如下截图 dolphin shell 介绍完毕 开始说明现象 有天有人调整了集群的cdp配置 executor cores max 1 我之前这
  • spark算子执行位置研究,driver端?executor端?

    参考资料 https cloud tencent com developer article 1545723 前言 spark算子的执行位置 driver端 还是executor端 这些之前其实没有注意过 最近在学流处理 发现这个还是很重要
  • Spark Job写文件个数的控制以及小文件合并的一个优化

    文章目录 背景说明 通过引入额外Shuffle对写入数据进行合并 EnsureRepartitionForWriting Rule CoalesceShufflePartitions Rule OptimizeShuffleWithLoca
  • spark_hadoop集群搭建自动化脚本

    bin bash 脚本使用说明 1 使用脚本前需要弄好服务器的基础环境 2 在hadoop的每个节点需要手动创建如下目录 data hdfs tmp 3 修改下面的配置参数 4 脚本执行完备后需要收到格式化namenode
  • Spark 【分区与并行度】

    RDD 并行度和分区 SparkConf setMaster local 我们在创建 SparkContext 对象时通常会指定 SparkConf 参数 它包含了我们运行时的配置信息 如果我们的 setMaster 中的参数是 local
  • JAVA 安装与简单使用

    JAVA简易安装 下载安装 环境变量 进入变量界面 设置变量 验证JAVA环境 运行Java程序 个人站 ghzzz cn 还在备案 很快就能访问了 下载安装 第一步当然是从官网下载安装java了 网上有很多的教程 这里简单的写一下 在这里
  • Spark 中 BroadCast 导致的内存溢出(SparkFatalException)

    背景 本文基于 Spark 3 1 1 open jdk 1 8 0 352 目前在排查 Spark 任务的时候 遇到了一个很奇怪的问题 在此记录一下 现象描述 一个 Spark Application Driver端的内存为 5GB 一直
  • spark相关

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 提示 这里可以添加本文要记录的大概内容 例如 随着人工智能的不断发展 机器学习这门

随机推荐

  • 【React】hooks的原理

    https medium com ryardley react hooks not magic just arrays cd4f1857236e 参考了这篇文章 对hooks的实现有初步的了解 具体的还是得研究一下官方的 这篇文章用了一个简
  • pptp和l2tp有什么区别

    PPTP协议是点对点隧道协议 其将控制包与数据包分开 控制包采用TCP控制 用于严格的状态查询及信令信息 数据包部分先封装在PPP协议中 然后封装到GREV2协议中 L2TP是国际标准隧道协议 它结合了PPTP协议以及第二层转发L2F协议的
  • 转:基于 Python 和 Scikit-Learn 的机器学习介绍

    我叫Alex 我在机器学习和网络图分析 主要是理论 有所涉猎 我同时在为一家俄罗斯移动运营商开发大数据产品 这是我第一次在网上写文章 不喜勿喷 现在 很多人想开发高效的算法以及参加机器学习的竞赛 所以他们过来问我 该如何开始 一段时间以前
  • 7天学完Spring:基础学习结束,关于Spring事务及其传播机制

    目录 前言 一丶Spring中事务的实现 lt 1 gt MySQL中的事务使用 回顾 lt 2 gt 手动操作事务 lt 3 gt 自动操作事务 1 gt 作用域说明 2 gt 参数说明 3 gt Transactional 工作原理 二
  • PPPoE Server防止ARP***

    在一般情况下 只要有一台计算机感染ARP病毒就可能造成此网段中所有计算机上网时断时续或缓慢等其它不正常现象 为了保障网络正常运行 针对ARP病毒的猖獗和破坏性 我们也已有一些应对措施 这些措施有的尽管能解一时之急 但不能从根本上彻底解决问题
  • HIVE-执行命令的几种方式 和 hive -e 和hive -f的使用

    第一种 在bash中直接通过hive e命令 并用 gt 输出流把执行结果输出到制定文件 hive e select from test hour rate2 where year 2019 gt tmp output 1 txt 第二种
  • 流明(lux)和坎德拉;

    流明是光照度 坎德拉是光强 流明是光通量的单位 cd是光强单位 光强是单位立体角的光通量 照度是单位面积的光通量 尼特是亮度单位 1尼特 1CD m 2 1 lx 1 流明每平方米 面发光度 光照度 纸面的反射系数 发光强度1坎德拉 cd
  • C++中for( : )用法

    常用的遍历数组的写法 随机定义的数组 int array 10 1 2 3 4 5 6 7 8 9 10 for int i 0 i lt 10 i cout lt lt array i lt lt 输出 1 2 3 4 5 6 7 8 9
  • Vuex安装时报错“Could not resolve dependency: npm ERR peer vue@“^3.0.2“ from vuex@4.0.2”

    报错的原因 安装的版本过高的原因造成的 解决方法 1 可以npm view vuex versions json查版本 找适合的版本 不要最新的 2 npm install vuex 3 6 2 save根据版本下载 这样就可以了
  • 第七届蓝桥杯省赛C++A/B组 最大比例

    X星球的某个大奖赛设了 M 级奖励 每个级别的奖金是一个正整数 并且 相邻的两个级别间的比例是个固定值 也就是说 所有级别的奖金数构成了一个等比数列 比如 16 24 36 54 其等比值为 3 2 现在 我们随机调查了一些获奖者的奖金数
  • sprintf, snprintf, _snprintf, sprintf_s 等的区别

    先放结论 1 在支持snpritf的编译器 只使用int snprintf char buffer size t count const char format argument 无论成功或者失败 都会返回字符串的总长度 不包括结束符 如果
  • 计算机网络之网络层

    网络层涉及的问题 1一般是网关 18 是外网 内网有两类 1 存储转发包交换 2 提供给传输层的服务 3 非连接服务的实现 4 面向连接服务的实现 5 虚电路和数据包的比较 OSPF开放式最短路径优先 自治域 cisco路由器 4种延迟 传
  • 批量修改文件夹名称——规则重命名(Excel+Python脚本两种方式)

    批量修改文件夹名称 场景 在进行神经网络训练的时候 有些时候获取到的数据集的命名是不规则的 不便于直观理解数据的结构 由此需要进行批量重命名 本文提供Excel Python脚本两种方式 Excel 如下图所示 文件是命名是乱序无规则的 在
  • QT信号槽跨线程传递QDataStream问题

    第一点 查看QDataStream类 可以发现这一句 Q DISABLE COPY QDataStream Q DISABLE COPY是QT的一个宏 顾名思义 意思为禁用拷贝构造函数 如果要知道这个宏的实现 可以继续F2 所以第一个结论
  • Android 全局异常处理之UncaughtExceptionHandler

    在日常开发中可能有需要将机器奔溃日志保存本机 以便保存到本地 那么该如何做呢 实现UncaughtExceptionHandler接口 public class ApplicationCrashHandler implements Thre
  • upload-labs 环境搭建(docker)

    1 切换到root用户 2 在docker镜像仓库搜索upload labs镜像 3 下载镜像 4 查看本地镜像库 看是否下载成功 如下图就有了下载的镜像 5 运行镜像 生成镜像 docker run d p92 80 镜像id 92端口是
  • Linux学习笔记一:vmware安装Ubuntu虚拟机并进行联网设置

    目录 概述 新建虚拟机 安装Ubuntu 安装后重启失败 联网设置 修改分辨率 概述 主要参考讯为的教程 没有使用讯为提供的镜像 为了自己动手把相关工具安装一遍 采用了官方的Ubuntu18镜像 过程中与教程难免存在差异 遇到问题再针对解决
  • 总结:Git 撤销操作

    1 还未添加到暂存区 git checkout filename 执行命令后 会回退到未修改之前的状态 2 已经添加到暂存区 git reset HEAD filename 执行命令后 会回退到工作区之前的状态 3 已经 commit 但是
  • 以太坊Python智能合约开发指南

    在以太坊上获得一个基本的智能合约是一个很简单的事 只需google查询 ERC20代币教程 你会发现有关如何做到这一点的大量信息 以编程方式与合约交互完全是另一回事 如果你是一个Python程序员 那么教程就很少 所以写这个Python中的
  • Adaptive让 Spark SQL 更高效更智能

    本文转发自技术世界 原文链接 http www jasongj com spark adaptive execution 1 背景 前面 Spark SQL Catalyst 内部原理 与 RBO 与 Spark SQL 性能优化再进一步