TFS Nginx模块实现
– 生命周期:请求
• 共享内存
– 生命周期:nginx进程
16/26
接收buf
• Header buffer(共用) • 每个连接有各自的body buffer • 处理buf overflow情况
ngx_http_tfs_t
recv_chain header_buffer
ngx_chain_t
buf next
• BatchGetBlockInfo
21/26
原生大文件(cont)
写 读
删 Stat
• 数据分片:根据数据长度计算好分片个数 • 元分片:数据全部写成功之后生成 • 元分片:读到内存一个临时的buf中 • 数据分片:根据offset和size找到需要的分片 • 元分片:读到内存一个临时的buf中 • 数据分片:和元分片一块删除
• 操作解析
– 方法:GET/POST/PUT/DELETE/HEAD – 参数
• 举例
– curl --data-binary @file_to_up 10.232.35.41:3900/v1/tfscom
11/26
TFS交互模块
• 状态机 • 连接的读写事件
– ngx_http_tfs_read_handler – ngx_http_tfs_send_handler
JSON输出模块
排重
8/26
通用模块部分
• 配置文件指令解析
– 3个配置数据结构 • main_conf • srv_conf • loc_conf – 生命周期和nginx进程周期相同
• 设置Handler(请求入口)
– ngx_http_tfs_handler
• 初始化timer(用于rc-keep-alive)
• server
#server 配置块
– tfs_keepalive max_cached=100 bucket_count=10; #连接池大小 – tfs_tackle_log “pipe:/usr/sbin/cronolog -p 30min /home/mingyan.zc/ngx_bin/logs/cronolog/%Y/%m/%Y-%m-%d-%H-%Mtfs_access.log"; #配置tfs访问日志 – tfs_net_device bond0; #配置使用的网卡(获取本地地址用于rc登录)
• 使用json输出模块 • ls_dir要处理buf overflow
自动创建父 目录
• 无法使用递归 • 利用ngx_str_t结构的特性, 使用一个长度数组
25/26
排重
• 使用ngx_tair模块 • 动态创建tair实例
– 在main_conf中使用一个固定大小的数组,保存 • tair实例指针 • tair地址的哈希 – 每个逻辑集群有自己的tair实例 – 只初始化一次 – tair地址改变或进程退出时销毁tair实例
9/26
Handler
• 分配关键数据结构ngx_http_tfs_t
– 从请求的pool中分配的 – 生命周期和请求的生命周期相同 • RESTful解析 – 解析URI – 解析操作
• 对请求进行处理
– 特殊请求:写文件请求(带body)
10/26
RESTful解析
• URI解析
– 协议版本 • v1:原生TFS • v2:自定义文件名 – appkey – 关键词和文件名
CREATE_REQUEST INPUT_FILTER(可选) PROCESS_REQUEST_BODY FINALIZE_REQUEST(可选)
RETRY_HANDLER (可选)
typedef ngx_int_t (*tfs_peer_handler_pt)(ngx_http_tfs_t *t);
• 内存管理
– pool中分配,无需显式释放
• 发送/接收buf
12/26
状态机
读原生TFS文件 自定义文件名目录操作
START GET_META_TABLE
START GET_META_TABLE PROCESS DONE
GET_BLK_INFO
READ_DATA DONE
13/26
状态处理流程
– 指定content_type => "application/json“
28/26
Thank You!
29
写 读
• 重用大文件的过程 • 每写成功一批分片,保存元数据到meta server
• 重用大文件的过程(反复从ms读分片信息) • 空洞:将一个zero_buf反复挂到输出链
删
• 重用大文件的过程(反复从ms读分片信息) • 挨个删除分片,再删除ms上的元数据
24/26
自定义文件名——其他
ls_dir/ls_file
• location /
#根location配置块
#是否启用tfs模块
5
– tfs_pass enable=1;
编译运行
• 编译
– ./configure --add-module=/home/path/to/mod_tair/tair_2/ -add-module=/home/path/to/mod_tfs -prefix=/home/path/to/ngx_bin/ --with-debug
14/26
连接读写事件
• 写事件
– 连接tfs server( ngx_event_connect_peer ) – 发送tfs请求
• 读事件
– 接收tfs应答
15/26
内存管理
• 配置数据结构
– main_conf/srv_conf/loc_conf – 生命周期:nginx进程
• 从pool中分配
ngx_chain_t
buf next
ngx_http_tfs_peer_connection_t
tfs_peer peer body_buffer pool
17/26
连接池模块
• 维护到tfs的server之间的长连接 • 根据ip地址计算hash • 两个hash链表
– cache – free
• 使用readV2协议将元分片的头读出来
22/26
自定义文件名
• 重用原生文件的各个过程
– 区分:URI中的协议版本号(v2)
• 增加目录操作的过程 • Meta table
– 保存在配置文件的loc_conf结构中 – 更新:首次/root server更改/操作返回版本错误时
23/26
自定义文件名——文件
27/26
JSON输出模块
• 依赖yajl库 • ngx_http_tfs_json_init • ngx_http_tfs_json_xxx
– 对要返回的内容进行json封装 – 返回一个ngx_chain_t结构指针(会被链在ngx_http_tfs_t 的out_bufs的末尾)
• 返回json格式的应答
– 固定大小
• 数据结构
– 红黑树
• 内存分配/释放
– ngx_slab_alloc/ngx_lab_free_locked
• 我们需要实现
– 选择红黑树的key – 查找/插入/淘汰
20/26
原生大文件
• 重用小文件的各个过程
– 区分:大文件标记 • 参数显式指定(写) • 数据超过指定大小(15MB)(写) • 文件名(L)(读/删/stat)
• 所有的tair操作(PUT/GET/DELETE)也都是异步 的
26/26
rc keep-alive
• 利用nginx的定时事件
– module初始化时创建一个在worker process之间互斥的 变量 – worker process初始化时添加定时事件
• 在事件超时时模拟请求处理过程
– 遍历共享内存中的rc节点 – 记录当前keep-alive的节点在队列中的位置 – 处理完毕再添加一个定时事件
Nginx-tfs实现
2012.8.10 明俨
1
Agenda
• The Big Picture • 配置和使用 • 内部实现
2
The Big Picture
DownStream UpStream
CLIENT
• • • • • POST GET PUT DELETE HEAD
Nginx
• tengine • ngx_mod_tfs • ngx_mod_tair
TFS
• • • • • rc server name server data server root server meta server
3/26
配置和使用
4
配置文件
• http
– – – –
– – – –
#http 配置块
tfs_upstream 10.232.36.203:6100; #rc_server 地址 tfs_rc_zone size=128M; #rc所使用共享内存大小 tfs_block_cache_zone size=256M; #本地block cache所使用共享内存大小 tfs_poll_rcs lock_file=/home/xxx/nginx/logs/lk.file interval=10s timeout=3s enable=1; #rc keep-alive 使用的锁文件,时间间隔,超时时间,启用否 tfs_send_timeout 3s; #向tfs server发送数据超时时间 tfs_connect_timeout 3s; #连接tfs server超时时间 tfs_read_timeout 3s; #从tfs server读数据超时时间 tair_timeout 1s; #tair超时时间(连接/发送/接收数据)