(实验二 熟悉常用的 Hbase 操作)
--------------------------------------------------------------------------------------------------------------------------------
Tips:"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量加持💪,快来和我一起分享这份快乐吧😊!
喜欢我的博客的话,记得点个红心❤️和小关小注哦!您的支持是我创作的动力!(有什么问题可以私信)
一、实验目的
1.理解 HBase 在 Hadoop体系结构中的角色。
分布式存储:HBase以分布式方式存储数据,利用HDFS作为底层存储介质,确保数据的高可用性和可靠性。面向列的存储:HBase将数据按列存储,提供高效的随机读写能力,尤其适合需要频繁访问单个数据列的应用场景。实时读写:HBase支持实时的数据读写,能够满足对数据实时性要求较高的应用需求,如在线交易处理、日志分析等。整合Hadoop生态系统:HBase与其他Hadoop生态系统组件(如HDFS、MapReduce、YARN等)紧密集成,能够协同工作,提供全面的大数据解决方案。
2.熟练 HBase 操作常用的 Shell命令。
| # 创建表 |
3.熟悉 HBase 操作常用的 JavaAPI。
熟悉HDFS操作常用的Java API:除了Shell命令,HBase提供了一套Java API,开发者通过编程的方式操作HDFS。
二、实验环境
1. VMware WorkStation Pro 16
2. Jdk 1.8.0_241
3. Hadoop2.7.5
4. Zookeeper3.4.6
5. HBase2.1.0
三、实验原理
1. 连接Hbase集群
创建一个HBase配置对象,设置ZooKeeper的主机名或IP地址。通过ConnectionFactory类创建一个Connection对象,用于与HBase集群建立连接。
2. 插入Hbase数据
创建一个Put对象,指定要插入数据的行键,然后添加列族、列限定符和对应的值。通过Table对象的put方法将数据插入到HBase表中。
3. 读取Hbase数据
创建一个Get对象,指定要读取数据的行键,可添加列族和列限定符进行条件查询。通过Table对象的get方法获取指定行的数据,返回一个Result对象。从Result对象中提取数据。
4. 修改Hbase数据
创建一个Put对象,指定要修改数据的行键,然后添加列族、列限定符和对应的新值。通过Table对象的put方法执行修改操作,将新值覆盖原有的值。
5. 删除Hbase数据
创建一个Delete对象,指定要删除数据的行键。通过Table对象的delete方法执行删除操作,从HBase表中删除指定行的数据。
- 实验原理解释
HBase是一个分布式、可扩展、面向列的NoSQL数据库,通过Java客户端API可以访问和操作HBase。Java代码与HBase集群建立连接,通过Connection对象获取Table对象,用于操作HBase表。插入数据使用Put对象,指定行键和列族、列限定符以及对应的值,将数据插入到HBase表中。读取数据使用Get对象,指定要读取的行键和列族、列限定符,从HBase表中获取指定行的数据。修改数据也使用Put对象,指定要修改的行键和列族、列限定符以及新值,通过put方法执行修改操作。删除数据使用Delete对象,指定要删除的行键,通过delete方法执行删除操作,从HBase表中删除指定行的数据。这些操作可以通过Java代码实现,实现了对HBase表中数据的增加、删除、修改和查询。
四、实验步骤与实验结果
(一)安装Zookeeper。
1.准备安装包。
| rz zookeeper-3.4.6.tar.gz |

2.解压。
| tar zxvf zookeeper-3.4.6.tar.gz -C /export/server/ |

3.创建文件夹zkdata,并建立三个节点文件夹zk。
| # 切换到数据目录 cd /export/data/ # 创建zkdata文件夹,并建立子文件夹 mkdir zkdata cd zkdata mkdir zk1 mkdir zk2 mkdir zk3 |
4.创建zoo.cfg文件。
| # 第一个文件 cd /export/data/zkdata/zk1 vim zoo1.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/export/data/zkdata/zk1 clientPort=2181 server.1=192.168.88.100:2888:3888 server.2=192.168.88.100:2889:3889 server.3=192.168.88.100:2890:3890 # 第二个文件 cd /export/data/zkdata/zk2 vim zoo2.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/export/data/zkdata/zk2 clientPort=2182 server.1=192.168.88.100:2888:3888 server.2=192.168.88.100:2889:3889 server.3=192.168.88.100:2890:3890 # 第三个文件 cd /export/data/zkdata/zk3 vim zoo3.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/export/data/zkdata/zk3 clientPort=2183 server.1=192.168.88.100:2888:3888 server.2=192.168.88.100:2889:3889 server.3=192.168.88.100:2890:3890 |

