浅谈大数据处理工作中数据倾斜问题的解决方案

本文探讨了大数据处理中常见的数据倾斜问题,分析了其产生的原因,并提出了多种实用的解决方案,包括过滤异常数据、提前聚合、调整并行度、打散倾斜key等方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一  概述
 本文整理了笔者再从事大数据处理工作中对于数据倾斜问题的各类解决方案
 
二  现象
 在hadoop,spark等分布式计算框架中运行某个作业时,发现某个算子(可能是map,也可能是reduce)执行特别慢
 在hadoop中还不算特别致命,就是慢点,最终往往还是能算出结果,但是在spark等基于内存的计算框架中则很可能是致命的
 往往会导致内存溢出或频繁的jvm full gc
 
三 发生点
 一般发生在shuffle阶段,尤其是有join的场合,但是有些情况下在map端也会发生数据倾斜
 
四 产生原因
 A 数据key值分布不均匀,少数key下包含的数据占比过大
  例如医疗就诊数据中,往往是少数几个三甲医院产生了大部分的门急诊量,而大量的小医院就诊量确很少
    股市中少数几支热门股占据了大部分交易量
    两张表join时某些关联key,所关联的数据,占比过大
    
 B 数据在计算节点间分布不均匀
  类似hadoop,spark等框架都遵循一个原则,“移动计算,而不移动数据”,也就是作业调度算法会尽可能的
  在实际存储数据的节点上调度执行计算任务,这样的好处是避免了传输大数据所带来的磁盘io和网络开销,
  但正因为如此,如果某个节点数据非常多,那么在这个节点就会执行大量任务,这也是map端发生数据倾斜的原因
  一般现在大数据存储都是在hdfs上,可执行hadoop 的balancer命令,使得数据均匀分布
  
五 解决方案
   笔者从实施角度,按先易后难的顺序罗列一下自己所掌握的解决方案,一个有趣的现象是,往往容易的方案是更有效的方案
  
1 过滤掉导致倾斜的数据
 这是最简单的方法,分析业务,当发现导致倾斜的数据是不需要的,直接抛弃这部分数据
 最经典的例子是null值,源数据有大量key值是null的数据,这些null值在进行shuffle时会分配给同一个reduce任务处理
 那么当业务允许的情况下,直接删掉这些数据
 
2 在数据源头尽量进行聚合
 例如某个医院A有以下10条门急诊数据:
 A    数据1
 A    数据2
 A    数据3
 A    数据4
 A    数据5
 A    数据6
 A    数据7
 A    数据8
 A    数据9
 A    数据10
 
 在正式进行统计分析任务前,进行数据预处理任务,使用聚合操作,把以上数据聚合成如下形式
 A    数据1,数据2,数据3,数据4,数据5,数据6,数据7,数据8,数据9,数据10
 
3 提高并行度,也就是增加reduce任务数量,摊薄reduce任务的压力
 这种方案,只能缓解数据倾斜,不是根本解决,效果要看具体场景,之所以放在第3条,是因为实在是很简单
 
4 打散倾斜key,进行多次聚合
 如果在数据源没有进行聚合,或者无法聚合,或者聚合后还是有倾斜key存在,则可以使用此方案
 还是以上述A医院的数据为例,我们使用一个随机数,将A随机变换成A-1,....A-N形式,假设随机数取值为1至3
 则以上数据会变成如下形式
 A-1    数据1
 A-2    数据2
 A-3    数据3
 A-1    数据4
 A-2    数据5
 A-3    数据6
 A-1    数据7
 A-2    数据8
 A-3    数据9
 A-1    数据10
 针对这种形式的数据,我们进行两次聚合,第一次聚合结果如下
 A-1    数据1,数据4,数据7,数据10
 A-2    数据2,数据5,数据8
 A-3    数据3,数据6,数据9
 第二次聚合,去掉随机数再聚合,结果如下
 A    数据1,数据2,数据3,数据4,数据5,数据6,数据7,数据8,数据9,数据10
 
 本方案的局限性在于,不适用于join产生的数据倾斜
 
