这是一个巨大的坑,网上对这块的完整描述真的很少,新手真的会很迷茫!!!
插件
选择插件
reader插件选择:ftpread
write插件选择:hdfswrite
参数配置
reader参数
"parameter": {
//选择要导入的列所有用*,如果要指定{"index":0,"type":"string"}
"column": [
"*"
],
//编码格式
"encoding": "UTF-8",
//分隔符
"fieldDelimiter": "\t",
//ftp服务器ip
"host": "172.XXX.XXX.XXX",
//ftp连接用户、密码
"username": "ftp"
"password": "***",
//ftp导入文件目录(坑1)
"path": [
"/upload/tmp2.csv"
],
//ftp连接port
"port": 21,
//ftp连接协议
"protocol": "ftp",
//是否跳过首行
"skipHeader": true,
}
write参数
"parameter":{
//导入的列名
"column": [
{
"name": "id",
"type": "STRING"
},
{
"name": "name",
"type": "STRING"
},
{
"name": "address",
"type": "STRING"
}
],
//压缩类型
"compress": "",
//hdfs连接
"defaultFS": "hdfs://172.XXX.XXX.XXX:XXXX",
//分隔符
"fieldDelimiter": "\u0001",
//表名
"fileName": "ftp_test_001",
//数据文件格式
"fileType": "text",
"nullFormat": "\\N",
//数据文件地址
"path": "/user/hive/warehouse/ftp.db/ftp_test_001",
//写入模式
"writeMode": "append"
}
遇到的问题
坑1 不知道ftp的path要填什么
刚搭建完ftp,还不知道怎么用,所以这个地方完全无从下手。
只能通过windows的命令窗连接一下ftp,尝试使用功能增加了解
使用ls命令发现下面的目录和linux的”/var/ftp“下的目录是一样的
linux:
同时根据官网的描述,推测这里的path写的就是从ftp之后开始算起
所以我上面配置的是”/upload/tmp2.csv“(为什么是upload后面再讲)
坑2 执行datax任务,一直报错NullPointerException
这里简直是神坑!完全不知道为什么,只能一点一点展开排查。
首先排查是否有必填字段没写。(这点可以从官网看)我这里是吧必填的都写了。
然后还是找不到原因,只能打开源码,看一下出错的地方。
找到了大致的报错点如图
所以就推测是不是inputStream是null所以报了空指针的异常。
于是写了一个简单的用Java连接ftp获取文件的demo,发现果然传”/pub/tmp2.csv“会返回null。
于是通过windows的命令窗get 一下这个tmp2.csv,发现报错
基本问题已经锁定了,就是这里获取不到文件。
获取不到文件的原因一般就是两个
1. 路径没配对
2. 权限问题
基于上面的推测1不太可能了,只有可能是权限的问题。
然后网上找了很多关于ftp权限的帖子
1.
解决方法:setsebool -P ftpd_disable_trans 1service vsftpd restart
但是试过了不行。
2.
修改
ftpusers、user_list等文件
依然不行
3. 最后
看到了这样的一个帖子,他解决的是无法上传,我是无法下载,我觉得问题很像,他的修改内容主要是
1.ftp目录权限:
查看ftp目录:
cat /etc/passwd | grep ftp
ftp:x:107:65534::/var/ftp:/bin/false
ftp目录为/var/ftp
chown root:root /var/ftp
chmod -R 777 /var/ftp
但这样是不能上传文件的。因为这是匿名用户,当前目录所有者是root用户; 真的要上传文件在该目录下建立一个文件夹如名字是upload,
mkdir /var/ftp/upload
chown ftp:root /var/ftp/upload
于是就创建了一个新的upload目录(这就是为什么我得脚本用的是‘/upload/tmp2.csv’),然后修改了这个目录的权限给ftp用户。
然后我在命令窗里执行了一下get命令
于是终于不报空指针了,我马上去运行datax脚本,开始报新的错误!
居然连接不上了,我赶紧重新命令框连接,连接失败。
别看他连接失败了,但感觉要好起来了。于是开始解决这个连接不上了的问题。
坑3 ftp 500 OOPS: vsftpd: refusing to run with writable root inside chroot()
这个问题看起来还是权限的问题,根据网上的帖子修改了vsftpd.conf文件
chroot_local_user=YES
allow_writeable_chroot=YES
但依然不行。
网上很多是这样说的,这时我注意到了标红的地方
从2.3.5之后,vsftpd增强了安全检查,如果用户被限定在了其主目录下,则该用户的主目录不能再具有写权限了!如果检查发现还有写权限,就会报该错误。
要修复这个错误,可以用命令chmod a-w /home/user去除用户主目录的写权限,注意把目录替换成你自己的。或者你可以在vsftpd的配置文件中增加下列两项中的一项:
这时候想起了坑2中把/var/ftp的权限改成了777,推测可能是这个原因,于是就改成755
chmod -R 755 /var/ftp
于是再次尝试连接,成功啦!撒花!
运行一下datax任务,也执行成功啦!
总结
解决这个问题正常的步骤(有些可能是多余配置,成功后我就没仔细的验证每个配置对本次修改的影响范围)
1. 修改ftp文件目录的权限
chmod -R 755 /var/ftp
2. 修改vsftpd.conf
chroot_local_user=YES
allow_writeable_chroot=YES3. 创建新的目录,将目录权限给你连接ftp的用户
mkdir /var/ftp/upload
chown ftp:root /var/ftp/upload
(
setsebool -P ftpd_disable_trans 1service vsftpd restart这个我也改了,但是我感觉和他没啥关系,1、2、3执行不行的话也改一下这个吧)
4. 重启服务,改完这些配置都需要重启的
systemctl restart vsftpd.service
接下来我要研究这两个插件的参数具体可以控制什么细节了,以上只能让任务跑通。
最后附上我得vsftpd.conf以及datax的任务json
vsftpd.conf
anonymous_enable=YES
local_enable=YES
write_enable=YES
allow_writeable_chroot=YES
local_umask=022
anon_umask=022
allow_ftpd_full_access
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_std_format=YES
chroot_local_user=YES
listen=NO
listen_ipv6=YES
pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES
datax.json
{
"job": {
"content": [
{
"reader": {
"name": "ftpreader",
"parameter": {
"host": "172.XXX.XXX.XXX",
"port": 21,
"username": "ftp",
"password": "123",
"protocol": "ftp",
"path": [
"/upload/tmp2.csv"
],
"fieldDelimiter": "\t",
"encoding": "UTF-8",
"column": [
"*"
],
"skipHeader": true
}
},
"writer": {
"name": "hdfswriter",
"parameter": {
"defaultFS": "hdfs://172.XXX.XXX.XXX:8020",
"writeMode": "append",
"fieldDelimiter": "\u0001",
"fileType": "text",
"compress": "",
"path": "/user/hive/warehouse/ftp.db/ftp_test_001",
"fileName": "ftp_test_001",
"nullFormat": "\\N",
"column": [
{
"name": "id",
"type": "STRING"
},
{
"name": "name",
"type": "STRING"
},
{
"name": "address",
"type": "STRING"
}
]
}
}
}
],
"setting": {
"speed": {
"channel": 1
}
}
}
}