5.创建文件myid。
| #在每台机器的dataDir指定的目录下创建一个文件 名字叫做myid #myid里面的数字就是该台机器上server编号。server.N N的数字就是编号 [root@node1 conf]# echo 1 >/export/data/zkdata/zk1/myid [root@node1 conf]# echo 2 >/export/data/zkdata/zk2/myid [root@node1 conf]# echo 3 >/export/data/zkdata/zk3/myid |
6.启动单台zookeeper服务。
| #在哪个目录执行启动命令 默认启动日志就生成当前路径下 叫做zookeeper.out /export/server/zookeeper/bin/zkServer.sh start /export/data/zkdata/zk1/zoo1.cfg # 启动命令 jps # 查看服务进程 /export/server/zookeeper/bin/zkServer.sh stop /export/data/zkdata/zk1/zoo1.cfg # 关闭命令 |


7.封装脚本启动zookeeper服务。
| 本质:在node1机器上执行shell脚本,由shell程序通过ssh免密登录到各个机器上帮助执行命令。 一键关闭脚本: [root@node1 ~]# vim stopZk.sh #!/bin/bash hosts=(node1) for host in ${hosts[*]} do ssh $host "/export/server/zookeeper/bin/zkServer.sh stop /export/data/zkdata/zk1/zoo1.cfg" done 一键启动脚本: [root@node1 ~]# vim stopZk.sh #!/bin/bash hosts=(node1) for host in ${hosts[*]} do ssh $host "/export/server/zookeeper/bin/zkServer.sh start /export/data/zkdata/zk1/zoo1.cfg" done |

(二)安装HBase。
1.准备安装包。
| rz hbase-2.1.0.tar.gz |

2.上传、解压。
| tar -zxvf hbase-2.1.0.tar.gz -C /export/server/ |

3.修改配置文件hbase-env.sh。
| # 切换到配置文件目录下 cd /export/server/hbase-2.1.0/conf/ # 修改hbase-env.sh #28行 export JAVA_HOME=/export/server/jdk1.8.0_241 #125行 export HBASE_MANAGES_ZK=false |
4.修改配置文件hbase-site.sh。
| # 修改hbase-site.xml cd /export/server/hbase-2.1.0/ mkdir datas vim conf/hbase-site.xml <property > <name>hbase.tmp.dir</name> <value>/export/server/hbase-2.1.0/datas</value> </property> <property > <name>hbase.rootdir</name> <value>hdfs://node1:8020/hbase</value> </property> <property > <name>hbase.cluster.distributed</name> <value>true</value> </property> <property> <name>hbase.zookeeper.quorum</name> <value>node1</value> </property> <property> <name>hbase.unsafe.stream.capability.enforce</name> <value>false</value> </property> |
5.修改配置文件regionservers。
| vim conf/regionservers node1 |
6.配置环境变量。
| vim /etc/profile #HBASE_HOME export HBASE_HOME=/export/server/hbase-2.1.0 export PATH=:$PATH:$HBASE_HOME/bin # 刷新环境变量 source /etc/profile |
7.复制jar包。
| #切换目录 cd /export/server/hbase-2.1.0 # 复制jar包到lib目录 cp lib/client-facing-thirdparty/htrace-core-3.1.0-incubating.jar lib/ |
8.启动hbase服务。
| # 首先启动hdfs cd /export/server/hadoop-2.7.5/sbin ./start-all.sh # 再启动zookeeper cd ./startZk.sh # 最后启动hbase cd /export/server/hbase-2.1.0/bin ./start-hbase.sh |

9.关闭hbase服务。
| # 首先关闭hbase cd /export/server/hbase-2.1.0/bin ./stop-hbase.sh # 再关闭zookeeper cd ./stopZk.sh # 最后关闭hdfs cd /export/server/hadoop-2.7.5/sbin ./stop-all.sh |
10.观察Hbase的UI界面。
| # 浏览器上打开 node1:16010 |