5 对于join产生的数据倾斜,优先考虑将reduce端的join,转换为map端的join
 因为map端是一条条数据去join的,不存在归并的过程,也就自然没有了数据倾斜
 首先讨论一下,为什么join操作,常规是用reduce算子来做
 原因很简单,map reduce思想是分而治之的思想,map负责分,reduce负责合
 同一套数据在map过程中会分给Nmap任务,最终按关联关系,将相同的key所对应的数据输出给同一个reduce任务
 要做join则必须拿到join两端的所有数据,这只有在reduce的过程中才能拿到
 
 从上述分析可见,map端做不了join是由于无法获得join两端的所有必须数据,那么如果我们提供一种方法
 让map端能获得join两端的所有必须数据,则map端就能进行join了。好在框架已经为我们提供了这种方法。
 
 在hadoop中可以用DistributedCache.addCacheFile
 在spark中可以用broadcast广播变量
 在hive中可以用/*+ MAPJOIN() */
 
 以上代码的作用都是将join两端中的某一端(一般是数据量小的一端),广播出来,分发到所有运行map任务的节点
 这样map端就可以执行join了
 
 本方案的局限性在于,需要将join的一端,完全载入map任务节点的内存中,因此只适用于join的一端是小表的情况,
 不适用于join两端都是大表的情况,不过对于大表join大表的场景,笔者曾经尝试在hadoop mapreduce程序中将大表预先
 加载到redis等高并发缓存中,也取得不错的效果(这种方式其实是用增大网络流量的方式来换取节约内存空间,对网络传输速度有较高要求)
 
 
6 抽取分割倾斜数据,分别进行join后再归并
 对于无法用map join方案的可尝试此方案
 
 原理
  预先分析源数据,将会发生数据倾斜的数据,单独拉出来;
  用这个会倾斜的数据单独去join一下,这个时候,key对应的数据,可能就会分散到多个任务中去进行join操作。
 
 例
 数据表 A 包含倾斜key,内容为
 key    value
 1       x1
 1       x2
 1       x3
 1       x4
 1       x5
 1       x6
 2       x7
 3       x8
 
 数据表 B 为要join的表,内容为
 key    value
 1       y1
 2       y2
 3       y3
 
  首先,分析数据表 A的倾斜key,拆分 A 为  A1(只含倾斜key) A2(不含倾斜key)
  A1 内容为
  key    value
 1       x1
 1       x2
 1       x3
 1       x4
 1       x5
 1       x6
 
 A2 内容为
  key    value
 2       x7
 3       x8
 
 
  然后,对数据表 B也按照倾斜key 拆分出  B1(只含倾斜key)
  B1 内容为
  key    value
 1       y1
 
  对A1,对key打上随机数前缀 得到 AP,这里的随机数取值范围为(1,2,3)
  AP 内容为
  key    value
 1-1       x1
 2-1       x2
 3-1       x3
 1-1       x4
 2-1       x5
 3-1       x6
 
  对B1,对key打上有序唯一数前缀 得到BP,这里有序唯一数取值范围必须覆盖上面的随机数范围(1,2,3)
  BP 内容为
  key    value
 1-1      y1
 2-1      y1
 3-1      y1
 
 
  AP join BP 得到 ABP 这里可以结合提升reduce操作并行度获得更好的效果
  ABP 内容为
  key    value
 1-1    x1,y1
 1-1    x4,y1
 2-1    x2,y1
 2-1    x5,y1
 3-1    x3,y1
 3-1    x6,y1
 
  对ABP 去掉随机数前缀 得到 AB1
  AB1 内容为
  key    value
  1    x1,y1
  1    x4,y1
  1    x2,y1
  1    x5,y1
  1    x3,y1
  1    x6,y1
 
  用A2 join B 得到 AB2
  AB2 内容为
  key    value
 2      x7,y2
 3      x8,y3
 
  最终合并AB1 和AB2
  key    value
  1    x1,y1
  1    x4,y1
  1    x2,y1
  1    x5,y1
  1    x3,y1
  1    x6,y1
  2    x7,y2
  3    x8,y3
 
 本方案适用于源数据中倾斜key只有少数几个的场景
 
7 随机扩容
 对于join数据中有很多倾斜key,不能用方案6解决的,可以尝试本方案
 
 选择一个join表,进行扩容,将每条数据,用有序唯一数作为前缀打散,映射为多条数据,通常选择10以内的有序唯一数,即最多扩容10倍。
  将另外一个表,做普通的map映射操作,每条数据,都打上一个10以内的随机数前缀。
  最后,将两个处理后的表,进行join操作
 
 本方案只是对数据倾斜的缓解,而不是根本解决,可以看出本方案的本质是通过放大数据量来谋求数据的均衡,代价还是比较明显的,
 因此只有前述方案都无法适用时,才应考虑使用本方案
 
 
 
 
 
 
 
 
 
