模块设计
模块组成
Nginx Web模块
Shell脚本模块
最终形体
Openresty(Nginx+lua扩展+lua_upload库) + Shell(OS+HDFS+Hive+Impala)
设计思想
Nginx Web模块
采用 封装 lua 语言扩展完善的 Openresty 自带 upload 库
Openresty 部署方式为 Docker 快速部署
带来的问题: Docker 容器封装导致的 Shell 仅能调用 Docker 内服务 --> 无法调用 宿主机 Linux 部署的相关服务
解决办法 -> 将原属于 连带 调用的 Shell 脚本 进行拆离 -> 宿主机 Linux Crontab 定时调用 Shell 脚本
Web服务形式
API: http://IP/hdfs_upload? 【default 未配置 域名/特殊端口 拦截】
URI参数: tenant=&dbtable=&dt=&isclean= 【非必要参数 isclean, dt 支持 多个日期使用','分隔, 支持 tenant/dataone_tenant 自动切换顺带切换dt】
POST参数: -F "file=@/Path/to/file"
为什么既用 Get URI 又用 POST 为什么不直接 Post 传参即可?
问题: -F 文件内容过大 占据 Body,而 Post 参数也在 Body 存储传输 导致 ngx.req.get_post_args() 无法解析
解决办法: 使用 URI 参数 通过 ngx.req.get_uri_args() 进行解析
参数校验
tenant: >0 <1000 数值
dbtable: db只能为字母开头+'_'混合组成 db与table之间必须有'.' table由字母+数字+'_'组成 '.'之后必须以字母起头
dt: 数值 8位 或者 非数值'ACTIVE'
isclean: 非必要参数 只校验是否等于 "true" 其余输入默认 "false"
OS
创建 /tmp/upload/pending/ 下目录
目录名组成: tenant=?+dbtable=?+dt=?+isclean=?+20位随机数
以文件流形式写入创建的目录下
创建 上传的同名文件
上传结束标志文件 位于同级目录下
创建 _success 文件
Shell脚本模块
查询同名进程,如果存在则不执行,不存在则执行本次Shell脚本
扫描 /tmp/upload/pending 目录 所有文件目录
如果扫描到 文件 且 同级目录下 存在 _success 文件 则执行 数仓操作
判断 文件 / ZIP [ZIP 解压 并 定死 数仓操作目标为 ZIP 文件内容]
HDFS 创建目录
HDFS 文件上传
Hive 建立分区
如果 路径中的tenant 类似 d999 则使用 dataone_tenant + dataone_dt
否则 使用 tenant dt
Impala 刷新目标表
环境命令
Docker重启
docker exec -it cdp_nginx nginx -s reload
Error日志
tail -f /var/log/nginx/error.log
Nginx日志
vim /nginx/conf.d/default.conf
实现细节
Nginx 配置文件
location ^~ /hdfs_upload {
content_by_lua_file /app/hdfs_upload.lua; # Docker 挂载目录 实际目录位于其他位置
lua_code_cache on; # 测试时设置为 off
lua_need_request_body off; # 如果 on 则导致 file stream 读取失败
client_max_body_size 1024m; # 文件内容过大导致 拒绝请求 client_body_buffer_size 128k
}
URI 配置
/hdfs_upload?tenant=${tenant}|?dataone_tenant=${dataone_tenant}&dt=${dt}&dbtable=${db.table}&isclean=${clean}
POST 配置
-F "file=@/home/xxx/hdfs_load.sh" -X POST
CURL 请求示例
curl -F "file=@/home/xxx/hdfs_load.sh" -X POST "http://xx.xxx.x.xxx/hdfs_upload?tenant=999&dbtable=db.table&dt=20200724,ACTIVE&isclean=true"
注意[涵盖未实现]
1.使用 dataone_tenant 作为参数传递,在创建分区时 dt 自动转为 dataone_dt
2.上传的文件名 及 ZIP压缩包内文件名 禁止出现空格,如 " - 副本.csv"
3.dt 支持多日期,以","隔开,如"dt=20200727,ACTIVE",不识别小写 active
4.同一时刻只存在一个 sh hdfs_load.sh 进程 即不并行处理 /tmp/upload/pending 待处理文件
5.未对Spark新建表进行 Impala 元数据同步 "invalidate metadata db.table;",只 refresh table 报错无效 Impala不可见
6.待优化 创建分区+刷新表 单个文件执行 -> 攒批处理
参考资源
level 1 [实现参考主体]
Openresty文件上传upload
http://moguhu.com/article/detail?articleId=19
Openresty官方upload test示例 [建议先完整实现一遍 Synopsis 以这个为基础糅合其他参考]
https://github.com/openresty/lua-resty-upload
level 2 [有效解决方案]
post请求体过大导致ngx.req.get_post_args()取不到参数体的问题
https://www.cnblogs.com/wangzhisdu/p/7771310.html
level 3 [部分参考]
Nginx + Lua搭建文件上传下载服务
https://cloud.tencent.com/developer/article/1004880
level 4 [感觉有用但没用到的]
Openresty 最佳实践 [有时间可以详勘 -- 调研]
https://moonbingbing.gitbooks.io/openresty-best-practices/content/
lua 使用中遇到的坑总结
https://www.cnblogs.com/zhuzi91/p/8392385.html
lua-resty-upload模块实现图片上传
https://github.com/shixinke/openresty-practices/blob/master/upload/upload.lua
Nginx与Lua: 使用Nginx的upload模块打造文件上传服务
https://cyrusin.github.io/2015/10/13/lua-20151013/
使用openresty的lua-resty-upload实现文件上传 [带Github]
http://www.shixinke.com/openresty/openresty-upload-file
level 5 [Docker]
openresty/openresty
https://hub.docker.com/r/openresty/openresty/dockerfile
使用 OpenResty Docker 镜像快速搭建 Web 服务器
https://www.jianshu.com/p/6e15a4b3d838
Docker下的OpenResty三部曲之一:极速体验
https://blog.csdn.net/boling_cavalry/article/details/79290944
Docker下的OpenResty三部曲之二:细说开发
https://blog.csdn.net/boling_cavalry/article/details/79292356
level 0 [基础知识]
玩转 Nginx 之:使用 Lua 扩展 Nginx 功能
https://my.oschina.net/leejun2005/blog/494248
Nginx与Lua
https://blog.huoding.com/2012/08/31/156
【Nginx 归档整理】Openresty 实现数据文件上传数仓网关 2020.7.28
最新推荐文章于 2022-08-16 11:29:50 发布