目录
3、A 文件有 50 亿条 URL,B 文件也有 50 亿条 URL,每条 URL 大小为 64B,在一台只有 4G 内存的机器上,怎么找出 A、B 中相同的 URL?
基础题
1、介绍一下拉链表的原理,以及适用于哪些场景?
拉链表是一种数据模型,主要是针对数据仓库设计中表存储数据的方式而定义的;顾名思义,所谓拉链表,就是记录历史,记录一个事务从开始一直到当前状态的所有变化的信息。
拉链表可以避免按每一天存储所有记录造成的海量存储问题,同时也是处理缓慢变化数据(SCD2)的一种常见方式。
原理:说白了就是在原有表基础上增加两个字段,一个start_time,一个end_time
数据如果不变就不动,如果有新数据进来,就将原数据的end_time天数-1(改成前天),start_time不变,新数据的start_time写成今天,end_time设置成9999-12-31 这其中的操作都在新建的两张临时表(update表和tmp表)中进行,它适合最大程度节省存储空间,又能满足数据历史状态的场景
思考题
2、如果使用spark遇到了 OOM ,你会怎么处理?
Driver OOM
- driver端生成大对象
- 将大对象转换成Executor端加载,比如调用sc.textfile
- 评估大对象占用的内存,增加dirver-memory的值
collect数据收集导致
- 本身不建议将大的数据从executor端,collect回来。建议将driver端对collect回来的数据所作的操作,转换成executor端rdd操作,若无法避免,估算collect需要的内存,相应增加driver-memory的值。
Executor OOM
- java.lang.OutOfMemoryError: Java heap space
- 原因:1、数据量太大,申请的Executor资源不足以支撑。2.单分区的数据量过大,和分区数过多导致执行task和job存储的信息过多导致Driver OutOfMemoryError
- 解决方法:1、尽量不要使用collect操作。2、查看数据是否有倾斜,增加shuffle的并行度,加大Executor内存
- shuffle 报 org.apache.spark.shuffle.FetchFailedException: Direct buffer memory
- 原因:堆外内存不够导致,直接内存
- 解决方法:增大JVM 参数-XX:MaxDirectMemorySize(如:spark.executor.extraJavaOptions = -XX:MaxDirectMemorySize=xxxm)
- java.lang.OutOfMemoryError:GC overhead limit exceeded
- 当 Java 进程花费 98% 以上的时间执行 GC,但只恢复了不到 2% 的内存,且该动作连续重复了 5 次,就会抛出 这个报错。此类问题的原因与解决方案跟
Javaheap space
非常类似,参考上面的。
Permanent Generation OOM
永久代存储对象主要包括以下几类:
- 加载/缓存到内存中的 class 定义,包括类的名称,字段,方法和字节码;
- 常量池
- 对象数组、类型数组所关联的 class
- 解决办法
- 修改
-XX:MaxPermSize
启动参数,调大永久代空间。
- 如果上述无法解决,可以用 jmap 命令 dump 内存快照,然后用 Eclipse MAT 功能分析开销最大的 classloader 和重复的 class。
- Permanent Generation OOM
- 该错误表示 Metaspace 已被用满,通常是因为加载的 class 数目太多或体积太大。此类问题的原因与解决方法跟
Permgenspace
非常类似,可以参考上文。需要特别注意的是调整 Metaspace 空间大小的启动参数为-XX:MaxMetaspaceSize
- Spark on Yarn
- Driver 经常被 container kill(container的物理和虚拟内存不够)
- Container [pid=1151,containerID=container_1578970174552_5615_01_000001] is running beyond physical memory limits. Current usage: 4.3 GB of 4 GB physical memory used; 7.8 GB of 8.4 GB virtual memory used. Killing container.增大spark.yarn.driver.memoryoverhead 值,默认此参数是 1GB。
- container_1578970174552_5615_01_000001: 4.3 GB of 4 GB physical memory used; 7.8 GB of 8.4 GB virtual memory used. 增加虚拟内存的比例,虚拟内存上限 = 物理内存上限 x yarn.nodemanager.vmem-pmem-ratio(Apache版本默认是2.1)
Executor 经常被 container kill(container的物理和虚拟内存不够)
- Container [pid=1151,containerID=container_1578970174552_5615_01_000004] is running beyond physical memory limits. Current usage: 4.3 GB of 4 GB physical memory used; 7.8 GB of 8.4 GB virtual memory used. Killing container.增大spark.yarn.executor.memoryoverhead 值,默认此参数是 1GB。
- container_1578970174552_5615_01_000005: 4.3 GB of 4 GB physical memory used; 7.8 GB of 8.4 GB virtual memory used. 增加虚拟内存的比例,虚拟内存上限 = 物理内存上限 x yarn.nodemanager.vmem-pmem-ratio(Apache版本默认是2.1)
当然还有一种办法,不过不推荐使用,把检查物理内存和虚拟的内存的参数都关闭
- 注意 :container_xx_000001 是 driver 所在的 container
- Executor 自动 dump命令
–conf spark.executor.extraJavaOptions=“-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/srv/Bigdata/spark.bin”
Driver 自动 dump 命令
–conf spark.driver.extraJavaOptions=“-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/srv/Bigdata/spark.bin”
- 如果增加了内存,或者调整了heap ,老年代,新生代,永久代这些比例后,还是经常出现 OOM,建议在 Spark 提交脚本里面增加上述的命令,方便复现 OOM,然后用 Eclipse MAT 分析,或者用 Parfma 社区提供的工具分析,也当然可以用阿里开源的 Arthas 工具分析。
总结:
先调整参数值,调整的过程是逐渐调整,不要一下参数值变化很多(一般变化2倍就行),如果调整过1,2次还是出现 OOM,则需要 heap dump内存快照,然后用自己喜欢的工具对应分析,看是代码啥地方的问题。
智力题
3、A 文件有 50 亿条 URL,B 文件也有 50 亿条 URL,每条 URL 大小为 64B,在一台只有 4G 内存的机器上,怎么找出 A、B 中相同的 URL?
本题来源:https://mp.weixin.qq.com/s/u5LoPxhXpKbx9CUR5qqQqg 大数据肌肉猿
针对这种大数据量的问题,通常要想到「分而治之」。为了方便讲解,我这里就先计算一下。
50 亿条 URL 文件的大小:50 * 10^8 * 64 Byte ≈ 32 * 10^10 Byte ≈ 320G
用流程图表示:
借助 Hash 函数,依次扫描 A、B 两个文件,将 URL 分别存储到 1000 个小文件中,那么每个文件大约 300M,满足内存的需求,文件以 0-999 的数字结尾作为编号,下面说下具体过程。
首先遍历 A 文件,对每个 URL 取 hash(url)%1000 的值,该值就是 URL 要存储到小文件的编号,最终所有 URL 分别存储在 1000 个小文件中,文件名记成以下形式: a0、a1、…、a999。
再遍历 B 文件,用同样的方法将 B 文件的 URL 分别存储在 b0、b1、…、b999 这 1000 个小文件中。
我们知道 Hash 的一个特点:相同的 key,hash 之后的 value 一定是相同的。所以,对于 A、B 文件中相同的 URL,Hash 之后,一定会存储到相同下标的文件中。
如果 Hash 函数设计合理,将数据均匀分散,每个文件大致 300M。
我们再读取相同下标的小文件到内存中,判断是否存在相同的 URL 即可