1. HDFS 小文件过多会导致什么问题,怎么处理这个问
  2. 你是怎么考虑你的数据分层的
  3. spark 的懒加载机制
  4. HDFS 的主要组件是哪些
  5. union 和 union all 的区别是什么
  6. mysql的 binlog 日志
  7. 数据压缩机
  8. 项目里遇到的难点

答案如下:

1. HDFS 小文件过多会导致什么问题,怎么处理这个问题

考察知识点

  • HDFS架构特性(元数据存储机制)
  • 小文件对集群性能的影响
  • 小文件治理的常用方案

参考回答

问题

HDFS设计用于存储大文件(默认块大小128MB/256MB),小文件(远小于块大小)过多会引发两个核心问题:

  1. NameNode内存压力激增:NameNode将文件元数据(路径、块信息等)存储在内存中,每个文件约占150字节。若有1亿个小文件,元数据需占用约15GB内存,可能导致NameNode内存溢出,影响集群稳定性。
  2. 读写效率下降:小文件的寻址时间(定位块存储位置)远大于实际读写时间,且MapReduce/Spark处理时会生成大量小Task(每个小文件对应一个Task),导致Task调度开销远超计算开销,集群资源利用率降低。

处理方案

  1. 离线合并
    • Hadoop Archive(HAR):将多个小文件归档为一个HAR文件(元数据集中存储),减少NameNode内存占用(1万个小文件归档后元数据仅占约1KB),但不改变文件内容,适合冷数据归档。
    • 批量合并为大文件:通过MapReduce/Spark任务,将同目录下的小文件合并为大文件(如按日期合并日志文件),写入HDFS时设置合理块大小(如128MB),适合热数据处理。
  2. 实时写入优化
    • SequenceFile/ORC/Parquet:将小文件按Key-Value结构写入SequenceFile,或用列存格式ORC/Parquet(支持块级压缩和合并),减少文件数量。例如,实时日志采集时,用Flink将10分钟内的小日志合并为一个ORC文件写入HDFS。
  3. 存储层适配
    • 小文件量极大时(如数十亿个),改用HBase存储:HBase将小文件按RowKey聚合存储在HFile中,元数据由HMaster和RegionServer管理,减轻NameNode压力,适合随机读写的小文件场景(如用户头像、小尺寸日志)。
  4. 源头控制
    • 数据采集端限制小文件生成:如Flume设置batchSize(批量写入,积累到一定大小再提交),Kafka设置log.segment.bytes(控制日志段大小,避免频繁滚动生成小文件)。

注意要点

  • 合并策略需区分“热数据”和“冷数据”:热数据(频繁查询)适合合并为大文件(提升读写效率),冷数据(归档)适合HAR(节省内存)。
  • 避免过度合并:单个大文件不宜超过10GB(否则Map Task处理时拆分过多块,反而降低效率)。

2. 你是怎么考虑你的数据分层的

考察知识点

  • 数据仓库分层逻辑(ODS/DWD/DWS/ADS)
  • 分层设计的核心目的(复用、维护、性能)
  • 分层与业务的结合

参考回答

数据分层的核心思路是“按数据加工粒度和用途拆分,实现数据复用、降低维护成本、提升查询效率”,结合实习项目,我采用经典的4层架构:

  1. ODS层(操作数据存储层)
    • 定位:存储原始数据,完全保留数据源格式(如日志、业务库表),不做清洗,仅做格式转换(如JSON→Parquet)。
    • 作用:作为数据入口,支持数据回溯(如原始日志异常时,可重新从ODS层加工)。
    • 实例:用户行为日志(raw_log_${dt})、MySQL订单表同步数据(ods_order_${dt},通过Sqoop/CDC同步)。
  2. DWD层(数据明细层)
    • 定位:对ODS层数据清洗、转换、脱敏,生成细粒度明细数据(一条记录对应一个具体行为/业务事件)。
    • 核心操作:① 清洗(过滤空值、异常值,如user_id=null的日志);② 脱敏(手机号、身份证号加密);③ 关联(补充维度信息,如用user_id关联用户表,补充用户等级)。
    • 作用:为上层提供干净、一致的明细数据,避免重复清洗。
    • 实例:dwd_user_click_detail(用户点击明细,含清洗后的商品id、点击时间、用户等级)。
  3. DWS层(数据服务层/汇总层)
    • 定位:按业务主题(如用户、商品、订单)聚合明细数据,生成中粒度汇总数据(如用户日活、商品周销量)。
    • 聚合维度:时间(天/周/月)、业务实体(用户/商品/渠道)。
    • 作用:减少上层查询的重复计算(如运营查“用户日活”可直接读DWS层,无需扫全量DWD明细)。
    • 实例:dws_user_active_day(用户日活表,按user_id和dt聚合,标记是否活跃)。
  4. ADS层(应用数据层)
    • 定位:面向具体业务需求(报表、dashboard、API),生成最终可直接使用的数据。
    • 特点:数据粒度粗(如全平台月GMV)、格式适配应用(如JSON/CSV,供Superset/BI工具直接读取)。
    • 实例:ads_gmv_month(月GMV报表,含各品类GMV占比)。

