20

11-03Windows10系统下Hadoop和Hive开发环境搭建填坑指南

 3 years ago
source link: http://www.throwable.club/2020/11/03/hadoop-hive-dev-env-in-win-10/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前提

笔者目前需要搭建数据平台,发现了 Windows 系统下, HadoopHive 等组件的安装和运行存在大量的坑,而本着有坑必填的目标,笔者还是花了几个晚上的下班时候在多个互联网参考资料的帮助下完成了 Windows10 系统下 HadoopHive 开发环境的搭建。这篇文章记录了整个搭建过程中的具体步骤、遇到的问题和对应的解决方案。

环境准备

基于笔者的软件版本洁癖,所有选用的组件都会使用当前(2020-10-30)最高的版本。

软件 版本 备注 Windows 10 操作系统 JDK 8 暂时不要选用大于等于 JDK9 的版本,因为启动虚拟机会发生未知异常 MySQL 8.x 用于管理 Hive 的元数据 Apache Hadoop 3.3.0 - Apache Hive 3.1.2 - Apache Hive src 1.2.2 因为只有 1.x 版本的 Hive 源码提供了 .bat 启动脚本,有能力可以自己写脚本就不用下此源码包 winutils hadoop-3.3.0 HadoopWindows 系统下的启动依赖

下面列举部分组件对应的下载地址:

  • Apache Hadoop 3.3.0https://mirror.bit.edu.cn/apache/hadoop/common/hadoop-3.3.0/hadoop-3.3.0.tar.gz
  • Apache Hive 3.1.2https://mirrors.bfsu.edu.cn/apache/hive/hive-3.1.2/apache-hive-3.1.2-bin.tar.gz
  • Apache Hive 1.2.2 srchttps://mirrors.bfsu.edu.cn/apache/hive/hive-1.2.2/apache-hive-1.2.2-src.tar.gz
  • winutilshttps://github.com/kontext-tech/winutils (如果下载速度慢,可以先把仓库导入 gitee.com 再下载,或者用笔者已经同步好的仓库 https://gitee.com/throwableDoge/winutils

下载完这一些列软件之后, MySQL 正常安装为系统服务随系统自启。解压 hadoop-3.3.0.tar.gzapache-hive-3.1.2-bin.tar.gzapache-hive-1.2.2-src.tar.gzwinutils 到指定目录:

YvmaUrr.jpg!mobile

接着把源码包 apache-hive-1.2.2-src.tar.gz 解压后的 bin 目录下的文件拷贝到 apache-hive-3.1.2-binbin 目录中:

JnuyAr6.jpg!mobile

然后把 winutils 中的 hadoop-3.3.0\bin 目录下的 hadoop.dllwinutils.exe 文件拷贝到 Hadoop 的解压目录的 bin 文件夹下:

ZBJ7NrV.jpg!mobile

最后再配置一下 JAVA_HOMEHADOOP_HOME 两个环境变量,并且在 Path 中添加 %JAVA_HOME%\bin;%HADOOP_HOME%\bin

mIZ77jB.jpg!mobile

笔者本地安装的JDK版本为1.8.0.212,理论上任意一个小版本的JDK8都可以。

接着用命令行测试一下,如果上述步骤没问题,控制台输出如下:

E3qa2uz.jpg!mobile

配置和启动Hadoop

HADOOP_HOMEetc\hadoop 子目录下,找到并且修改下面的几个配置文件:

core-site.xml(这里的 tmp 目录一定要配置一个非虚拟目录,别用默认的 tmp 目录,否则后面会遇到权限分配失败的问题)

<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://localhost:9000</value>
    </property>  
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/e:/LittleData/hadoop-3.3.0/data/tmp</value>
    </property>  
</configuration>

hdfs-site.xml(这里要预先创建 nameNodedataNode 的数据存放目录,注意一下每个目录要以 / 开头,笔者这里预先在 HADOOP_HOME/data 创建了 nameNodedataNode 子目录)