(三)编程实现一下指定功能,并用hadoop提供的hbase shell命令完成相同的任务。
1.提前准备实验数据。
| # 进入命令行shell模式 hbase shell # 当创建 HBase 表时,需要使用 create 命令,并设置好表的名称、列族等信息 # 这条命令会创建一个名为 student 的表,包含两个列族,分别为 info 和 score。 create 'student', 'info', 'score' # 可以使用 put 命令向表中插入数据, put 'student', '001', 'info:name', 'Tom' put 'student', '001', 'info:gender', 'male' put 'student', '001', 'score:math', '85' put 'student', '001', 'score:english', '78' |

2.列出Hbase所有表的相关信息,如表名,创建时间等。
(1)shell版本
| # hbase罗列数据表 list # 表信息 scan 'student' |

(2)Java版本
| package cn.itcast.Exp_3; System.out.println("-------------------------------------"); |

3.在终端打印指定表的所有记录数据。
(1)shell版本
| # 表信息 scan 'student' |

(2)Java版本
| package cn.itcast.Exp_3; |

4.向已经创建好的表添加和删除指定的列族或者列。
(1)shell版本
| # 添加列簇 alter 'student', {NAME => 'newColumnFamily'} # 删除列簇 alter 'student', {NAME => 'newColumnFamily', METHOD => 'delete'} # 添加列 put 'student', '001', 'info:newColumn', 'NewValue' # 删除列 delete 'student', '001', 'info:newColumn' ==============经过以上操作:数据表student不变================== |




(2)Java版本
| package cn.itcast.Exp_3; |




5.清空指定表的所有记录数据。
(1)shell版本
| truncate 'student' # 如果执行完之后,表就是空表了,记得补充数据进去才能进行java实验! put 'student', '001', 'info:name', 'Tom' put 'student', '001', 'info:gender', 'male' put 'student', '001', 'score:math', '85' put 'student', '001', 'score:english', '78' |

(2)Java版本
| package cn.itcast.Exp_3; |

| # 如果执行完之后,表就是空表了,记得补充数据进去才能进行一个实验! put 'student', '001', 'info:name', 'Tom' put 'student', '001', 'info:gender', 'male' put 'student', '001', 'score:math', '85' put 'student', '001', 'score:english', '78' |
6.统计表的行数。
(1)shell版本
| Count ‘student’ |

(2)Java版本
| package cn.itcast.Exp_3; |

(四)现有以下关系型数据库中的表(见表4-20、表4-21、表4-22),要求将其转换为适合HBase存储的表并插入数据。
表4-20 学生表(Student)
| 学号(S_No) | 姓名(S_Name) | 性别(S_Sex) | 年龄(A_Age) |
| 2015001 | Zhangsan | male | 23 |
| 2015002 | Mary | female | 22 |
| 2015003 | Lisi | male | 24 |
表4-21 课程表(Course)
| 课程号(C_No) | 课程名(C_Name) | 学分(C_Credit) |
| 123001 | Math | 2.0 |
| 123001 | Computer Science | 5.0 |
| 123003 | English | 3.0 |
表4-22 选课表(SC)
| 学号(SC_Sno) | 课程号(SC_Cno) | 成绩(SC_Score) |
| 2015001 | 123001 | 86 |
| 2015001 | 123003 | 69 |
| 2015002 | 123002 | 77 |
| 2015002 | 123003 | 99 |
| 2015003 | 123001 | 98 |
| 2015003 | 123002 | 95 |
1.准备数据源
(1)shell版本
| # 创建学生表 create 'Student', 'info' # 插入学生数据 put 'student', '2015001', 'info:S_No', '2015001' put 'student', '2015001', 'info:S_Name', 'Zhangsan' put 'student', '2015001', 'info:S_Sex', 'male' put 'student', '2015001', 'info:A_Age', '23' put 'student', '2015002', 'info:S_No', '2015002' put 'student', '2015002', 'info:S_Name', 'Mary' put 'student', '2015002', 'info:S_Sex', 'female' put 'student', '2015002', 'info:A_Age', '22' put 'student', '2015003', 'info:S_No', '2015003' put 'student', '2015003', 'info:S_Name', 'Lisi' put 'student', '2015003', 'info:S_Sex', 'male' put 'student', '2015003', 'info:A_Age', '24' # 创建课程表 create 'Course', 'info' # 插入课程数据 put 'Course', '123001', 'info:C_No', '123001' put 'Course', '123001', 'info:C_Name', 'Math' put 'Course', '123001', 'info:C_Credit', '2.0' put 'Course', '123002', 'info:C_No', '123002' put 'Course', '123002', 'info:C_Name', 'Computer Science' put 'Course', '123002', 'info:C_Credit', '5.0' put 'Course', '123003', 'info:C_No', '123003' put 'Course', '123003', 'info:C_Name', 'English' put 'Course', '123003', 'info:C_Credit', '3.0' # 创建选课表 create 'SC', 'info' # 插入选课数据 put 'SC', '2015001', 'info:SC_Sno', '2015001' put 'SC', '2015001', 'info:SC_Cno', '123001' put 'SC', '2015001', 'info:SC_Score', '86' put 'SC', '2015001', 'info:SC_Sno', '2015001' put 'SC', '2015001', 'info:SC_Cno', '123003' put 'SC', '2015001', 'info:SC_Score', '69' put 'SC', '2015002', 'info:SC_Sno', '2015002' put 'SC', '2015002', 'info:SC_Cno', '123002' put 'SC', '2015002', 'info:SC_Score', '77' put 'SC', '2015002', 'info:SC_Sno', '2015002' put 'SC', '2015002', 'info:SC_Cno', '123003' put 'SC', '2015002', 'info:SC_Score', '99' put 'SC', '2015003', 'info:SC_Sno', '2015003' put 'SC', '2015003', 'info:SC_Cno', '123001' put 'SC', '2015003', 'info:SC_Score', '98' put 'SC', '2015003', 'info:SC_Sno', '2015003' put 'SC', '2015003', 'info:SC_Cno', '123002' put 'SC', '2015003', 'info:SC_Score', '95' |
(2)Java版本
| package cn.itcast.Exp_3; |