<think>好的,我现在需要解决用户在加载预训练模型时遇到的SafetensorError,具体是'MetadataIncompleteBuffer'错误。这个问题出现在使用Hugging Face的Transformers库的from_pretrained方法时。用户可能对Safetensors和相关的错误不太熟悉,所以我得先理解这个错误的原因,然后给出解决方案。 首先,我应该回忆一下Safetensors的相关知识。Safetensors是Hugging Face开发的一种安全且高效的文件格式,用于替代传统的PyTorch bin文件。它能够加快加载速度,并且避免反序列化时的安全风险。而MetadataIncompleteBuffer错误通常与文件头部的元数据不完整或损坏有关。可能的原因包括文件下载不完整、文件损坏,或者版本不兼容。 接下来,我需要考虑用户的具体情况。用户可能在下载模型时网络中断,导致文件不完整。或者他们使用的库版本过旧,无法正确解析Safetensors文件。还有可能模型文件本身存在问题,比如上传时损坏,或者使用了不兼容的Safetensors版本生成的文件。 针对这些可能的原因,我应该分步骤给出解决方案。首先建议用户检查文件完整性,重新下载模型文件。然后,确保所有相关库(如Transformers、Safetensors)更新到最新版本,以解决兼容性问题。如果问题依旧,可以尝试禁用Safetensors,强制使用PyTorch格式,这样虽然牺牲一些性能,但可能绕过当前的问题。此外,用户可能还需要清除缓存文件,因为旧的缓存可能导致问题。 另外,我需要考虑用户可能不知道如何执行这些步骤,比如如何检查文件哈希,或者如何更新库。因此,在回答中需要给出具体的命令行指令,例如使用`wget`重新下载,或者使用`pip install --upgrade`命令更新库。同时,如果用户禁用Safetensors,需要指导他们在from_pretrained方法中添加参数`use_safetensors=False`。 最后,应该提醒用户,如果所有方法都失败,可以联系模型维护者确认文件是否有问题,或者到社区寻求帮助。例如,Hugging Face的论坛或GitHub仓库都是寻求支持的好地方。 现在,我需要确保回答结构清晰,步骤明确,并且涵盖所有可能的原因和解决方法。同时,按照用户的要求,生成相关问题,帮助用户进一步理解Safetensors和相关错误。</think>### 解决 `SafetensorError: MetadataIncompleteBuffer` 错误 #### 问题原因分析 此错误通常发生在使用 `transformers` 库的 `from_pretrained` 方法加载 Safetensors 格式的模型时,可能由以下原因导致: 1. **模型文件损坏**:文件下载不完整或传输过程中数据丢失 2. **版本不兼容**:使用的 `safetensors` 或 `transformers` 库版本过低 3. **元数据解析失败**:Safetensors 文件头部的元数据结构不符合预期格式[^1] #### 逐步解决方案 1. **验证文件完整性** - 重新下载模型文件(建议使用断点续传工具) ```bash wget --continue https://huggingface.co/[模型路径]/resolve/main/model.safetensors ``` - 检查文件哈希值是否与模型仓库中声明的匹配 2. **升级依赖库** ```bash pip install --upgrade transformers safetensors ``` 3. **清除缓存** ```python from transformers import AutoModel model = AutoModel.from_pretrained("模型名称", force_download=True) # 强制重新下载 ``` 4. **禁用 Safetensors(临时方案)** ```python model = AutoModel.from_pretrained("模型名称", use_safetensors=False) ``` 5. **检查文件编码(开发者场景)** 若需手动检查 Safetensors 文件: ```python from safetensors import safe_open with safe_open("model.safetensors", framework="pt") as f: print(f.keys()) # 验证元数据是否可读 ``` #### 技术原理说明 Safetensors 文件结构包含: $$ \text{Header} + \text{Tensor Data} $$ 其中头部使用 JSON 格式存储张量元数据。当反序列化过程中检测到 JSON 解析失败或长度不匹配时,会触发 `MetadataIncompleteBuffer` 错误[^1]。 相关问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值