<configuration>
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
    <property>
        <name>dfs.http.address</name>
        <value>0.0.0.0:50070</value>
    </property>
    <property>    
        <name>dfs.namenode.name.dir</name>    
        <value>/e:/LittleData/hadoop-3.3.0/data/nameNode</value>    
    </property>    
    <property>    
        <name>dfs.datanode.data.dir</name>    
        <value>/e:/LittleData/hadoop-3.3.0/data/dataNode</value>  
    </property>
    <property>
        <name>dfs.permissions.enabled</name>
        <value>false</value>
    </property>
</configuration>

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>
    <property>
        <name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
        <value>org.apache.hadoop.mapred.ShuffleHandler</value>
    </property>
</configuration>

至此,最小化配置基本完成。接着需要格式化 namenode 并且启动 Hadoop 服务。切换至 $HADOOP_HOME/bin 目录下,使用 CMD 输入命令 hdfs namenode -format (格式化 namenode 切记不要重复执行):

Un2yEzj.jpg!mobile

格式化 namenode 完毕后,切换至 $HADOOP_HOME/sbin 目录下,执行 start-all.cmd 脚本:

bMFju2y.jpg!mobile

这里命令行会提示 start-all.cmd 脚本已经过期,建议使用 start-dfs.cmdstart-yarn.cmd 替代。同理,如果执行 stop-all.cmd 也会有类似的提示,可以使用 stop-dfs.cmdstop-yarn.cmd 替代。 start-all.cmd 成功执行后,会拉起四个 JVM 实例(见上图中的 Shell 窗口自动新建了四个 Tab ),此时可以通过 jps 查看当前的 JVM 实例:

λ jps
19408 ResourceManager
16324 NodeManager
14792 Jps
15004 NameNode
2252 DataNode

可见已经启动了 ResourceManagerNodeManagerNameNodeDataNode 四个应用,至此 Hadoop 的单机版已经启动成功。通过 stop-all.cmd 命令退出这四个进程。可以通过 http://localhost:8088/ 查看调度任务的状态:

3myaEzr.jpg!mobile

通过 http://localhost:50070/ 去查看 HDFS 的状态和文件:

Q7RRVjb.jpg!mobile

重启 Hadoop 的办法:先执行 stop-all.cmd 脚本,再执行 start-all.cmd 脚本。

配置和启动Hive

Hive 是构筑于 HDFS 上的,所以务必确保 Hadoop 已经启动。 HiveHDFS 中默认的文件路径前缀是 /user/hive/warehouse ,因此可以先通过命令行在 HDFS 中创建此文件夹:

hdfs dfs -mkdir /user/hive/warehouse
hdfs dfs -chmod -R 777 /user/hive/warehouse

同时需要通过下面的命令创建并为 tmp 目录赋予权限:

hdfs dfs -mkdir /tmp
hdfs dfs -chmod -R 777 /tmp

在系统变量中添加 HIVE_HOME ,具体的值配置为 E:\LittleData\apache-hive-3.1.2-bin ,同时在 Path 变量添加 %HIVE_HOME%\bin; ,跟之前配置 HADOOP_HOME 差不多。下载和拷贝一个 mysql-connector-java-8.0.x.jar$HIVE_HOME/lib 目录下:

NbymMrq.jpg!mobile

创建 Hive 的配置文件,在 $HIVE_HOME/conf 目录下已经有对应的配置文件模板,需要拷贝和重命名,具体如下:

  • $HIVE_HOME/conf/hive-default.xml.template => $HIVE_HOME/conf/hive-site.xml
  • $HIVE_HOME/conf/hive-env.sh.template => $HIVE_HOME/conf/hive-env.sh
  • $HIVE_HOME/conf/hive-exec-log4j.properties.template => $HIVE_HOME/conf/hive-exec-log4j.properties
  • $HIVE_HOME/conf/hive-log4j.properties.template => $HIVE_HOME/conf/hive-log4j.properties

FJ3ANb6.jpg!mobile

修改 hive-env.sh 脚本,在尾部添加下面内容:

export HADOOP_HOME=E:\LittleData\hadoop-3.3.0
export HIVE_CONF_DIR=E:\LittleData\apache-hive-3.1.2-bin\conf
export HIVE_AUX_JARS_PATH=E:\LittleData\apache-hive-3.1.2-bin\lib

修改 hive-site.xml 文件,主要修改下面的属性项:

属性名 属性值 备注 hive.metastore.warehouse.dir /user/hive/warehouse Hive 的数据存储目录,这个是默认值 hive.exec.scratchdir /tmp/hive Hive 的临时数据目录,这个是默认值 javax.jdo.option.ConnectionURL jdbc:mysql://localhost:3306/hive?characterEncoding=UTF-8&amp;serverTimezone=UTC Hive 元数据存放的数据库连接 javax.jdo.option.ConnectionDriverName com.mysql.cj.jdbc.Driver Hive 元数据存放的数据库驱动 javax.jdo.option.ConnectionUserName root Hive 元数据存放的数据库用户 javax.jdo.option.ConnectionPassword root Hive 元数据存放的数据库密码 hive.exec.local.scratchdir E:/LittleData/apache-hive-3.1.2-bin/data/scratchDir 创建本地目录 $HIVE_HOME/data/scratchDir hive.downloaded.resources.dir E:/LittleData/apache-hive-3.1.2-bin/data/resourcesDir 创建本地目录 $HIVE_HOME/data/resourcesDir hive.querylog.location E:/LittleData/apache-hive-3.1.2-bin/data/querylogDir 创建本地目录 $HIVE_HOME/data/querylogDir hive.server2.logging.operation.log.location E:/LittleData/apache-hive-3.1.2-bin/data/operationDir 创建本地目录 $HIVE_HOME/data/operationDir datanucleus.autoCreateSchema true 可选 datanucleus.autoCreateTables true 可选 datanucleus.autoCreateColumns true 可选 hive.metastore.schema.verification false 可选

修改完毕之后,在本地的 MySQL 服务新建一个数据库 hive ,编码和字符集可以选用范围比较大的 utf8mb4 (虽然官方建议是 latin1 ,但是字符集往大范围选没有影响):

7fA7FfY.jpg!mobile

上面的准备工作做完之后,可以进行 Hive 的元数据库初始化,在 $HIVE_HOME/bin 目录下执行下面的脚本:

hive --service schematool -dbType mysql -initSchema

这里有个小坑, hive-site.xml 文件的第 3215 行有个神奇的无法识别的符号:

2m2Y7ze.jpg!mobile

此无法识别符号会导致 Hive 的命令执行异常,需要去掉。当控制台输出 Initialization script completed schemaTool completed 的时候,说明元数据库已经初始化完毕:

Mz263uQ.jpg!mobile

$HIVE_HOME/bin 目录下,通过 hive.cmd 可以连接 Hive (关闭控制台即可退出):

> hive.cmd

尝试创建一个表 t_test

hive>  create table t_test(id INT,name string);
hive>  show tables;

查看 http://localhost:50070/ 确认 t_test 表已经创建成功。

vuiMNni.jpg!mobile

尝试执行一个写入语句和查询语句:

hive>  insert into t_test(id,name) values(1,'throwx');
hive>  select * from t_test;

bqMRf2Q.jpg!mobile

写用了 30 多秒,读用了 0.165 秒。

使用JDBC连接Hive

HiveServer2Hive 服务端接口模块,必须启动此模块,远程客户端才能对 Hive 进行数据写入和查询。目前,此模块还是基于 Thrift RPC 实现,它是 HiveServer 的改进版,支持多客户端接入和身份验证等功能。配置文件 hive-site.xml 中可以修改下面几个关于 HiveServer2 的常用属性:

属性名 属性值 备注 hive.server2.thrift.min.worker.threads 5 最小工作线程数,默认值为5 hive.server2.thrift.max.worker.threads 500 最大工作线程数,默认值为500 hive.server2.thrift.port 10000 侦听的 TCP 端口号,默认值为10000 hive.server2.thrift.bind.host 127.0.0.1 绑定的主机,默认值为 127.0.0.1 hive.execution.engine mr 执行引擎,默认值为 mr