(五)同时,请编程完成以下指定功能。
1.createTable(String tableName, String[] fields)。
创建表,参数tableName为表的名称,字符串数组 fields为存储记录各个域名称的数组。要求当HBase已经存在名为tableName的表的时候,先删除原有的表,再创建新的表。
| package cn.itcast.Exp_3; |

2addRecord(String tableName, String row, String[] fields, String[] values)。
向表tableName、行 row (用S_Name表示)和字符串数组fields指定的单元格中添加对应的数据 values。其中 fields中每个元素如果对应的列族下还有相应的列限定符的话,用"columnFamily:column”表示。例如,同时向“Math”,“Computer Science”,“English”3列添加成绩时,字符串数组fields为{“Score:Math”,"Score: Computer Science”, "Score:English"},数组 values存储这3门课的成绩。
| package cn.itcast.Exp_3; |


3 scanColumn(String tableName, String column)。
浏览表tableName某一列的数据,如果某一行记录中该列数据不存在,则返回null。要求当参数column为某一列族名称时,如果底下有若干个列限定符,则要列出每个列限定符代表的列的数据;当参数column为某一列具体名称(如“Score:Math”)时,只需要列出该列的数据。
| package cn.itcast.Exp_3; |

4.modifyData(String tableName,String row,String column)。
修改表tableName,行row(可用学生姓名S_Name表示),列column指定的单元格的数据。
| package cn.itcast.Exp_3; |

5.deleteRow(String tableName, String row)。
删除表tableName 中 row指定的行的记录。
| package cn.itcast.Exp_3; |

