简介:本资源为南京邮电大学大数据存储与管理课程实验一的完整报告文档,面向大数据、计算机相关专业学生及Redis初学者,帮助解决单机与集群环境搭建、后端应用开发等实操问题。压缩包内仅含1个doc文件,约933KB,内容涵盖实验目的、环境配置、原理说明、详细步骤与结果分析,结构完整,可直接作为实验参考或课程作业模板。文档以Ubuntu 16.04为操作环境,系统梳理了Redis单机安装、六节点集群搭建以及基于Redis的文章投票网站后端实现,涉及String与Sorted Set数据模型、INCR、ZADD、ZRANGE等核心命令,并附有PyCharm与Another Redis Desktop Manager的配置与排错记录。目前已有324人学习,适合需要快速掌握Redis基础操作与集群部署的读者对照实践,也可为后续大数据存储技术学习提供入门参考。
1. 南邮大数据存储与管理实验一:从单机伪分布式到 HDFS 读写的最小闭环
很多同学第一次看到“南邮大数据存储与管理实验一”这个标题,会下意识以为它只是装个 Hadoop、跑个 WordCount 就完事。真动手才发现,卡住人的从来不是代码,而是环境:Java 版本对不上、core-site.xml 里端口写错、NameNode 反复格式化、DataNode 起不来。这个实验真正要建立的能力,是理解 HDFS 的存储模型——块、副本、元数据——并且能在单机伪分布式环境下把“上传、分块、复制、读取”这条链路完整跑通。它适合刚接触大数据存储的本科生和转行工程师,也适合想补回底层认知的后端开发者。下面我按自己踩过坑的顺序,把这条最小闭环拆开讲。
2. 实验环境怎么搭:伪分布式不是“简化版”,而是单机模拟集群
伪分布式(Pseudo-Distributed)的核心是:所有守护进程跑在同一台机器上,但彼此通过 RPC 通信,行为和真实集群一致。这意味着你调试时看到的日志、端口、进程关系,和线上集群是同一套逻辑。很多人图省事用本地模式(Local Mode)跑完就交,结果完全没碰到 HDFS,实验分自然低。
2.1 三个前置条件必须先确认
在装 Hadoop 之前,有三件事必须先落地,否则后面全是玄学报错。
第一是 JDK。Hadoop 3.x 官方推荐 JDK 8,用 JDK 11 或 17 会出现模块访问相关的反射警告,严重时 NameNode 直接起不来。用下面命令确认版本:
# 确认 Java 版本,必须是 1.8.x java -version # 输出示例:openjdk version "1.8.0_xxx" # 确认 JAVA_HOME 已导出,Hadoop 脚本依赖它 echo $JAVA_HOME第二是主机名与 hosts。HDFS 的 DataNode 注册时用的是主机名,如果hostname返回的名字在/etc/hosts里解析不到,DataNode 会一直连不上 NameNode。常见做法是把主机名和 127.0.0.1 绑定:
# 查看当前主机名 hostname # 编辑 hosts,把主机名映射到回环地址 sudo vi /etc/hosts # 追加一行(把 your-hostname 换成上一步的输出) 127.0.0.1 your-hostname第三是 SSH 免密。伪分布式下 start-dfs.sh 会通过 SSH 登录本机启动进程,没配免密就会反复要密码,脚本直接中断。
# 生成密钥对,一路回车 ssh-keygen -t rsa -P '' # 把公钥追加到授权文件 cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys # 验证免密登录本机 ssh localhost这三步做完再解压 Hadoop,能省掉后面一半的排查时间。
2.2 四个配置文件决定集群能不能起来
Hadoop 的配置集中在etc/hadoop/下,伪分布式只需要改四个文件。我一般按下面顺序改,改完逐个核对。
core-site.xml指定默认文件系统和临时目录:
<configuration> <!-- NameNode 的 RPC 地址,端口 9000 是约定俗成的 --> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> <!-- 临时目录,格式化后会在这里生成元数据 --> <property> <name>hadoop.tmp.dir</name> <value>/home/youruser/hadoop/tmp</value> </property> </configuration>hdfs-site.xml指定副本数和数据目录:
<configuration> <!-- 伪分布式只有一台机器,副本数必须设为 1 --> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/home/youruser/hadoop/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/home/youruser/hadoop/datanode</value> </property> </configuration>mapred-site.xml和yarn-site.xml分别指定计算框架和资源调度:
<!-- mapred-site.xml --> <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration> <!-- yarn-site.xml --> <configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> </configuration>参数说明:dfs.replication设成 1 是因为伪分布式只有单个 DataNode,设成 3 会导致副本永远处于“复制中”状态,健康检查一直告警。hadoop.tmp.dir一定要指向一个有写权限的目录,默认的/tmp在重启后可能被清理,元数据丢失就得重新格式化。
2.3 格式化与启动的正确顺序
配置改完后,第一次启动前必须格式化 NameNode,且只能格式化一次。多次格式化会导致 NameNode 和 DataNode 的 clusterID 不一致,DataNode 拒绝注册。
# 格式化 NameNode,只做一次 hdfs namenode -format # 启动 HDFS start-dfs.sh # 用 jps 确认进程,应该看到 NameNode、DataNode、SecondaryNameNode jps如果 jps 里只有 NameNode 没有 DataNode,先去看logs/下 DataNode 的日志,八成是 clusterID 不匹配或数据目录权限问题。解决方式是停掉进程,删掉 namenode 和 datanode 两个目录,重新格式化一次。
3. HDFS 读写链路:块、副本、元数据到底怎么协作
环境起来只是第一步,实验真正要考的是你对 HDFS 存储机制的理解。很多人能跑通命令,但被问到“一个 200MB 文件上传后有几个块、几个副本、元数据存在哪”就答不上来。这一章把读写链路拆开。
3.1 写流程:客户端不是直接写 DataNode
HDFS 写数据的核心是“客户端只和 NameNode 要位置,数据直接流向 DataNode”。具体链路是:
- 客户端调用
create(),NameNode 在元数据里新建文件条目,此时文件大小为 0。 - 客户端开始写数据,数据先缓存在本地,按 128MB(Hadoop 3.x 默认块大小)切块。
- 每个块向 NameNode 申请一组 DataNode 位置,NameNode 按副本策略返回。
- 客户端和第一个 DataNode 建立管道,第一个再连第二个,形成 Pipeline。
- 数据包沿管道流下,每个 DataNode 写完向上一级发 ACK。
- 所有块写完,客户端通知 NameNode 关闭文件,元数据落盘。
用命令验证这个过程:
# 在 HDFS 建目录 hdfs dfs -mkdir -p /user/test/input # 上传一个本地文件 hdfs dfs -put ./local_data.txt /user/test/input/ # 查看文件被切成几个块,每个块在哪个 DataNode hdfs fsck /user/test/input/local_data.txt -files -blocks -locationsfsck的输出会列出每个 block 的 ID、大小和所在 DataNode。如果文件小于 128MB,只会有一个块;副本数配置为 1 时,locations 里只有一个地址。
3.2 读流程:短路读与网络读的差别
读流程比写简单,但有个容易忽略的点:客户端会优先选择离自己最近的副本。伪分布式下只有一个副本,所以走的是网络读。真实集群里,如果客户端本身就在某个 DataNode 上,会触发“短路读”,直接读本地磁盘,不走网络。
# 读取 HDFS 文件内容 hdfs dfs -cat /user/test/input/local_data.txt # 查看文件的元数据信息 hdfs dfs -stat "%n %o %r %b" /user/test/input/local_data.txt-stat的格式符含义:%n文件名,%o块大小,%r副本数,%b文件字节数。这几个值能直接反映你的配置是否生效。
3.3 用 Java API 跑通一次完整读写
命令行只是验证,实验通常要求用 Java API 编程。下面是一个最小可运行示例,包含写入和读取。
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.*; import java.io.*; public class HdfsDemo { public static void main(String[] args) throws Exception { // 加载配置,会自动读取 core-site.xml 里的 fs.defaultFS Configuration conf = new Configuration(); conf.set("fs.defaultFS", "hdfs://localhost:9000"); FileSystem fs = FileSystem.get(conf); // 写入:创建文件并写入内容 Path writePath = new Path("/user/test/api_demo.txt"); FSDataOutputStream out = fs.create(writePath, true); out.writeUTF("hello hdfs"); out.close(); // 读取:打开文件并打印内容 Path readPath = new Path("/user/test/api_demo.txt"); FSDataInputStream in = fs.open(readPath); String content = in.readUTF(); in.close(); System.out.println("读取内容: " + content); fs.close(); } }逻辑说明:FileSystem.get(conf)会根据配置返回对应文件系统的实例,伪分布式下就是 DistributedFileSystem。create()的第二个参数true表示覆盖已存在文件。writeUTF和readUTF是成对使用的,写入时会在前面加两个字节的长度前缀,读取时必须用同样的方法,否则会读到乱码。
参数说明:如果程序报Connection refused,检查 NameNode 是否在跑、端口是否和 core-site.xml 一致。如果报权限错误,是因为 HDFS 默认用当前系统用户做鉴权,可以在程序里设置conf.set("fs.defaultFS", ...)之前加System.setProperty("HADOOP_USER_NAME", "youruser")。
4. 避坑与排查:五个让实验卡到崩溃的典型问题
这一章是我自己带人做实验时收集的高频翻车点,每条都按“现象 → 原因 → 解决”写,照着排查基本能覆盖九成问题。
4.1 NameNode 反复格式化后 DataNode 消失
现象:jps只看到 NameNode,DataNode 进程不存在,日志里报Incompatible clusterIDs。
原因:每次hdfs namenode -format都会生成新的 clusterID,而 DataNode 的目录里还留着旧 ID,两者对不上就拒绝启动。
解决:停掉所有进程,删除dfs.namenode.name.dir和dfs.datanode.data.dir指向的目录,重新格式化一次,再启动。记住格式化只做一次。
4.2 上传文件报“Could only be replicated to 0 nodes”
现象:hdfs dfs -put卡住很久后报错,提示无法分配 DataNode。
原因:DataNode 没起来,或者磁盘空间不足,或者dfs.replication设成了大于实际 DataNode 数量的值。
解决:先jps确认 DataNode 在跑,再hdfs dfsadmin -report看集群节点数和剩余空间。伪分布式下把副本数改成 1。
4.3 端口 9000 被占用导致 NameNode 起不来
现象:NameNode 日志报BindException: Address already in use。
原因:上一次进程没退干净,或者别的服务占用了 9000。
解决:netstat -tlnp | grep 9000找到占用进程,杀掉或改端口。改端口要同时改 core-site.xml 和所有引用该地址的地方,改完重启。
4.4 Java API 报“No FileSystem for scheme: hdfs”
现象:程序启动就抛异常,说找不到 hdfs 的 FileSystem 实现。
原因:classpath 里缺 Hadoop 的 jar 包,或者core-site.xml没被打进 classpath。
解决:用 Maven 管理依赖,确保hadoop-common和hadoop-hdfs-client都在。如果手动加 jar,把etc/hadoop目录也加到 classpath 里。
4.5 读取文件时中文乱码
现象:hdfs dfs -cat显示的中文是乱码。
原因:文件本身编码不是 UTF-8,或者终端编码不匹配。
解决:确认源文件用 UTF-8 保存,终端执行export LANG=en_US.UTF-8或zh_CN.UTF-8。用 Java API 读写时统一用writeUTF/readUTF或指定StandardCharsets.UTF_8。
5. 从实验到生产:块大小、副本策略与一个小验证技巧
实验做完,很多人会问:这套东西和真实集群差在哪?差在参数调优和故障域设计。伪分布式下块大小默认 128MB,副本数 1,这两个值在生产里都要根据场景调。块太小,NameNode 元数据膨胀,内存压力大;块太大,MapReduce 任务并行度不够,单个任务拖尾严重。常见做法是:冷数据、大文件用 256MB,热数据、小文件多就维持 128MB 甚至更小,同时配合 HAR 或 CombineFileInputFormat 合并小文件。
副本策略在真实集群里默认是 3,且遵循机架感知:第一个副本放本地,第二个放同机架另一节点,第三个放不同机架。伪分布式只有一台机器,所以只能设 1。你可以用下面这个技巧验证副本策略是否生效:
# 查看某个文件的块分布和副本位置 hdfs fsck /user/test/input/local_data.txt -files -blocks -locations # 输出里每个 block 后面会跟一串 DataNode 地址 # 伪分布式下只有一个地址,真实集群下应该有三个且跨机架另一个值得养成的习惯是:每次改完配置,不要急着跑业务,先用hdfs dfsadmin -report看集群状态,确认 Live datanodes 数量、容量、剩余空间都符合预期。这个命令相当于集群的体检报告,能提前暴露八成配置问题。
我自己踩过最深的一个坑,是早期为了图快,在没配 hosts 的情况下直接格式化,结果 DataNode 注册时用了一个解析不到的主机名,日志里只报连接超时,查了两个小时才定位到是主机名解析的问题。从那以后,我养成了一个习惯:任何分布式环境,先确认主机名、hosts、SSH 三件套,再动安装包。这个顺序能帮你省下大量后悔药。
希望帮到你。
本文还有配套的精品资源,点击获取