简介:这份PPT课件是《大数据技术基础与实战》完整版电子讲义,面向初学大数据的读者及高校相关课程教师,适合作为教学课件、课前预习或复习资料。内容围绕“概念—流程—技术—实践”主线展开,先介绍大数据的4V特性以及工业、金融、医疗健康等典型应用场景;再详细拆解数据采集、导入与清洗、统计与分析、数据挖掘与应用四个处理步骤,并说明各环节面临的高并发、数据规模大、算法复杂等现实挑战;随后重点讲解Hadoop生态,涵盖HDFS分布式文件系统与MapReduce分布式计算框架,穿插VirtualBox实践环境准备,兼顾原理与动手基础。资源包共1个pptx文件,大小约9.97MB,采用章节化课件形式,便于按知识点定位浏览。目前已有167人浏览学习。读者可获得一份结构完整、知识点密集的讲义,既能快速建立大数据技术整体认知,也能理解Hadoop核心组件的工作机制,为后续开发实践打下坚实基础。
1. 拿到这套《大数据技术基础与实战》PPT课件,别急着翻到Hadoop那一章
第一次打开这套《大数据技术基础与实战》PPT课件的朋友,多半会被目录里Hadoop、HDFS、MapReduce、Spark这些名词吸引,直接跳到后面看技术组件。但我建议你先在前两章多停一会儿——大数据处理流程和4V特性这两个部分看起来像概念堆砌,实际上决定了你后面学Hadoop时是“看懂”还是“只会敲命令”。这套课件是面向信息技术人才培养的完整讲义,从概念到环境准备都有,适合刚入门大数据的学生,也适合想系统梳理知识体系的开发人员。如果你打算照着它搭一套自己的实验环境,或者准备大数据技术期末考试,这篇笔记能把课件里没展开的坑给你填上。
2. 从4V到数据形态:先给数据分类,再决定用HDFS还是HBase
2.1 4V不是四个形容词,是四组硬约束
课件里把大数据特性概括为规模性、多样性、高速性、价值性,也就是4V。很多初学者把这四个词背下来就过去了,但真正选型的时候,4V每一条都在逼你做决定。
规模性(Volume)直接决定你是用单机MySQL还是分布式存储。数据量从TB级往上走时,单机磁盘吞吐和索引维护都会成为瓶颈。多样性(Variety)决定你要不要引入NoSQL或者多模态存储,比如图片、音视频和结构化日志混在一起时,用一张关系表硬扛是不现实的。高速性(Velocity)决定你的链路是批处理还是流处理,像Flume采集日志到HDFS是准实时,而Spark Streaming就是微批。价值性(Value)最容易被忽略,它说的是数据密度低、单条价值不高,但整体挖掘价值高,这就意味着你不能只做简单的count、sum,得引入机器学习算法从低密度数据里找规律。
把这四个维度列成一张表,对照着看你的业务场景,比死记定义有用得多:
| 特性 | 核心问题 | 典型技术选择 | 常见误区 |
|---|---|---|---|
| 规模性 Volume | 数据多大?增长多快? | HDFS、HBase、对象存储 | 用MySQL分库分表硬撑 |
| 多样性 Variety | 数据有哪些形态? | Hive、HBase、Elasticsearch混搭 | 试图全部结构化后入关系库 |
| 高速性 Velocity | 数据多久需要被处理? | Flume + Kafka、Spark Streaming | 把实时需求全部批处理化 |
| 价值性 Value | 数据能挖出什么? | MLlib、Mahout、Spark | 只做报表统计,不做挖掘 |
2.2 结构化、半结构化、非结构化:如何用脚本快速识别数据形态
课件里把数据分成结构化、非结构化和半结构化三类,并指出结构化数据因果关系强,非结构化数据没有因果关系,半结构化数据因果关系弱。这个分类不是学术概念,它直接决定你后续用什么工具解析。
结构化数据通常指关系表,字段固定,行与行之间结构一致。半结构化数据有标签或键值对,比如JSON、XML、HTML邮件,虽然可以解析成树结构,但字段可能缺省,没有严格的模式。非结构化数据就是图片、语音、视频、纯文本,没有固定格式,无法直接套用表模型。
2.2.1 用Python做数据形态探查
拿到一批不确定格式的文件时,我一般先写个脚本做快速探查,而不是直接扔进Hadoop。下面这个脚本读几个文件样本,输出文件类型、行数、是否有分隔符、是否是JSON/XML:
import json import os import xml.etree.ElementTree as ET def probe_file(filepath, sample_lines=5): try: with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: head = [next(f) for _ in range(sample_lines)] except StopIteration: head = [] if not head: return f"{filepath}: 空文件" first = head[0].strip() # 常规分隔符判断 separators = [',', '\t', '|', ';'] sep_found = None for sep in separators: if first.count(sep) >= 2: sep_found = sep break # JSON 判断 try: json.loads(first) return f"{filepath}: 半结构化 (JSON), 分隔符: N/A" except Exception: pass # XML 判断 if first.startswith('<?xml') or first.startswith('<'): try: ET.fromstring('\n'.join(head)) return f"{filepath}: 半结构化 (XML), 分隔符: N/A" except Exception: pass if sep_found: lines = len(open(filepath, encoding='utf-8', errors='ignore').readlines()) return f"{filepath}: 结构化? 分隔符={sep_found!r}, 总行数约={lines}" else: return f"{filepath}: 非结构化/纯文本, 首行={first[:50]}"这段脚本的逻辑是先读文件前几行,然后依次判断:是否存在常见的列分隔符,能不能被解析成JSON,是不是XML。分隔符连续出现两次以上才认为是结构化的标志,否则很可能是普通文本里的逗号。判断出结构化后,再统计总行数,方便你估算数据规模。注意,errors='ignore'是处理非UTF-8编码时用的,实际生产环境里中文日志经常是GBK,这个参数能避免读到一半抛异常。
2.2.2 三种形态在存储与计算上的不同待遇
知道了形态,下一步就是选存储和计算框架:
- 结构化数据:如果量在千万级以内,关系库完全够用;量再大就上Hive,用HQL做离线分析。
- 半结构化数据:推荐存HBase,因为HBase本身就是稀疏映射表,支持行键、列族、时间戳,天然适应字段不固定的场景。也可以用Hive的JSON SerDe直接解析日志。
- 非结构化数据:一般把文件本身放HDFS,元数据放Hive或者Elasticsearch,这样既保留原始文件,又让上层能检索。
课件里提到的HDFS“一次写入、多次读取”机制,其实就暗示了它适合存放非结构化和半结构化的大文件,而HBase则适合需要随机读写的结构化或半结构化数据。把这些对应关系记牢,比只会背定义有用得多。
2.3 一个实际判断例子
假设你现在收到一批电商订单日志,每行是一个JSON,里面包含用户ID、商品ID、数量、价格、时间戳,但偶尔有字段缺失,比如有的行没有“优惠券”字段。按上面的规则,这是典型的半结构化数据。如果每天产生的日志有5亿条,单日约200GB,那么你就不应该用MySQL直接存。常见做法是:用Flume实时采集到HDFS落地,同时写一份到Kafka;离线条数统计用Hive;实时查询用户最近订单用HBase。这就是4V中的“多样性”和“高速性”共同作用下的结果。课件后面讲的Hadoop生态组件,本质上就是为这类场景拼装出来的工具箱。
3. 大数据处理流程四步:从采集到挖掘,每一步都有坑
课件把大数据处理流程拆成数据采集、数据导入与清洗处理、数据统计与数据分析、数据挖掘和应用。这四个步骤看起来跟普通数据处理差不多,但实际做起来,每一步都有大量细节。我带过的很多项目就是死在第一步和第二步的连接处——数据采上来了,但格式五花八门,清洗脚本没法复用。
3.1 数据采集:并发高不是靠加线程,是靠分流
课件提到数据采集的主要特点是并发数高。很多初学者以为并发高就上多线程、多线程不够就上线程池,但真实场景里,并发高只意味着接入层需要缓冲,以及日志源需要分流。
以Flume为例,Flume把一个采集任务抽象成Source、Channel、Sink三个部分。Source负责接收数据,Channel是中间缓冲,Sink把数据写到目标端。下面是一个采集nginx日志到HDFS的配置示例:
agent1.sources = tailSource agent1.channels = fileChannel agent1.sinks = hdfsSink agent1.sources.tailSource.type = spooldir agent1.sources.tailSource.spoolDir = /data/nginx/logs agent1.sources.tailSource.fileHeader = true agent1.sources.tailSource.batchSize = 100 agent1.channels.fileChannel.type = file agent1.channels.fileChannel.checkpointDir = /data/flume/checkpoint agent1.channels.fileChannel.dataDirs = /data/flume/data agent1.sinks.hdfsSink.type = hdfs agent1.sinks.hdfsSink.hdfs.path = hdfs://standalone:9000/flume/nginx/%Y%m%d agent1.sinks.hdfsSink.hdfs.filePrefix = nginx_log agent1.sinks.hdfsSink.hdfs.fileType = DataStream agent1.sinks.hdfsSink.hdfs.rollInterval = 600 agent1.sinks.hdfsSink.hdfs.rollSize = 134217728 agent1.sources.tailSource.channels = fileChannel agent1.sinks.hdfsSink.channel = fileChannel这段配置里,spooldir类型的Source会监控/data/nginx/logs目录,只要目录里有新文件就会被读走。这个机制很稳定,比直接tail文件更不容易丢数据。Channel选的是file类型,把数据先落盘到本地,避免Flume进程重启时数据丢失。Sink写到HDFS,rollInterval是每10分钟滚动一个文件,rollSize是128MB滚动一次,这跟你HDFS的块大小有关系,设得太小会产生大量小文件,设得太大则单文件读取效率低。我一般会同时设这两个参数,满足任何一个条件就切换文件。
3.2 数据导入与清洗:先做格式统一,再做去重
采集到的原始数据必然有重复、缺失、格式不统一的问题。课件里说导入集中分布式数据库前的清洗是最大挑战。实际上清洗工作应该分层做:第一层在数据采集时做格式校验,第二层在入仓时做去重和字段补全。
下面用Spark SQL演示一个通用的清洗作业,针对常见的JSON日志:
import org.apache.spark.sql.SparkSession import org.apache.spark.sql.functions._ val spark = SparkSession.builder() .appName("data_clean") .enableHiveSupport() .getOrCreate() val rawDF = spark.read.json("hdfs://standalone:9000/flume/nginx/2024/") val cleanedDF = rawDF .filter(col("user_id").isNotNull) .dropDuplicates("request_id") .withColumn("event_date", to_date(from_unixtime(col("timestamp") / 1000))) .withColumn("body_size", col("request_body_size").cast("long")) .na.fill(0, Seq("body_size")) cleanedDF.write.mode("overwrite").partitionBy("event_date") .saveAsTable("ods_nginx_log")这段代码做的事情很直接:先过滤掉user_id为空的记录,再按request_id去重,然后把毫秒时间戳转换成日期作为分区字段,最后把请求体大小字段转成long类型,空值填0。注意,去重必须基于业务主键,不能随便对所有字段去重,否则会把同一用户不同时间段的正常记录删掉。分区字段按照event_date建,后续查询按天过滤时能极大减少扫描量。
清洗完的数据建议落地到ODS层(操作数据存储),跟原始数据分开。原始数据永远保留一份,清洗逻辑改了还能重跑。这一点课件里没有细讲,但实际运维时非常重要。
3.3 数据统计与分析:目的清晰再写聚合,避免全表扫描
课件里说数据统计与分析的特点是目的清晰,按规则分类汇总。这听着简单,但很多刚接触大数据的人会犯同一个毛病:在Hive里写SELECT *,然后把所有数据拉到客户端再算。这是最忌讳的。
正确做法是把聚合下推到Hive或者Spark引擎里,只返回结果。比如要统计每一天每个商品的销量排行,写这个HQL:
SELECT event_date, product_id, SUM(quantity) AS total_qty FROM ods_nginx_log WHERE event_date >= '2024-01-01' GROUP BY event_date, product_id ORDER BY total_qty DESC LIMIT 100;这个查询看起来没什么特别,但它背后的执行逻辑是:先按分区过滤event_date,减少输入数据量;然后GROUP BY在MapReduce阶段完成局部聚合,Reduce阶段再做全局聚合;最后只取前100条。如果数据量特别大,ORDER BY会触发全局排序,非常耗时。更优的做法是先按total_qty降序输出到临时表,或者用SORT BY配合DISTRIBUTE BY做并行排序。这些都是课件里没有提到的优化细节。
另外,分析任务最好错峰执行,不要在实时业务高峰期占用YARN资源。课件里提到的YARN资源协调器,就是用来管理这类资源调度的。你可以给不同任务设置不同的队列,把离线分析和实时计算分开。
3.4 数据挖掘与应用:计算量大怎么拆?用历史数据训练,用新数据预测
最后一步数据挖掘,课件强调计算量大,这没错。但实际项目中,你不可能每天都跑一遍全量训练。常见做法是把训练和预测拆成两个流程:训练流程定期跑,比如每天凌晨用前30天的数据训练模型;预测流程则是实时的,用训练好的模型文件对新数据进行推理。
以MLlib里的逻辑回归为例,你只需要在Spark里这样调用:
import org.apache.spark.ml.classification.LogisticRegression val lr = new LogisticRegression() .setMaxIter(10) .setRegParam(0.01) val model = lr.fit(trainingDF) model.write.save("hdfs://standalone:9000/models/lr_model_20240101")这个训练过程中,Spark会把数据分到各个executor上做梯度计算,这跟MapReduce的并行思路类似。训练完成后把模型保存到HDFS,后续实时预测时再加载模型,对每条新数据进行预测。这里要注意,setMaxIter太大容易过拟合,太小则模型不收敛,一般从10开始调;setRegParam是正则化参数,用于防止过拟合,取值通常在0.001到0.1之间。这类参数需要在验证集上做网格搜索,不能凭感觉定。
4. Hadoop生态十一个组件,按这个顺序学才不会乱
课件里一口气列出了Hadoop Common、HDFS、YARN、MapReduce、HBase、Hive、Flume、Spark、Spark Streaming、MLlib、Tachyon等十几个组件。初学者看到这张列表很容易懵,以为每个都要精通。实际上它们分属不同层次,按层去理解,学习路径就清晰了。
4.1 先分清存储、计算、调度、查询四层
我一般把这堆组件分成四个层次:
| 层次 | 组件 | 职责 |
|---|---|---|
| 存储层 | HDFS、HBase、Tachyon | 文件存储、列式数据库、内存级分布式存储 |
| 计算层 | MapReduce、Spark、Spark Streaming | 批量计算、内存计算、流式微批计算 |
| 调度与资源层 | YARN | 集群资源管理与任务调度 |
| 查询与分析层 | Hive、Pig、Mahout、MLlib | SQL查询、数据挖掘、机器学习算法 |
Flume和Sqoop属于采集层,可以单独记。Tachyon现在更多叫Alluxio,是以内存为中心的存储系统,它不替代HDFS,而是给Spark和MapReduce提供内存级文件共享服务。课件里说它的吞吐量比HDFS高,实际场景中主要用于跨作业的数据共享,避免重复从磁盘读。
4.2 HDFS读写原理与常用命令
HDFS的核心是NameNode和DataNode。NameNode管元数据,DataNode管数据块。课件说HDFS适合“一次写入、多次读取”,这是它的设计约束。你在HDFS上改一个文件,实际上是重写整个文件,不支持随机修改。所以它不适合做在线事务处理。
实际工作中最常用的HDFS操作命令就这么几个:
# 创建目录 hdfs dfs -mkdir -p /data/ods # 上传本地文件 hdfs dfs -put ./nginx.log /data/ods/ # 查看块大小和副本 hdfs fsck /data/ods/nginx.log -files -blocks -locations # 设置副本数 hdfs dfs -setrep -w 3 /data/ods/nginx.log # 列出目录下文件大小,按G显示 hdfs dfs -du -h /data/odshdfs fsck这个命令很多人不知道,但它排错非常有用,可以看到文件被切成几块,块分布在哪几个DataNode上。如果你发现某个文件的块副本数低于配置值,可以用-setrep -w 3强制补副本,-w表示等待所有副本写入完成再返回。
HDFS默认块大小是128MB,副本数是3。副本数不是越大越好,3副本在200个节点以下够用;超过这个规模,机架感知配置不到位的话,副本数反而增加网络压力。课件里说HDFS能运行在低成本硬件上,前提是你接受硬件故障常态化的设计。所以不要把所有数据只设1副本,除非你能容忍丢数据。
4.3 MapReduce的Map和Reduce到底做了什么:用WordCount拆开看
MapReduce的抽象只有两个阶段:Map和Reduce。Map处理输入数据,输出键值对;Reduce把相同键的值汇总。很多教材都用WordCount做例子,但光看代码不理解执行流程,还是纸上谈兵。
下面用Python模拟整个过程的伪代码,更贴近计算逻辑:
# mapper.py import sys for line in sys.stdin: words = line.strip().split() for word in words: print(f"{word}\t1") # reducer.py import sys current_word = None current_count = 0 for line in sys.stdin: word, count = line.strip().split('\t', 1) try: count = int(count) except ValueError: continue if current_word == word: current_count += count else: if current_word: print(f"{current_word}\t{current_count}") current_word = word current_count = count if current_word: print(f"{current_word}\t{current_count}")这段代码里,mapper从标准输入读一行,按空格切词,每个词输出词\t1。reducer读取mapper的输出,按词累加计数。关键在于,Hadoop在Map和Reduce之间会做一个shuffle操作,把相同key的所有value分发给同一个reducer。也就是说,reducer看到的同一词的数据一定是连续的。如果你的reducer逻辑依赖key的顺序,就需要在shuffle阶段设置分区函数和排序。这是MapReduce性能和正确性的核心。
实际用Hadoop运行这段Python,需要Streaming API指定mapper和reducer路径。不推荐新手直接手写Java的MapReduce,代码冗长且调试成本高。用Hive或者Spark SQL做数据分析省时得多,理解MapReduce的价值在于看懂框架的容错和并行机制,而不是让你什么都用它写。
4.4 Hive把SQL变成MapReduce,离线分析为什么离不开它
Hive的杀手锏就是让熟悉SQL的人能操作Hadoop。课件里说Hive本质上是基于HDFS的应用,数据存在HDFS上,HQL会被翻译成MapReduce任务。这就带来一个特性:Hive查询延迟高,跑一个count(*)可能都要几十秒,因为它启动任务有固定开销。所以Hive只适合离线分析,不适合在线查询。
使用Hive时,一个重要的设计是分区和分桶。分区按业务日期或地区划分,可以减少查询扫描的数据量。分桶则是对分区内的数据再做哈希散列,用于抽样和join优化。建表语句通常长这样:
CREATE EXTERNAL TABLE ods_nginx_log ( request_id STRING, user_id STRING, request_path STRING, status INT, body_size BIGINT ) PARTITIONED BY (event_date STRING) ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.JsonSerDe' STORED AS TEXTFILE LOCATION '/data/ods/nginx';注意,EXTERNAL关键字表示数据文件不归Hive管理,删表不会删HDFS文件。这在做ODS层时非常安全,即使误删表,数据还在。JsonSerDe让Hive直接解析JSON格式的日志文件,不需要提前转成文本表。PARTITIONED BY中的分区字段不能和表内字段重复,分区目录在HDFS上表现为/data/ods/nginx/event_date=2024-01-01。
4.5 Spark、Spark Streaming、MLlib、Tachyon:什么时候用它们
Spark跟MapReduce的最大区别是中间结果缓存在内存里,减少磁盘I/O。课件里说Spark比Hadoop快100倍,那是理想情况。实际上,如果你的数据不能全部放进内存,或者集群内存配置不合理,Spark会退化成频繁的磁盘shuffle,性能提升幅度会大打折扣。
选型建议按这个逻辑来:
- 离线复杂ETL、多表关联、机器学习迭代计算:用Spark,比MapReduce写起来简单,运行快。
- 需要秒级或分钟级延迟的实时计算:用Spark Streaming,它把流数据切成微批处理,适合对延迟不那么极端的场景。如果要求毫秒级,考虑Flink,这是后话。
- 想在Spark里做分类、聚类、协同过滤:直接用MLlib,它提供了现成的算法封装。
- 多个Spark作业共享同一份热数据:考虑Tachyon(Alluxio)做内存缓存,避免每个作业都从HDFS重新读一遍。
组件不是越多越好。小集群宁可少上组件,先把HDFS、YARN、Hive、Spark这四件套跑稳,再根据需求加HBase和Flume。课件里列了11个组件,但生产环境里很多都只是备用选项。
5. 实践环境准备:VirtualBox搭伪分布式集群,这些参数别照抄
课件最后一章讲实践环境准备,提到VirtualBox的安装与配置。很多人在这一步卡住,不是因为不会装VirtualBox,而是不会规划网络和资源。如果你是照着课件里的图一步步点,大概率会遇到虚拟机起不来、节点互通失败、HDFS能启动但DataNode掉线这些问题。
5.1 VirtualBox网络模式与内存分配
搭建Hadoop集群至少需要三台虚拟机(一个主节点,两个从节点)。VirtualBox网络模式选“仅主机网络(Host-Only)”或“桥接网卡”。我建议用NAT + Host-Only双网卡,NAT用于虚拟机访问外网下载软件包,Host-Only用于集群节点间通信。如果你直接在NAT模式下搭建集群,三台机器默认在同一子网,但宿主机和虚拟机之间通信不稳定,HDFS的DataNode上报经常超时。
内存分配方面,Hadoop的NameNode、DataNode、ResourceManager、NodeManager都是Java进程,每台机器至少给2GB内存。主机如果是16GB内存,三台虚拟机各2GB,剩余留给宿主机和IDE。如果你的内存只有8GB,就别硬开三台,用伪分布式单机模式更实际——所有角色跑在一个JVM里,也能完整走通MapReduce流程。
5.2 克隆虚拟机后的三个必须改的配置
很多人为了省事,先装一台虚拟机,配置好Hadoop后再克隆两台。克隆出来的机器如果不改配置,三台机器的主机名和IP完全一样,整个集群直接瘫痪。克隆后必须改三个地方:
# 1. 修改主机名 sudo hostnamectl set-hostname hadoop01 # 2. 修改静态IP(以Ubuntu 20.04为例) sudo vi /etc/netplan/01-netcfg.yaml # 修改 addresses: [192.168.56.101/24] 为各节点不同的IP # 3. 清空Hadoop临时目录(关键!否则DataNode启动失败) rm -rf /usr/local/hadoop/tmp/dfs/name/current前两步好理解,第三步是很多人踩坑的地方。克隆的虚拟机里已经包含原来机器上NameNode生成的元数据,如果直接启动,新节点的NameNode会认为自己已经有集群信息,但DataNode的clusterID不匹配,导致DataNode反复启动失败。清空临时目录后,重新执行hdfs namenode -format格式化,再启动就正常了。注意,格式化之前先把原来Hadoop进程全部停掉。
5.3 用脚本验证集群是否就绪
启动完集群后,不要只看jps里有没有五个进程,还要检查数据节点是否被NameNode接纳。写一个简单的验证脚本:
#!/bin/bash echo "=== Java 进程检查 ===" jps | grep -E 'NameNode|DataNode|ResourceManager|NodeManager|SecondaryNameNode' echo "=== HDFS 状态 ===" hdfs dfsadmin -report | grep -E 'Live datanodes|Name:|Hostname:' echo "=== YARN 节点检查 ===" yarn node -list 2>/dev/null | grep RUNNING echo "=== 上传测试文件 ===" echo "test data" | hdfs dfs -put - /tmp/test.txt hdfs dfs -cat /tmp/test.txt脚本依次检查Java进程、HDFS存活DataNode数量、YARN节点状态,最后上传并读取一个测试文件。如果Live datanodes只有1个,说明另外两台节点的DataNode没注册成功,去对应节点的日志目录看logs/hadoop-hadoop-datanode-*.log,最常见的就是clusterID不一致。如果YARN节点状态为空,检查yarn-site.xml里的yarn.resourcemanager.hostname是否指向主节点。
这套环境跑通之后,回去看课件里的HDFS、MapReduce、Hive原理,你会突然发现它们不再是抽象概念。接下来要做的,就是拿课件里的例子一个个实验,比如自己写个WordCount跑一遍,用Hive建一张外部表查日志。只有环境在自己手里真正跑起来,才算把大数据技术基础这本书读进去了。
本文还有配套的精品资源,点击获取