$HIVE_HOME/bin 目录下执行下面的命令可以启动 HiveServer2

hive.cmd --service hiveserver2

客户端需要引入 hadoop-commonhive-jdbc 依赖,依赖的版本尽量和对接的 HadoopHive 版本对应。

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>3.3.0</version>
</dependency>
<dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-jdbc</artifactId>
    <version>3.1.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    <version>2.3.5.RELEASE</version>
</dependency>

hadoop-common 依赖链比较长,会连带下载大量其他相关依赖,所以可以找个空闲时间在某个 Maven 项目先挂起该依赖下载的任务(笔者挂起此依赖下载任务洗完澡仍然没下完,还会出现 org.glassfish:javax.el 的快照包无法下载的问题,不过不影响正常使用)。最后添加一个单元测试类 HiveJdbcTest

@Slf4j
public class HiveJdbcTest {

    private static JdbcTemplate TEMPLATE;
    private static HikariDataSource DS;

    @BeforeClass
    public static void beforeClass() throws Exception {
        HikariConfig config = new HikariConfig();
        config.setDriverClassName("org.apache.hive.jdbc.HiveDriver");
        // 这里笔者修改过hive-site.xml的对应配置,因为端口不是默认的10000
//        config.setJdbcUrl("jdbc:hive2://127.0.0.1:10091");
        config.setJdbcUrl("jdbc:hive2://127.0.0.1:10091/db_test");
        DS = new HikariDataSource(config);
        TEMPLATE = new JdbcTemplate(DS);
    }

    @AfterClass
    public static void afterClass() throws Exception {
        DS.close();
    }

    @Test
    public void testCreateDb() throws Exception {
        TEMPLATE.execute("CREATE DATABASE db_test");
    }

    @Test
    public void testCreateTable() throws Exception {
        TEMPLATE.execute("CREATE TABLE IF NOT EXISTS t_student(id INT,name string,major string)");
        log.info("创建t_student表成功");
    }

    @Test
    public void testInsert() throws Exception {
        int update = TEMPLATE.update("INSERT INTO TABLE t_student(id,name,major) VALUES(?,?,?)", p -> {
            p.setInt(1, 10087);
            p.setString(2, "throwable");
            p.setString(3, "math");
        });
        log.info("写入t_student成功,更新记录数:{}", update);  // 这里比较神奇,数据写入了,返回的update数量为0
    }

    @Test
    public void testSelect() throws Exception {
        List<Student> result = TEMPLATE.query("SELECT * FROM t_student", rs -> {
            List<Student> list = new ArrayList<>();
            while (rs.next()) {
                Student student = new Student();
                student.setId(rs.getLong("id"));
                student.setName(rs.getString("name"));
                student.setMajor(rs.getString("major"));
                list.add(student);
            }
            return list;
        });
        // 打印日志:查询t_student成功,结果:[HiveJdbcTest.Student(id=10087, name=throwable, major=math)]
        log.info("查询t_student成功,结果:{}", result);
    }

    @Data
    private static class Student {

        private Long id;
        private String name;
        private String major;
    }
}

可能遇到的问题

下面小结一下可能遇到的问题。

Java虚拟机启动失败