分层考虑因素

  • 业务需求:高频查询的指标(如实时GMV)在DWS层预聚合,低频复杂分析(如用户行为路径)直接基于DWD层。
  • 性能:DWD/DWS层用ORC/Parquet压缩,按时间分区,提升查询效率;ODS层保留原始格式,便于回溯。
  • 维护成本:每层职责明确,修改某层数据不影响其他层(如DWD清洗逻辑变更,仅需重新生成DWD及上层数据)。

注意要点

  • 避免过度分层:中小规模业务可简化为ODS→DWD→ADS,避免层级冗余增加维护成本。
  • 分层需“向上兼容”:上层数据必须完全由下层数据生成,确保数据血缘可追溯。

3. Spark 的懒加载机制

考察知识点

  • Spark SQL中“转换操作”与“行动操作”的区分
  • 懒加载的核心原理(逻辑计划构建与延迟执行)
  • 懒加载在SQL场景中的优化逻辑(如执行计划优化、减少无效计算)
  • 实际工作中对懒加载机制的验证与应用

参考回答

Spark的懒加载机制(Lazy Evaluation)是指在Spark SQL中,所有对数据的“转换操作”仅会记录逻辑处理步骤,不会立即执行计算;只有当遇到“行动操作”时,才会触发之前所有转换操作的实际执行。这一机制是Spark优化计算效率的核心特性,在SQL场景中表现如下:

(1)核心原理

  • Spark SQL将操作分为两类:
    • 转换操作(Transformation):对数据进行处理但不生成最终结果的操作(如SELECTWHEREJOINGROUP BY等)。这类操作仅会被Spark解析为“逻辑计划”(记录“要做什么”),不实际读取数据或执行计算。
    • 行动操作(Action):触发计算并生成结果的操作(如SHOWCOUNTINSERT INTOCREATE TABLE ... AS SELECT等)。这类操作会触发Spark对之前所有转换操作的逻辑计划进行优化(如合并步骤、谓词下推),并生成物理计划(确定“如何执行”),最终提交任务到集群执行。

(2)SQL场景示例

假设我们有一张用户行为表user_behavior(含user_idageaction字段),需求是“筛选30岁以上用户的行为记录,并统计其数量”。

-- 步骤1:定义转换操作(仅记录逻辑计划,不执行)
-- 转换1:筛选30岁以上用户
CREATE OR REPLACE TEMPORARY VIEW filtered_users AS
SELECT user_id, action
FROM user_behavior
WHERE age > 30;  -- WHERE属于转换操作

-- 转换2:按用户ID分组统计行为次数
CREATE OR REPLACE TEMPORARY VIEW user_action_cnt AS
SELECT user_id, COUNT(action) AS action_count
FROM filtered_users
GROUP BY user_id;  -- GROUP BY属于转换操作

此时,执行上述SQL后,Spark仅会解析语法并生成逻辑计划(可通过EXPLAIN user_action_cnt;查看),但不会读取user_behavior表的数据,也不会执行筛选或聚合计算——这就是“懒加载”的体现。

This post is for subscribers on the 网站会员 and 成为小万的高级会员 tiers only

Subscribe Now

Already have an account?