五、实验总结
(一)发现问题与解决问题
1.至少需要指定一个列簇
| Caused by: org.apache.hadoop.hbase.ipc.RemoteWithExtrasException(org.apache.hadoop.hbase.DoNotRetryIOException): org.apache.hadoop.hbase.DoNotRetryIOException: Table should have at least one column family. Set hbase.table.sanity.checks to false at conf or table descriptor if you want to bypass sanity checks |
原因分析:根据报错信息进行查询资料发现,在创建表的时候需要指定列簇,并且一旦指定就无法轻易删除,只能通过修改名字来进行更改!这个异常的意思是表至少应该有一个列族。HBase要求表在创建时必须至少包含一个列族,否则会触发这个异常。
在HBase中,数据是按照行键(rowkey)、列族(column family)、列限定符(qualifier)和时间戳(timestamp)来组织的。列族是表的一个重要组成部分,每个表都必须至少有一个列族。如果在创建表的时候没有指定列族,就会出现这个异常。
解决方法:所以在创建表的时候,一定要为表指定至少一个列族。可以通过HBase shell或者Java API来创建表,并在创建表的时候指定列族。
2.zookeeper需要伪分布式安装
| 2023-11-13 09:57:58,097 INFO [main-SendThread(node1.itcast.cn:2182)] zookeeper.ClientCnxn: Opening socket connection to server node1.itcast.cn/192.168.88.100:2182. Will not attempt to authenticate using SASL (unknown error) 2023-11-13 09:57:58,098 WARN [main-SendThread(node1.itcast.cn:2182)] zookeeper.ClientCnxn: Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect java.net.ConnectException: Connection refused at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717) org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:361) at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1141) |
原因分析:根据报错信息可知,根据提供的错误日志,可以看出出现了连接拒绝的错误(Connection refused)。这通常表示在与服务器建立连接时遇到了问题。
可能的原因和解决方法如下:
服务器未启动或未正确配置。请确保Zookeeper服务器已启动并正常运行,并且可以通过指定的主机名和端口号进行访问。
防火墙或网络配置问题。防火墙设置可能会阻止与指定主机和端口的连接。请检查防火墙配置并确保允许与Zookeeper服务器的通信。
网络连接问题。连接拒绝错误可能是由于网络连接问题引起的。请确保网络连接正常,并且没有任何故障或中断。
端口号错误。请确保正在使用正确的端口号连接到Zookeeper服务器。默认情况下,Zookeeper使用2181端口。
解决方法:所以在搭建zookeeper的时候采取伪分布式安装,即可实现一个node节点可以有三个zookeeper服务,进而在连接hbase时可以正常使用。
3.hregionserver服务启动失败
| 2023-11-13 09:30:45,378 WARN [main] regionserver.HRegionServerCommandLine: Not starting a distinct region server because hbase.cluster.distributed is false |
原因分析:根据提供的警告日志,可以看到"HRegionServerCommandLine"指示不会启动独立的区域服务器。
解决方法:所以在hbase-site.xml中设置集群模式为true。
4.端口占用报错
| Could not start ZK at requested port of 2181. ZK was started at port: 2182. Aborting as clients (e.g. shell) will not be able to find this ZK quorum. |
原因分析:根这个问题的原因是在尝试启动Zookeeper时,发现使用的默认端口2181已经被占用,所以Zookeeper启动在了备选的端口2182上。然而,由于客户端(例如shell)通常会默认连接到2181端口,所以Zookeeper启动在备选端口上可能导致客户端无法正确连接到Zookeeper集群。
解决方法:
| [root@node1 hbase-2.1.0]# netstat -tlnp | grep 2181 tcp6 0 0 :::2181 :::* LISTEN 4390/java [root@node1 hbase-2.1.0]# kill -9 4390 [root@node1 hbase-2.1.0]# netstat -tlnp | grep 2181 hbase-site.xml <property> <name>hbase.zookeeper.property.clientPort</name> <value>2182</value> </property> |
(二)实验心得与思考体会
在进行Java操作HBase的实验过程中,我获得了一些实验心得和思考体会。下面是我总结的几点:
- HBase的数据模型:
HBase是一个基于列族的分布式数据库,它的数据模型与传统的关系型数据库有所不同。在实验中,我学会了如何创建表、定义列族,并根据需要插入、查询和删除数据。这让我更好地理解了HBase的数据组织方式和操作方法。
- 使用Java API操作HBase:
通过Java API,我可以在Java程序中对HBase进行增删查改操作。我学会了如何使用HBase的Java API连接到HBase集群、创建和删除表,以及对表中的数据进行CRUD操作。这为我开发基于HBase的应用程序提供了基础。
- 批量操作和过滤器:
在实验中,我还学习了如何使用批量操作和过滤器来提高HBase的性能。通过批量操作,我可以一次性插入或删除多行数据,减少网络开销和通信次数。而过滤器则可以帮助我在查询时快速定位到所需数据,避免不必要的数据传输和处理。
- 异常处理和错误调试:
在实验过程中,我遇到了一些异常情况和错误,例如连接超时、表不存在等。通过仔细阅读异常信息和调试代码,我学会了如何正确处理这些异常,并找出问题所在。这对于开发稳定和可靠的HBase应用程序至关重要。
总的来说,通过这次实验,我不仅对HBase有了更深入的理解,还提升了自己的Java编程能力和错误调试能力。我意识到在使用分布式数据库时,需要考虑到数据模型、性能优化和异常处理等方面的问题。这对于我今后的工作和学习都具有重要的指导意义。
1059

被折叠的 条评论
为什么被折叠?