目前定位到是 Hadoop 无法使用 JDK[9+ 的任意版本 JDK ,建议切换为任意 JDK8 的小版本。

出现找不到Hadoop执行文件异常

确保已经把 winutils 中的 hadoop-3.3.0\bin 目录下的 hadoop.dllwinutils.exe 文件拷贝到 Hadoop 的解压目录的 bin 文件夹中。

start-all.cmd 脚本执行时有可能出现找不到批处理脚本的异常。此问题在公司的开发机出现过,在家用的开发机没有重现,具体解决方案是在 start-all.cmd 脚本的首行加入 cd $HADOOP_HOME ,如 cd E:\LittleData\hadoop-3.3.0

无法访问localhost:50070

一般是因为 hdfs-site.xml 配置遗漏了 dfs.http.address 配置项,添加:

<property>
    <name>dfs.http.address</name>
    <value>0.0.0.0:50070</value>
</property>

然后调用 stop-all.cmd ,再调用 start-all.cmd 重启 Hadoop 即可。

Hive连接MySQL异常

注意 MySQL 的驱动包是否已经正确拷贝到 $HIVE_HOME/lib 下,并且检查 javax.jdo.option.ConnectionURL 等四个属性是否配置正确。如果都正确,注意是否 MySQL 的版本存在问题,或者服务的版本与驱动版本不匹配。

Hive找不到批处理文件

一般描述是 'xxx.cmd' is not recognized as an internal or external command... ,一般是 Hive 的命令执行时的异常,需要把 Hive 1.x 的源码包的 bin 目录下的所有 .cmd 脚本拷贝到 $HIVE_HOME/bin 对应的目录下。

文件夹权限问题

常见如 CreateSymbolicLink 异常,会导致 Hive 无法使用 INSERT 或者 LOAD 命令写入数据。出现这类问题可以通过下面方式解决:

  • Win + R 然后运行 gpedit.msc - 计算机设置 - Windows 设置 — 安全设置 - 本地策略 - 用户权限分配 - 创建符号链接 - 添加当前用户。

u26vUvi.jpg!mobile

或者 直接使用管理员账号或者管理员权限启动 CMD ,然后执行对应的脚本启动 Hadoop 或者 Hive

SessionNotRunning异常

启动 HiveServer2 中或者外部客户端连接 HiveServer2 时候有可能出现此异常,具体是 java.lang.ClassNotFoundException: org.apache.tez.dag.api.TezConfiguration 的异常。解决方案是:配置文件 hive-site.xml 中的 hive.execution.engine 属性值由 tez 修改为 mr ,然后重启 HiveServer2 即可。因为没有集成 tez ,重启后依然会报错,但是 60000 ms后会自动重试启动(一般重试后会启动成功):

RZB73qZ.jpg!mobile

这算是一个遗留问题,但是不影响客户端正常连接,只是启动时间会多了 60 秒。

HiveServer2端口冲突

修改配置文件 hive-site.xml 中的 hive.server2.thrift.port 属性值为未被占用的端口,重启 HiveServer2 即可。

数据节点安全模式异常

一般是出现 SafeModeException 异常,提示 Safe mode is ON 。通过命令 hdfs dfsadmin -safemode leave 解除安全模式即可。

AuthorizationException

常见的是 Hive 通过 JDBC 客户端连接 HiveServer2 服务时候会出现这个异常,具体是信息是: User: xxx is not allowed to impersonate anonymous 。这种情况只需要修改 Hadoop 的配置文件 core-site.xml ,添加:

<property>
    <name>hadoop.proxyuser.xxx.hosts</name>
    <value>*</value>
</property>
<property>
    <name>hadoop.proxyuser.xxx.groups</name>
    <value>*</value>
</property>

这里的xxx是指报错时候具体的系统用户名,例如笔者开发机的系统用户名为doge

然后重启 Hadoop 服务即可。

MapRedTask的权限问题

常见的是 Hive 通过 JDBC 客户端连接 HiveServer2 服务执行 INSERT 或者 LOAD 操作时候抛出的异常,一般描述是 Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask. Permission denied: user=anonymous, access=EXECUTE, inode="/tmp/hadoop-yarn":xxxx:supergroup:drwx------ 。通过命令 hdfs dfs -chmod -R 777 /tmp 赋予匿名用户 /tmp 目录的读写权限即可。

小结

没什么事最好还是直接在 Linux 或者 Unix 系统中搭建 HadoopHive 的开发环境比较合理, Windows 系统的文件路径和权限问题会导致很多意想不到的问题。本文参考了大量互联网资料和 HadoopHive 的入门书籍,这里就不一一贴出,站在巨人的肩膀上。

(本文完 c-4-d e-a-20201102)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK