大家好,我是明哥!
本片博文是 “基于 FTP 状态文件检测结果触发 JENKINS 数据同步作业” 系列文章的最后一篇,我们来看下 FTP 和本地文件系统的桥梁 - CurlFtpFS.
1 背景回顾
某客户现场,每天都会批量生成大量 CSV 文件存放到 FTP 系统,这些 CSV 文件需要导入到大数据平台 HIVE 数仓中做后续离线分析,且 HIVE 数仓中的离线分析作业目前是使用 JENKINS 来调度的。
由于这些 CSV 文件是每天都会生成,且文件数比较多数据量也比较大,初步计划使用 DATAX 来导入 FTP 上的 CSV 文件。
但在调度系统 JENKINS 中,如何检测 ftp 上的 csv 文件是否 ready,并及时触发 DATAX 导入作业,成为了一个问题。
为探索和验证 JENKINS 中 FTP 文件的检测和触发机制,笔者基于 vsftpd 搭建了 FTP 服务器,并通过 CurlFtpFS 挂载了远程 FTP 目录到本地文件系统。
本片文章是系列文章的最后一篇,介绍下 FTP 和本地文件系统的桥梁 - CurlFtpFS。关于 vsftpd 和 ftp 的 ACTIVE/PASSIVE 模式,请参见前期的博文:
michaelli:一篇文章了解开源 FTP 服务器 vsftpd
michaelli:一篇文章掌握彻底掌握 FTP 服务器的 ACTIVE 与 PASSIVE 工作模式
以下是正文。
2 curlftpfs 与 FUSE 简介
CurlFtpFS 是一个基于 libcurl 提供对远程 FTP 节点上文件系统的访问功能的用户态文件系统,可以让用户像访问本地文件系统一样去访问远程 ftp 节点的文件系统。
- CurlFtpFS is a filesystem for accessing FTP hosts based on FUSE and libcurl.
- It features SSL support, connecting through tunneling HTTP proxies, and automatically reconnecting if the server times out.
所谓 FUSE (Filesystem in Userspace),即用户态文件系统,是指完全在用户态而不是内核态实现的文件系统,其底层由 Linux 通过内核模块进行支持:
- FUSE 允许在不重新编译操作系统内核的前提下,在用户态提供一个自定义的文件系统实现;
- 最终用户态的应用程序,可以通过普通的 POSIX API, 读取 FUSE 文件系统中的文件;
- 允许非超级用户在用户空间开发文件系统,普通用户也可以挂载FUSE;
- 大致来说,FUSE 包含一个内核模块和一个用户空间 FUSE 服务进程,将应用对 VFS 的调用传递给这个用户空间 FUSE 服务程序来处理;
- 可以使用命令 fusermount 对 FUSE 文件系统进行挂载和卸载操作;(使用命令 man fusermount 查看说明)
- FUSE 的架构原理和工作机制如下图:
fuse-architecture
fuse
fuse主要由三部分组成:FUSE 内核模块、用户空间库 libfuse 以及挂载工具fusermount:
- fuse 内核模块:实现了和 VFS 的对接,实现了一个能被用户空间进程打开的设备,当VFS发来文件操作请求之后,将请求转化为特定格式,并通过设备传递给用户空间进程,用户空间进程在处理完请求后,将结果返回给fuse内核模块,内核模块再将其还原为Linux kernel需要的格式,并返回给VFS;
- fuse 库libfuse:负责和内核空间通信,接收来自/dev/fuse 的请求,并将其转化为一系列的函数调用,将结果写回到/dev/fuse;提供的函数可以对fuse文件系统进行挂载卸载、从linux内核读取请求以及发送响应到内核。libfuse提供了两个APIs:一个“high-level”同步API 和一个“low-level” 异步API 。这两种API 都从内核接收请求传递到主程序(fuse_main函数),主程序使用相应的回调函数进行处理。当使用high-level API时,回调函数使用文件名(file names)和路径(paths)工作,而不是索引节点inodes,回调函数返回时也就是一个请求处理的完成。使用low-level API 时,回调函数必须使用索引节点inode工作,响应发送必须显示的使用一套单独的API函数;
- 挂载工具:实现对用户态文件系统的挂载;
现在很多文件系统,出于易用性等各种考量因素,都提供了 FUSE 的使用方式,比如云原生分布式文件系统 JuiceFS,和云原生数据编排框架/基于内存的分布式文件系统 Alluxio,都不约而同提供了 FUSE 服务:
- 通过 FUSE,JuiceFS 文件系统能够以 POSIX 兼容的方式挂载到服务器,将海量云端存储直接当做本地存储来使用;
- Alluxio FUSE 服务通过提供 Unix/Linux 下的标准 POSIX 文件系统接口,让应用程序(比如Tensorflow,PyTorch等)在不修改代码的前提下,以访问本地文件系统的方式访问 Alluxio分布式文件系统中的数据;
- Alluxio 和 JuiceFS, 都是数字化转型大背景下,笔者比较看好也比较关注的两个云原生分布式文件系统;
alluxio-fuse
juicefs-fuse
3 curlftpfs 的安装
- 由于 Linux 操作系统的 epel 源中自带了curlftpfs,所以安装很方便:yum install curlftpfs;
- curlftpfs 不是系统常驻服务,不用通过 systemctl 进行启停管理;
4 临时挂载远程 FTP 目录到本地文件系统
可以使用命令 curlftpfs,临时挂载远程 ftp 目录到本地文件系统:
- sudo curlftpfs ftp://3.22.42.20:21 /tmp/ftp1 -o user=awsftpuser:awsftpuser,rw,allow_other
- sudo curlftpfs ftp://awsftpuser:awsftpuser@3.22.42.20:21 /tmp/ftp2 -o rw,allow_other
- sudo curlftpfs 3.22.42.20:21 /tmp/ftp11 -o user=awsftpuser:awsftpuser,allow_other,no_verify_peer,no_verify_hostname
- sudo curlftpfs awsftpuser:awsftpuser@3.22.42.20:21 /tmp/ftp21 -o allow_other
- curlftpfs 命令有大量参数,需要注意比较重要的参数 allow_other,allow_root, user=user:password 等
- 更多关于命令 curlftpfs 的详情,请 man curlftpfs;
5 永久挂载远程 FTP 目录到本地文件系统
使用命令 curlftpfs 挂载的 FTP 目录,在服务器重启后就失效了,如果要实现永久挂载,需要更改文件 /etc/fstab,添加以下条目:
- curlftpfs#awsftpuser:awsftpuser@3.22.42.20:21 /tmp/ftp3 fuse auto,user,uid=1000,allow_other,_netdev 0 0
- curlftpfs#3.22.42.20:21 /tmp/ftp31 fuse user=awsftpuser:awsftpuser,auto,user,uid=1000,allow_other,_netdev 0 0
- curlftpfs#ftp://3.22.42.20:21 /tmp/ftp32 fuse user=awsftpuser:awsftpuser,auto,user,uid=1000,allow_other,_netdev 0 0
- curlftpfs#ftp://3.22.42.20:21 /tmp/ftp33 fuse user=awsftpuser:awsftpuser,auto,user,uid=1000,allow_other,_netdev 0 0
- 以上各个参数的含义,跟命令 curlftpfs 的参数一致;
6 最终方案思路概述
“基于 FTP 状态文件检测结果触发 JENKINS 数据同步作业”的最终方案,思路概括如下:
- 首先通过 CurlFtpFS 将远程 FTP 特定目录映射到本地文件系统;
- 然后使用 jenkins 的插件 FSTrigger 来监控映射到本地文件系统的状态文件,当监控到状态文件 READY 时,触发数据同步作业;
- 也可以在 jenkins 中编写 groovy 脚本代码来监控映射到本地文件系统的状态文件,当监控到状态文件 READY 时,触发数据同步作业;
- 数据同步作业,可以直接使用 hive load 命令,来加载映射到本地文件系统的 csv 数据文件到 HIVE 中;(前提:CurlFtpFS 节点需要安装 HIVE 客户端);
- 当 curlftpfs 挂载到本地的远程 ftp 文件数量众多且数据量大时,如果 HIVE LOAD 直接同步数据的方式不稳定或效率不高,可以结合使用 datax 直接导入远程 ftp 数据文件到 HIVE 中;