本文详细介绍了Hadoop启动后的操作流程,包括HDFS基本操作、MapReduce示例运行、Flume日志采集配置以及ZooKeeper的核心概念。
主要内容包括:
- Hadoop环境验证和HDFS操作
- 通过jps命令验证Hadoop进程
- 创建用户目录和上传测试文件到HDFS
- 运行MapReduce示例程序
- Flume日志采集配置
- 配置netcat到控制台的简单示例
- 设置文件到HDFS的采集流程
- 模拟网站日志采集的完整方案
- ZooKeeper核心概念
- 解释ZooKeeper在分布式系统中的作用
- 对比Kafka和HBase中ZooKeeper的不同应用
- 提供实际操作命令和练习
- 数据处理流程
- 从日志生成到Flume采集
- HDFS存储到Hive分析的全流程
- 包含完整的SQL查询示例
文章通过清晰的步骤说明和实际操作命令,帮助读者掌握大数据生态系统中关键组件的使用方法和相互关系。
梳理补充优化老师的课堂笔记,现在看笔记,我完全不会操作了。Hadoop已经启动了,接下来是怎么做的?
这里按回车太快,忘记贴笔记原文了,AI竟然也能回答的有模有样,真是智能!
不会操作,一是老师讲太快,没有完全记住。二是今天的笔记有缺失,没有之前的详细。最重要的是,教室的电脑死机了重启耗费太多时间,等我想跟着老师做的时候,完全不知道从哪下手了。还好AI足够给力,把我缺的操作补起来了。
看起来你的笔记可能跳过了关键的操作步骤。我先帮你把Hadoop启动后的标准操作流程梳理出来,并补充常见的"卡住"点和检查方法。
第一步:确认Hadoop是否真的启动了
在继续之前,先快速确认一下:
bash
jps
你应该能看到以下至少4个进程(如果是单机伪分布式):
text
NameNode
DataNode
SecondaryNameNode
ResourceManager
NodeManager
如果缺少
NameNode或ResourceManager,说明没启动成功,需要先解决。
第二步:HDFS的基本操作(必须先做的事)
Hadoop启动后,HDFS是空的,你需要:
1️⃣ 创建用户目录
bash
hdfs dfs -mkdir -p /user/你的用户名
2️⃣ 上传数据到HDFS
bash
# 本地创建一个测试文件
echo "hello hadoop" > test.txt
# 上传到HDFS
hdfs dfs -put test.txt /user/你的用户名/
3️⃣ 验证文件是否成功
bash
hdfs dfs -ls /user/你的用户名/
hdfs dfs -cat /user/你的用户名/test.txt
第三步:运行一个MapReduce示例(验证Hadoop能用)
Hadoop自带示例jar包,用来测试:
bash
# 找到示例jar的位置(通常在Hadoop安装目录下)
find /home -name "hadoop-mapreduce-examples-*.jar" 2>/dev/null
# 或者
ls $HADOOP_HOME/share/hadoop/mapreduce/
# 运行wordcount示例
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount \
/user/你的用户名/test.txt \
/user/你的用户名/output
查看结果:
bash
hdfs dfs -cat /user/你的用户名/output/part-r-00000
第四步:接下来你真正想做什么?(选择一条路)
| 你的目标 | 下一步操作 |
|---|---|
| 学习MapReduce编程 | 写一个WordCount Java程序 → 打包成jar → 用hadoop jar提交 |
| 学习Hive | 启动Hive元数据服务和Hive CLI |
| 学习HBase | 启动HBase(start-hbase.sh),创建表,插入数据 |
| 学习Spark | 提交Spark任务(需要Scala/Python代码) |
| 我只是想用Hadoop存文件 | 用hdfs dfs -put/get 就够了 |
❗常见问题排查(针对"不会操作了")
问题1:jps看不到NameNode
bash
# 重新格式化并启动
hdfs namenode -format
start-dfs.sh
问题2:上传文件报错"No such file or directory"
→ 目录不存在,先mkdir -p创建父目录
问题3:没有$HADOOP_HOME环境变量
bash
export HADOOP_HOME=/你的hadoop安装路径
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
问题4:Web界面打不开
-
NameNode管理界面:
http://你的虚拟机IP:9870 -
检查防火墙:
systemctl stop firewalld
建议你立刻做的事
-
先执行
jps,把输出发给我 -
告诉我你是学习用途 还是做项目 ?笔记里接下来提到的是MapReduce / Hive / HBase / Spark中的哪一个?
我会根据你的实际进度,帮你把缺失的操作步骤完整补回笔记。
这里发了笔记原文
Flume : 是一个日志采集,传输的系统。基于流式架构。
并且高可用,高可靠,分布式。
......
太好了!你的Flume笔记内容很全,但缺少启动Hadoop后的具体操作顺序 ,而且笔记里写"默认启动zookeeper"容易让人困惑。我帮你重新梳理+补充缺失步骤 ,让你知道现在到底该做什么。
📌 你的现状(Hadoop已启动) → 接下来操作顺序
✅ 第一步:确认环境(5分钟)
bash
# 1. 确认Hadoop正常
jps # 应该看到NameNode, DataNode, ResourceManager, NodeManager
# 2. 确认HDFS可用(Flume要写数据到HDFS)
hdfs dfs -ls / # 能正常列出目录即可
# 3. 创建Flume在HDFS上的根目录(重要!)
hdfs dfs -mkdir -p /flume
⚠️ 你的笔记里写的
node100:9000,需要改成你的实际Hadoop地址:bash
# 检查你的core-site.xml配置 cat $HADOOP_HOME/etc/hadoop/core-site.xml | grep fs.defaultFS # 假设输出是 hdfs://localhost:9000 或 hdfs://你的IP:9000
📝 第二步:先跑通最简单的示例(netcat → console)
这是验证Flume本身是否能工作的必做测试:
1️⃣ 创建配置文件
bash
mkdir -p /opt/module/flume/job
vim /opt/module/flume/job/flume-netcat-logger.conf
把你的笔记中的配置完整粘贴进去(你的笔记这段是正确的)
2️⃣ 启动Flume Agent
bash
cd /opt/module/flume
bin/flume-ng agent \
-c conf/ \
-n a1 \
-f job/flume-netcat-logger.conf \
-Dflume.root.logger=INFO,console
3️⃣ 发送测试数据(新开一个终端窗口)
bash
nc localhost 8888
# 然后输入 hello flume 回车
# 再输入 test message 回车
4️⃣ 观察效果
Flume启动的窗口应该会打印出:
text
Event: { headers:{} body: 68 65 6c 6c 6f 20 66 6c 75 6d 65 hello flume }
✅ 成功标准:能看到Event输出 → Flume正常
📁 第三步:跑通"文件 → HDFS"示例(你笔记里的第二个)
1️⃣ 准备测试文件
bash
mkdir -p /opt/module/flume/test
touch /opt/module/flume/test/tail.txt
2️⃣ 修改配置文件中的HDFS路径
你的配置里写的是hdfs://node100:9000,需要改成你的实际地址:
bash
vim /opt/module/flume/job/flume-file-hdfs.conf
把这一行:
text
a2.sinks.k2.hdfs.path = hdfs://node100:9000/flume/%Y%m%d/%H
改成(查看你的Hadoop地址):
bash
# 先查看你的HDFS地址
hdfs getconf -confKey fs.defaultFS
# 假设输出是 hdfs://localhost:9000,就改成:
a2.sinks.k2.hdfs.path = hdfs://localhost:9000/flume/%Y%m%d/%H
3️⃣ 启动Flume(新终端窗口1)
bash
cd /opt/module/flume
bin/flume-ng agent -c conf/ -n a2 -f job/flume-file-hdfs.conf -Dflume.root.logger=INFO,console
4️⃣ 模拟产生日志(新终端窗口2)
bash
# 往监控文件里追加数据
echo "2025-01-01 10:13:34 INFO User login success" >> /opt/module/flume/test/tail.txt
echo "2025-01-01 10:15:22 WARN User logout" >> /opt/module/flume/test/tail.txt
echo "2025-01-01 10:20:45 ERROR Database timeout" >> /opt/module/flume/test/tail.txt
5️⃣ 检查HDFS结果
bash
# 查看HDFS上的文件(注意日期目录会自动生成)
hdfs dfs -ls /flume/
hdfs dfs -ls /flume/$(date +%Y%m%d)/$(date +%H)/
hdfs dfs -cat /flume/$(date +%Y%m%d)/$(date +%H)/logs-*
✅ 成功标准:能看到你刚echo的内容出现在HDFS文件中
🎯 第四步:你的实际需求(网站日志采集)
你笔记最后提到的网站日志场景,完整流程应该是:
完整采集链路
bash
# 1. 创建Flume配置文件(使用taildir source,比exec更可靠)
# 2. 启动Flume采集
# 3. 网站产生日志 → Flume实时采集 → 写入HDFS
# 4. 在Hive中建表查询
我可以帮你写一个生产级别的配置,解决你笔记里的埋点采集需求,需要吗?
⚠️ 你笔记中需要修正的地方
| 笔记原话 | 问题 | 正确做法 |
|---|---|---|
| "默认启动zookeeper" | Flume不需要ZK | Flume独立运行,只有HBase/Kafka需要ZK |
hdfs://node100:9000 |
硬编码主机名 | 改成你的实际HDFS地址 |
使用exec source |
容易丢数据 | 生产环境用taildir source |
🚀 你现在立刻做的事
选择一条路,告诉我:
-
"我想先跑通netcat示例" → 按第二步操作,把报错发我
-
"我想直接跑通文件到HDFS" → 按第三步操作,告诉我
hdfs getconf的输出 -
"我要做网站日志采集到Hive分析" → 我直接给你生产级配置+完整SQL
把jps的输出和hdfs getconf -confKey fs.defaultFS的结果发我,我帮你把命令里的地址全部替换正确。
用的教室环境,统一安装的虚拟机,环境应该和老师的一样。
bash
[hadoop@node100 hadoop-3.3.0]$ jps
2275 DataNode
3139 Jps
2084 NameNode
2732 ResourceManager
3004 NodeManager
2447 SecondaryNameNode
[hadoop@node100 hadoop-3.3.0]$ hdfs getconf -confKey fs.defaultFS
hdfs://node100:9000
[hadoop@node100 hadoop-3.3.0]$
完美!你的环境配置正确,node100:9000就是老师配置的HDFS地址。
现在直接按照下面的步骤操作即可。
🎯 你现在立刻按顺序执行(从0开始)
第一步:确认Flume安装位置
bash
# 找到Flume安装目录
ls /opt/module/ | grep flume
# 或者
find /home -name "flume" -type d 2>/dev/null
如果没有Flume,需要先安装。如果有,记录下路径(假设是/opt/module/flume)
第二步:创建Flume作业目录和测试文件
bash
# 创建job目录
mkdir -p /opt/module/flume/job
# 创建测试文件目录(用于第二个示例)
mkdir -p /opt/module/flume/test
# 创建测试文件
touch /opt/module/flume/test/tail.txt
第三步:跑通第一个示例(netcat → 控制台)
3.1 创建配置文件
bash
vim /opt/module/flume/job/flume-netcat-logger.conf
按 i 进入编辑模式,完整粘贴以下内容:
properties
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 8888
# Describe the sink
a1.sinks.k1.type = logger
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
按 ESC,输入 :wq 保存退出。
3.2 启动Flume(在当前终端)
bash
cd /opt/module/flume
bin/flume-ng agent -c conf/ -n a1 -f job/flume-netcat-logger.conf -Dflume.root.logger=INFO,console
你会看到Flume启动日志,最后停在那里不动(等待数据)。
3.3 发送测试数据(新开一个终端窗口)
bash
# SSH连接到node100(如果已经在新终端就跳过)
ssh hadoop@node100
# 发送数据
nc localhost 8888
然后输入:
text
hello flume
按回车
再输入:
text
test message
按回车
3.4 观察效果
回到第一个终端窗口,你应该看到类似这样的输出:
text
Event: { headers:{} body: 68 65 6c 6c 6f 20 66 6c 75 6d 65 hello flume }
Event: { headers:{} body: 74 65 73 74 20 6d 65 73 73 61 67 65 test message }
✅ 成功! 按 Ctrl+C 停止这个Flume任务,继续下一步。
第四步:跑通第二个示例(文件 → HDFS)
4.1 创建配置文件
bash
vim /opt/module/flume/job/flume-file-hdfs.conf
粘贴以下内容(已经改好node100:9000):
properties
# Name the components on this agent
a2.sources = r2
a2.sinks = k2
a2.channels = c2
# Describe/configure the source
a2.sources.r2.type = exec
a2.sources.r2.command = tail -F /opt/module/flume/test/tail.txt
# Describe the sink
a2.sinks.k2.type = hdfs
a2.sinks.k2.hdfs.path = hdfs://node100:9000/flume/%Y%m%d/%H
#上传文件的前缀
a2.sinks.k2.hdfs.filePrefix = logs-
#是否按照时间滚动文件夹
a2.sinks.k2.hdfs.round = true
#多少时间单位创建一个新的文件夹
a2.sinks.k2.hdfs.roundValue = 1
#重新定义时间单位
a2.sinks.k2.hdfs.roundUnit = hour
#是否使用本地时间戳
a2.sinks.k2.hdfs.useLocalTimeStamp = true
#积攒多少个Event才flush到HDFS一次
a2.sinks.k2.hdfs.batchSize = 100
#设置文件类型,可支持压缩
a2.sinks.k2.hdfs.fileType = DataStream
#多久生成一个新的文件
a2.sinks.k2.hdfs.rollInterval = 60
#设置每个文件的滚动大小
a2.sinks.k2.hdfs.rollSize = 134217700
#文件的滚动与Event数量无关
a2.sinks.k2.hdfs.rollCount = 0
# Use a channel which buffers events in memory
a2.channels.c2.type = memory
a2.channels.c2.capacity = 1000
a2.channels.c2.transactionCapacity = 100
# Bind the source and sink to the channel
a2.sources.r2.channels = c2
a2.sinks.k2.channel = c2
4.2 先在HDFS创建目录(重要!)
bash
hdfs dfs -mkdir -p /flume
4.3 启动Flume(当前终端)
bash
cd /opt/module/flume
bin/flume-ng agent -c conf/ -n a2 -f job/flume-file-hdfs.conf -Dflume.root.logger=INFO,console
4.4 生成测试数据(新开终端)
bash
# 模拟网站日志
echo "2025-05-28 10:13:34 INFO User login success" >> /opt/module/flume/test/tail.txt
echo "2025-05-28 10:15:22 WARN User logout" >> /opt/module/flume/test/tail.txt
echo "2025-05-28 10:20:45 ERROR Database timeout" >> /opt/module/flume/test/tail.txt
4.5 查看HDFS结果(新终端)
bash
# 等10-20秒让Flume处理
hdfs dfs -ls /flume/
# 查看具体文件(日期目录会自动生成)
hdfs dfs -ls /flume/20250528/10/
# 查看文件内容
hdfs dfs -cat /flume/20250528/10/logs-*
你应该能看到刚写入的三条日志。
✅ 成功! Flume已经将文件数据实时采集到HDFS了。
🎯 现在你要做的网站日志采集(实战场景)
既然环境已经验证通过,现在可以对接你的网站日志了。
创建生产级配置文件(用taildir,比exec更好)
bash
vim /opt/module/flume/job/flume-weblog-hdfs.conf
properties
# 生产环境推荐配置
a3.sources = r3
a3.sinks = k3
a3.channels = c3
# 使用taildir source(支持断点续传)
a3.sources.r3.type = taildir
a3.sources.r3.positionFile = /opt/module/flume/taildir_position.json
a3.sources.r3.filegroups = f1
a3.sources.r3.filegroups.f1 = /var/log/your-app/pinduoduo_server.log
a3.sources.r3.filegroups.f1.header.logtype = web
# 写入HDFS
a3.sinks.k3.type = hdfs
a3.sinks.k3.hdfs.path = hdfs://node100:9000/user/hive/warehouse/weblog_database.db/user_behavior_log/dt=%Y%m%d/
a3.sinks.k3.hdfs.filePrefix = log-
a3.sinks.k3.hdfs.round = true
a3.sinks.k3.hdfs.roundValue = 1
a3.sinks.k3.hdfs.roundUnit = hour
a3.sinks.k3.hdfs.useLocalTimeStamp = true
a3.sinks.k3.hdfs.batchSize = 100
a3.sinks.k3.hdfs.fileType = DataStream
a3.sinks.k3.hdfs.rollInterval = 3600
a3.sinks.k3.hdfs.rollSize = 134217728
a3.sinks.k3.hdfs.rollCount = 0
a3.channels.c3.type = memory
a3.channels.c3.capacity = 10000
a3.channels.c3.transactionCapacity = 1000
a3.sources.r3.channels = c3
a3.sinks.k3.channel = c3
然后在Hive中建表分析
sql
-- 创建外部表
CREATE EXTERNAL TABLE user_behavior_log (
log_time STRING,
log_level STRING,
user_ip STRING,
message STRING
)
PARTITIONED BY (dt STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ' '
LOCATION '/user/hive/warehouse/weblog_database.db/user_behavior_log';
-- 修复分区(自动加载HDFS上的数据)
MSCK REPAIR TABLE user_behavior_log;
-- 查询分析
SELECT
dt AS 日期,
COUNT(1) AS 用户行为数,
COUNT(DISTINCT user_ip) AS 独立IP数
FROM user_behavior_log
WHERE log_level = 'INFO'
GROUP BY dt;
📌 你现在告诉我
-
第一个示例跑通了吗?(看到Event输出)
-
第二个示例跑通了吗?(HDFS上有文件)
-
你的网站日志文件实际路径是什么?(我帮你改配置中的路径)
-
需要我帮你写完整的Hive SQL分析语句吗?
把执行结果或报错直接贴过来,我帮你解决。
第一个示例、第二个示例都跑通了。网站日志采集(实战场景)没看懂,网站日志文件实际路径没有,现在是教学环境,没有自己的网站。
太好了!你已经跑通了两个示例,说明Flume环境完全正常。既然现在是教学环境 ,没有真实网站日志,那我们就模拟网站日志来学习整个流程。
🎯 教学环境下的完整实战(模拟网站日志采集)
你将学会:模拟产生日志 → Flume采集 → 存入HDFS → Hive分析
第一步:模拟网站日志产生(写个脚本)
1.1 创建模拟日志目录
bash
# 创建目录存放模拟的网站日志
mkdir -p /opt/module/flume/weblog
# 创建模拟日志文件
touch /opt/module/flume/weblog/pinduoduo_server.log
1.2 编写日志生成脚本
bash
vim /opt/module/flume/weblog/generate_log.sh
粘贴以下内容:
bash
#!/bin/bash
# 模拟用户IP池
IPS=("10.46.78.122" "192.168.1.100" "172.16.5.88" "10.0.0.55" "192.168.10.200")
# 模拟行为
ACTIONS=("login" "search" "click_product" "add_cart" "order" "logout")
# 无限循环,每5秒生成一条日志
while true; do
# 当前时间
TIME=$(date "+%Y-%m-%d %H:%M:%S")
# 随机IP
IP=${IPS[$RANDOM % ${#IPS[@]}]}
# 随机行为
ACTION=${ACTIONS[$RANDOM % ${#ACTIONS[@]}]}
# 随机用户ID (1-1000)
USER_ID=$((RANDOM % 1000 + 1))
# 生成日志格式:时间 日志级别 IP 行为 用户ID
echo "$TIME INFO $IP org.apache.xxx: user $USER_ID $ACTION"
# 每5秒生成一条
sleep 5
done
1.3 给脚本执行权限并运行
bash
# 添加执行权限
chmod +x /opt/module/flume/weblog/generate_log.sh
# 后台运行脚本(持续产生日志)
cd /opt/module/flume/weblog
./generate_log.sh >> pinduoduo_server.log 2>&1 &
第二步:创建Flume采集配置(taildir版本)
2.1 创建Flume配置文件
bash
vim /opt/module/flume/job/flume-weblog-hdfs.conf
粘贴以下内容:
properties
# 模拟网站日志采集配置
a3.sources = r3
a3.sinks = k3
a3.channels = c3
# 使用taildir source(断点续传,不会丢数据)
a3.sources.r3.type = taildir
a3.sources.r3.positionFile = /opt/module/flume/taildir_position.json
a3.sources.r3.filegroups = f1
a3.sources.r3.filegroups.f1 = /opt/module/flume/weblog/pinduoduo_server.log
a3.sources.r3.batchSize = 100
# 输出到HDFS(按日期分区存储)
a3.sinks.k3.type = hdfs
a3.sinks.k3.hdfs.path = hdfs://node100:9000/user/hive/warehouse/weblog_db/user_behavior_log/dt=%Y%m%d/
a3.sinks.k3.hdfs.filePrefix = weblog-
a3.sinks.k3.hdfs.round = true
a3.sinks.k3.hdfs.roundValue = 1
a3.sinks.k3.hdfs.roundUnit = hour
a3.sinks.k3.hdfs.useLocalTimeStamp = true
a3.sinks.k3.hdfs.batchSize = 100
a3.sinks.k3.hdfs.fileType = DataStream
a3.sinks.k3.hdfs.rollInterval = 60
a3.sinks.k3.hdfs.rollSize = 134217728
a3.sinks.k3.hdfs.rollCount = 0
# 内存Channel
a3.channels.c3.type = memory
a3.channels.c3.capacity = 10000
a3.channels.c3.transactionCapacity = 1000
# 绑定关系
a3.sources.r3.channels = c3
a3.sinks.k3.channel = c3
2.2 启动Flume采集
bash
cd /opt/module/flume
bin/flume-ng agent -c conf/ -n a3 -f job/flume-weblog-hdfs.conf -Dflume.root.logger=INFO,console
保持这个终端运行,你会看到Flume在等待数据。
第三步:验证数据已经写入HDFS
3.1 等待1-2分钟让数据积累
bash
# 新开一个终端,查看HDFS上的文件
hdfs dfs -ls /user/hive/warehouse/weblog_db/
hdfs dfs -ls /user/hive/warehouse/weblog_db/user_behavior_log/
hdfs dfs -ls /user/hive/warehouse/weblog_db/user_behavior_log/dt=$(date +%Y%m%d)/
# 查看具体内容
hdfs dfs -cat /user/hive/warehouse/weblog_db/user_behavior_log/dt=$(date +%Y%m%d)/weblog-* | head -20
你应该能看到类似这样的数据:
text
2025-05-28 15:30:01 INFO 10.46.78.122 org.apache.xxx: user 345 login
2025-05-28 15:30:06 INFO 192.168.1.100 org.apache.xxx: user 789 search
第四步:Hive分析(完整SQL流程)
4.1 启动Hive
bash
# 进入Hive安装目录
cd /opt/module/hive
# 启动Hive CLI
bin/hive
4.2 创建外部表(关联HDFS数据)
sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS weblog_db;
USE weblog_db;
-- 创建外部表(分区表)
CREATE EXTERNAL TABLE user_behavior_log (
log_time STRING COMMENT '日志时间',
log_level STRING COMMENT '日志级别',
user_ip STRING COMMENT '用户IP',
message STRING COMMENT '日志消息'
)
PARTITIONED BY (dt STRING COMMENT '日期分区')
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}) (\\S+) (\\S+) (.*)"
)
STORED AS TEXTFILE
LOCATION '/user/hive/warehouse/weblog_db/user_behavior_log';
4.3 加载分区数据
sql
-- 方法1:手动添加分区
ALTER TABLE user_behavior_log ADD PARTITION (dt='20250528') LOCATION '/user/hive/warehouse/weblog_db/user_behavior_log/dt=20250528/';
-- 方法2:自动修复分区(推荐)
MSCK REPAIR TABLE user_behavior_log;
4.4 执行分析查询
sql
-- 1. 查看数据总量
SELECT COUNT(*) FROM user_behavior_log;
-- 2. 按日期统计访问量(你笔记里要的效果)
SELECT
dt AS 日期,
COUNT(1) AS 用户行为总数
FROM user_behavior_log
GROUP BY dt;
-- 3. 按行为类型统计
SELECT
REGEXP_EXTRACT(message, 'user (\\d+) (\\w+)', 2) AS 行为类型,
COUNT(1) AS 次数
FROM user_behavior_log
GROUP BY REGEXP_EXTRACT(message, 'user (\\d+) (\\w+)', 2);
-- 4. Top10活跃用户
SELECT
REGEXP_EXTRACT(message, 'user (\\d+)', 1) AS 用户ID,
COUNT(1) AS 活跃次数
FROM user_behavior_log
GROUP BY REGEXP_EXTRACT(message, 'user (\\d+)', 1)
ORDER BY 活跃次数 DESC
LIMIT 10;
-- 5. 按小时统计访问趋势
SELECT
HOUR(log_time) AS 小时,
COUNT(1) AS 访问量
FROM user_behavior_log
WHERE dt = '20250528'
GROUP BY HOUR(log_time)
ORDER BY 小时;
第五步:完整的数据处理流程(你笔记最后的内容)
你笔记里写的这段:
bash
hadoop fs -get hdfs日志文件 linux本地
awk -F " " '{print $1,$3,$7}' >> data.txt
load data local inpath data.txt into table 用户行为表;
对应的标准做法应该是:
5.1 直接从HDFS导出到本地
bash
# 下载HDFS数据到本地
hdfs dfs -get /user/hive/warehouse/weblog_db/user_behavior_log/dt=20250528/* /tmp/weblog_data.txt
# 用awk提取需要的字段(时间、IP、行为)
awk '{print $1, $3, $7}' /tmp/weblog_data.txt > /tmp/analysis.txt
5.2 或者直接用Hive导出查询结果
sql
-- Hive中直接导出查询结果到本地
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/hive_export'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
SELECT
log_time,
user_ip,
REGEXP_EXTRACT(message, 'user \\d+ (\\w+)', 1) AS action
FROM user_behavior_log
WHERE dt = '20250528';
🎯 你现在需要做什么
按顺序执行:
-
✅ 第一步:运行日志生成脚本(产生模拟数据)
-
✅ 第二步:启动Flume采集(看到数据在传输)
-
✅ 第三步:检查HDFS上是否有数据
-
✅ 第四步:进入Hive执行SQL查询
把每一步的执行结果截图或复制给我,我帮你确认是否正确。
如果有报错,直接把错误信息发给我,我帮你解决。
📝 补充:你笔记中的疑问解答
"Flume特性是流式处理"
→ 是的,Flume是实时流式处理,数据一产生就被采集,不需要等到第二天。
"离线vs实时"
→ 离线:处理昨天的历史数据(如Hive凌晨跑批)
→ 实时:数据产生后几秒内就能处理(如Flume→Kafka→Spark Streaming)
"启动Hadoop -- 默认启动zookeeper"
→ 这句不完全准确。Hadoop不需要ZK,但如果你要用HBase或Kafka才需要ZK。教学环境一般Hadoop单独运行即可。
zookeeper是什么?Kafka刚学完,后面马上要学习HBase
太好了!刚学完Kafka,马上学HBase,这时候理解ZooKeeper非常关键。
我用你刚学的Kafka作为桥梁,帮你理清ZooKeeper是什么。
🎯 ZooKeeper 一句话定义
ZooKeeper = 分布式系统的"管家" + "通知中心"
负责:协调管理 、配置维护 、命名服务 、集群管理
一、用Kafka理解ZooKeeper(你已经学过的)
Kafka中ZooKeeper的作用(你肯定见过)
bash
# 启动Kafka时,必须指定ZooKeeper地址
bin/kafka-server-start.sh config/server.properties
# server.properties里写着:zookeeper.connect=localhost:2181
ZooKeeper为Kafka做了什么?
| Kafka组件 | ZooKeeper管理的内容 |
|---|---|
| Broker | 记录哪些Broker活着、挂了、是新加入的 |
| Topic | 记录Topic的元数据(分区数、副本数) |
| Partition Leader | 选哪个Broker作为分区的Leader |
| Consumer Group | 记录消费者组消费到哪个offset(旧版本) |
| Controller | 从Broker中选出一个作为"总管" |
通俗理解:
-
ZooKeeper = 班级花名册(记录每个同学在不在、座位在哪)
-
Kafka = 全班同学
-
没有花名册 → 老师找不到学生,学生找不到自己的座位
二、ZooKeeper核心概念(最简单的理解)
2.1 数据结构:就像文件系统
text
/ (根目录)
├── /kafka
│ ├── /brokers
│ │ ├── /ids/0 (Broker 0的信息)
│ │ ├── /ids/1 (Broker 1的信息)
│ │ └── /topics
│ │ ├── /user-log/partitions/0/state
│ │ └── /order-info/partitions/1/state
├── /hbase
│ ├── /master
│ ├── /region-server
│ └── /table
└── /myapp
└── /config
每个节点叫Znode,可以存数据(如"10.0.0.1:9092"),也可以有子节点。
2.2 两大特性(面试必问)
| 特性 | 解释 | 例子(Kafka中) |
|---|---|---|
| 临时节点 | 客户端断开连接,节点自动删除 | Broker挂了 → 临时节点消失 → 其他Broker知道它下线了 |
| Watch机制 | 节点变化时通知客户端 | Broker 1挂了 → ZooKeeper通知所有订阅者 → Controller重新选Leader |
三、ZooKeeper在Kafka vs HBase中的角色对比
你刚学完Kafka,马上学HBase,对比着看:
| 功能 | Kafka中的ZK | HBase中的ZK |
|---|---|---|
| 选主 | 选举Controller Broker | 选举HMaster(主节点) |
| 服务发现 | 记录所有Broker地址 | 记录所有RegionServer地址 |
| 元数据存储 | Topic/分区元数据 | 表元数据、Region位置 |
| 状态监控 | Broker健康状态 | RegionServer健康状态 |
| 分布式锁 | 保证同组内只有一个Consumer消费 | 保证同一时刻只有一个Master写入 |
关键区别:
-
Kafka 2.8+ 可以不用ZK(用了Raft协议自带的元数据管理)
-
HBase 必须依赖ZK(核心依赖,无法脱离)
四、实际操作:你现在应该做什么
4.1 检查ZooKeeper是否运行(教室环境)
bash
# 查看ZK进程
jps | grep QuorumPeerMain
# 或者
ps aux | grep zookeeper
# 连接ZK看看
zkCli.sh -server node100:2181
4.2 ZK基础命令(帮你熟悉)
bash
# 连接后执行
ls / # 查看根目录
ls /kafka # 查看Kafka保存的信息(如果装了Kafka)
get /kafka/brokers/ids/0 # 查看Broker 0的信息
stat / # 查看节点状态
quit # 退出
4.3 创建自己的节点(练习)
bash
create /myapp "hello"
get /myapp
set /myapp "world"
delete /myapp
五、HBase中ZK的作用(预习)
你马上要学的HBase,ZK负责:
text
1. 保证只有一个HMaster运行(避免两个Master打架)
2. 监控RegionServer生死(谁挂了立刻通知Master)
3. 存储HBase系统元数据(-ROOT-表的位置)
4. 提供Master选举(主备切换)
启动顺序:
bash
# 1. 先启动ZooKeeper(必须)
zkServer.sh start
# 2. 再启动HBase
start-hbase.sh
# 3. HMaster和RegionServer会自动向ZK注册
六、常见问题解答
Q1:为什么Kafka可以脱离ZK,HBase不行?
A: Kafka 2.8+实现了自己的Raft协议管理元数据。HBase的设计深度绑定ZK,替换成本太高。
Q2:教室环境需要单独启动ZK吗?
A: 看你们的配置:
bash
# 检查是否开机自启
chkconfig --list | grep zookeeper
# 如果没有启动,手动启动
zkServer.sh start
# 或者有些环境用
systemctl start zookeeper
Q3:ZK挂了会怎样?
A:
-
Kafka: 生产消费不受影响(但无法做Broker上下线、分区重平衡)
-
HBase: 集群不可用(因为无法知道RegionServer状态)
Q4:生产环境ZK怎么部署?
A: 奇数台服务器(3/5/7台),因为选举需要过半同意:
-
3台:允许1台挂
-
5台:允许2台挂
-
7台:允许3台挂
七、你现在可以做的练习
练习1:启动ZK并观察Kafka注册
bash
# 1. 启动ZooKeeper
zkServer.sh start
# 2. 启动Kafka
bin/kafka-server-start.sh config/server.properties
# 3. 在另一个终端查看ZK中的数据
zkCli.sh
ls /kafka/brokers/ids # 应该能看到你启动的Broker ID
练习2:模拟Broker下线
bash
# 1. 在ZK中watch /kafka/brokers/ids
zkCli.sh
get /kafka/brokers/ids/0 watch
# 2. 停掉Kafka Broker
bin/kafka-server-stop.sh
# 3. 观察ZK终端的变化(临时节点消失)
📌 总结(一句话记忆)
ZooKeeper = 分布式系统的"通讯录"+"监控摄像头"
-
通讯录:记录谁在哪、谁活着
-
监控摄像头:谁变化了立刻通知所有人
对于你接下来的学习:
-
Kafka:知道ZK管理Broker/Topic元数据即可
-
HBase:必须掌握ZK的选举和监控机制(核心依赖)
-
面试重点:CAP理论中的CP(一致性+分区容错)
🎯 你现在告诉我
-
需要我帮你检查教室环境的ZK是否启动吗? (贴出
jps或zkCli.sh连接结果) -
需要我用HBase的例子再详细解释ZK的选举机制吗?(结合你马上要学的内容)
-
Flume的练习继续往下做吗?(之前模拟日志→HDFS→Hive已经跑通了吗?)
把当前进度和疑问发我,我接着帮你梳理!
因为是实操课,AI帮助我完成了实操,但我突然想起来,他遗漏了笔记中关于Flume的理论介绍部分,让我虽然实操通过了,但是完全不明白干了什么。于是有了下面的追问。
Flume也是今天第一天学,补充优化总结老师的课堂笔记中关于Flume的介绍
好的!我帮你把Flume课堂笔记重新梳理优化,让你今天学完后能真正理解并动手操作。
我会按**"是什么 → 为什么 → 怎么用 → 常见坑"**的逻辑重新组织。
📚 Flume 课堂笔记(优化版)
一、Flume是什么?(一句话 + 类比)
Flume = 日志界的"顺丰快递"
text
数据源(网站日志)→ Flume → 目的地(HDFS/Kafka)
实时采集 传输 存储
通俗理解:
-
你网购下单 → 快递员上门取件 → 分拣中心 → 送到你家
-
日志产生 → Source取数据 → Channel暂存 → Sink送走
二、为什么要用Flume?(解决什么问题)
| 问题 | 不用Flume | 用Flume |
|---|---|---|
| 数据源多 | 每个程序自己写代码写HDFS | 统一配置,无需改代码 |
| 流量洪峰 | 直接把HDFS打崩 | Channel做缓冲,削峰填谷 |
| 数据丢失 | 程序崩溃就丢数据 | Channel支持持久化,重启续传 |
| 实时性 | 定时批处理(延迟高) | 实时流式(秒级延迟) |
核心价值: 解耦 + 缓冲 + 可靠 + 实时
三、Flume核心架构(3大组件)
整体结构图(务必记住)
text
bash
[数据源] → [SOURCE] → [CHANNEL] → [SINK] → [目的地]
↑ ↑ ↑
对接上游 缓冲区 对接下游
3.1 Source(数据来源)
职责: 对接上游数据源,读取数据封装成Event
常用Source类型:
| 类型 | 用法 | 场景 | 注意事项 |
|---|---|---|---|
| taildir | 监控文件追加内容 | 采集日志文件 | ✅ 生产首选(支持断点续传) |
| netcat | 监听端口 | 测试/演示 | ❌ 生产不用(会丢数据) |
| exec | 执行tail命令 | 简单场景 | ⚠️ 进程重启会丢数据 |
| http | HTTP POST接收 | 埋点采集 | 适合Web端直接上报 |
| kafka | 从Kafka消费 | 数据管道 | 配合Kafka使用 |
3.2 Channel(传输通道)
职责: 缓冲区,解决读写速度不一致,保证数据不丢失
常用Channel类型:
| 类型 | 特点 | 场景 | 性能 |
|---|---|---|---|
| memory | 内存缓冲,快 | 允许丢数据(测试) | 极高 |
| file | 磁盘缓冲,安全 | 生产环境(不能丢数据) | 一般 |
| kafka | Kafka做通道 | 大数据管道 | 高 |
关键参数:
text
bash
capacity = 1000 # 队列最大容量
transactionCapacity = 100 # 每次事务最大处理数
3.3 Sink(数据出口)
职责: 从Channel取数据,推送到目标系统
常用Sink类型:
| 类型 | 目的地 | 场景 |
|---|---|---|
| hdfs | HDFS | 离线存储 |
| kafka | Kafka | 消息队列 |
| logger | 控制台 | 测试调试 |
| hbase | HBase | 实时查询 |
| file_roll | 本地文件 | 临时存储 |
四、核心概念:Event(事件)
Event = Flume传输的最小数据单元
text
bash
┌─────────────────┐
│ Headers (KV) │ ← 元数据(路径、时间戳等)
├─────────────────┤
│ Body (字节) │ ← 实际数据(日志内容)
└─────────────────┘
例子:
json
{
"headers": {
"timestamp": "2025-05-28 10:00:00",
"filename": "app.log"
},
"body": "2025-05-28 10:00:01 INFO User login"
}
五、Flume配置文件详解(模板)
5.1 配置文件三段式结构
properties
# 第1步:命名组件
agent名称.sources = source名称
agent名称.sinks = sink名称
agent名称.channels = channel名称
# 第2步:配置Source
agent名称.sources.source名称.type = xxx
agent名称.sources.source名称.参数1 = 值1
# 第3步:配置Sink
agent名称.sinks.sink名称.type = xxx
agent名称.sinks.sink名称.参数1 = 值1
# 第4步:配置Channel
agent名称.channels.channel名称.type = xxx
agent名称.channels.channel名称.参数1 = 值1
# 第5步:绑定关系
agent名称.sources.source名称.channels = channel名称
agent名称.sinks.sink名称.channel = channel名称
5.2 启动命令模板
bash
bin/flume-ng agent \
-c conf/ \ # 配置文件目录
-n agent名称 \ # Agent名字(必须和配置一致)
-f job/配置文件.conf \ # 配置文件路径
-Dflume.root.logger=INFO,console # 日志输出到控制台
六、三个实战案例(从易到难)
案例1:端口 → 控制台(测试连通性)
properties
# netcat-logger.conf
a1.sources = r1
a1.sinks = k1
a1.channels = c1
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 8888
a1.sinks.k1.type = logger
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
测试:
bash
# 终端1:启动Flume
bin/flume-ng agent -c conf/ -n a1 -f job/netcat-logger.conf
# 终端2:发送数据
nc localhost 8888
> hello flume
案例2:文件 → HDFS(生产常用)
properties
# file-hdfs.conf
a2.sources = r2
a2.sinks = k2
a2.channels = c2
# Source: 监控文件
a2.sources.r2.type = exec
a2.sources.r2.command = tail -F /opt/logs/app.log
# Sink: 写入HDFS
a2.sinks.k2.type = hdfs
a2.sinks.k2.hdfs.path = hdfs://node100:9000/flume/%Y%m%d/%H
a2.sinks.k2.hdfs.filePrefix = logs-
a2.sinks.k2.hdfs.useLocalTimeStamp = true
a2.sinks.k2.hdfs.fileType = DataStream
a2.sinks.k2.hdfs.rollInterval = 60 # 1分钟滚动
a2.sinks.k2.hdfs.rollSize = 134217728 # 128M滚动
a2.channels.c2.type = memory
a2.channels.c2.capacity = 1000
a2.channels.c2.transactionCapacity = 100
a2.sources.r2.channels = c2
a2.sinks.k2.channel = c2
关键参数说明:
-
rollInterval:多久生成新文件(秒) -
rollSize:文件多大时滚动(字节) -
round:是否按时间创建文件夹 -
useLocalTimeStamp:使用本地时间(不用HDFS时间)
案例3:多路复用(一个Source → 多个Sink)
properties
# fanout.conf
a3.sources = r3
a3.sinks = k3 k4
a3.channels = c3 c4
a3.sources.r3.type = taildir
a3.sources.r3.filegroups = f1
a3.sources.r3.filegroups.f1 = /opt/logs/*.log
# 根据header分流
a3.sources.r3.selector.type = multiplexing
a3.sources.r3.selector.header = logtype
a3.sources.r3.selector.mapping.error = c3
a3.sources.r3.selector.mapping.warn = c3
a3.sources.r3.selector.mapping.info = c4
# error/warn 写到HDFS
a3.sinks.k3.type = hdfs
a3.sinks.k3.hdfs.path = hdfs://node100:9000/error_logs/
# info 写到Kafka
a3.sinks.k4.type = kafka
a3.sinks.k4.kafka.topic = weblog
a3.channels.c3.type = file
a3.channels.c4.type = memory
a3.sources.r3.channels = c3 c4
a3.sinks.k3.channel = c3
a3.sinks.k4.channel = c4
七、常见错误 & 解决方案
错误1:java.net.ConnectException: Connection refused
原因: HDFS没启动或地址写错
解决:
bash
# 检查HDFS
hdfs dfs -ls /
# 查看配置
hdfs getconf -confKey fs.defaultFS
错误2:No such file or directory
原因: HDFS目录不存在
解决:
bash
hdfs dfs -mkdir -p /flume
错误3:java.lang.OutOfMemoryError
原因: Channel容量太大
解决:
properties
# 减小capacity
a1.channels.c1.capacity = 1000
# 增加JVM内存
export JAVA_OPTS="-Xmx2g"
错误4:Exec source丢数据
原因: 进程重启后tail命令中断
解决: 改用taildir source
properties
a1.sources.r1.type = taildir
a1.sources.r1.positionFile = /opt/flume/taildir.json
a1.sources.r1.filegroups = f1
a1.sources.r1.filegroups.f1 = /opt/logs/*.log
八、面试重点(背下来)
8.1 Flume的三大组件及作用
-
Source:采集数据,封装Event
-
Channel:缓冲数据,保证可靠性
-
Sink:发送数据到目的地
8.2 Flume如何保证数据不丢失?
-
Channel支持file持久化(重启后数据还在)
-
Sink有事务机制(成功才删除Channel数据)
-
taildir source记录读取位置(断点续传)
8.3 Memory Channel和File Channel区别
| 维度 | Memory | File |
|---|---|---|
| 速度 | 快 | 慢 |
| 可靠性 | 低(进程死丢数据) | 高 |
| 场景 | 测试/允许丢数据 | 生产/不能丢数据 |
8.4 Taildir Source优点
-
✅ 支持断点续传
-
✅ 支持通配符监控多个文件
-
✅ 不会丢数据
九、你今天必须动手做的练习
练习1:跑通netcat示例
bash
# 目标:看到Event输出
练习2:跑通file→HDFS示例
bash
# 目标:HDFS上看到文件
练习3:修改参数观察效果
bash
# 修改rollInterval=10,观察文件多久滚动一次
# 修改capacity=10,发送20条数据看会不会阻塞
练习4:模拟故障恢复
bash
# 1. 启动taildir采集
# 2. 写入100条数据
# 3. Ctrl+C停掉Flume
# 4. 再写入50条
# 5. 重启Flume → 应该能从断点继续,不会重复消费前100条
十、你笔记中需要补充的地方
| 你的笔记 | 问题 | 补充 |
|---|---|---|
| "基于流式架构" | 没解释流式和离线的区别 | 流式:数据产生即处理(秒级); 离线:处理历史数据(T+1) |
| "高可用,高可靠" | 没说明怎么实现的 | 高可用:多Agent部署; 高可靠:Channel持久化+事务 |
| "taildir, http, exec" | 没说明怎么选 | 生产用taildir, 测试用netcat, exec有坑别用 |
| "实时将用户行为数据拉取到HDFS" | 缺少具体配置 | 见上面案例2 |
🎯 你现在需要做的事
-
先确认环境 :
jps看Hadoop是否运行 -
跑通案例1(5分钟):netcat → logger
-
跑通案例2(10分钟):文件 → HDFS
-
把报错或成功截图发我
告诉我:
-
哪个案例跑通了?
-
哪个卡住了?
-
报错信息是什么?
我帮你解决直到完全跑通!