Table of Contents generated with DocToc
Ufop 完全操作指南
====
Ufop 的全称是 User-defined File OPeration
顾名思义,Ufop 是用户自定义的一种计算方式,当七牛暨有的 fop 功能不能满足用户对文件资源的操作时,可以将自定义的计算能力通过 ufop 的方式体现出来。用户自定义的 ufop 使用方式和七牛暨有 fop 的方式完全一致,因此用户添加到 Ufop 的功能能够无缝地融合到七牛的 fop 功能中。所以和七牛现有的 fop 一样,Ufop 也支持管道处理、持久化、预处理操作等所有特性。
对于文件处理,您当然也可自行将文件下载下来后进行处理,但如果使用 Ufop,那么可以将您的计算搬移至离您数据最近的地方,以最优的访问速度和最短的时间得到处理结果。
数据处理是 Ufop 的核心功能和价值,因此,每个 Ufop 需要做的事情非常简单,即专注数据处理本身:
- 获取输入数据
- 处理输入数据
- 输出处理结果
正是基于如此简单的单元结构,七牛才能使用特有的管道机制自由地将多个 fop/Ufop 的输入和输出像搭积木一样串起来,获得多样化、个性化的数据处理结果。
制作一个完整可用的 ufop,只需以下几步:
1. 注册一个有效可用的 ufop 名。
2. 通过工具上传符合规格(具体规格见下描述)的程序包。
3. 设置 ufop 的运行实例(实例将会自动启动运行)。
以上步骤所需要的唯一工具:qufopctl
当一个 Ufop 启动运行时,会根据您提供的程序包启动您的程序。
qufopctl 的注册规格为:
qufopctl reg <Ufop> -mode <AclMode> -desc <Desc>
其中:
<Ufop>
: 填写需要注册的 ufop 名称<AclMode>
:设置该 ufop 的访问权限:0 - 完全公开,1 - 半公开,2 - 私有<Desc>
:可选,对该 ufop 的描述文字
注意:当前普通用户只允许申请 AclMode 为 1 或者 2 的 ufop。
Ufop 的命名是全局的,和七牛暨有的 fop 处于相同的名字空间。因此,用户当前无法注册:
1. 七牛暨有的 fop 名
2. 其他用户已经注册的 ufop 名
命名规则:
1. UTF-8 编码
2. 长度限制:[5, 20]
3. 必须由 小写字母、数字、减号、下划线 中的一种或多种类型的字符组合而成
ufop 的拥有者可以选择设置某 Ufop 的权限为 完全公开、半公开、私有:
1. 完全公开的 Ufop:可以被任意其他用户的资源访问,所有用户默认都能够使用。例如 七牛官方公开的 Ufop。
2. 半公开的 Ufop:其他用户默认不可访问,但均可主动添加该 Ufop 到自己的可访问 Ufop 列表中。
3. 私有的 Ufop:其他用户无权使用和访问,只有 Ufop 的属主的资源能够使用。
这里以注册一个名为 grepd、权限为半公开 的 Ufop 为例:
qufopctl reg grepd -mode 1 -desc "demo ufop"
Ufop 注册成功后,您还需要提供一个由二进制服务程序和一个编译脚本形成的程序包。
一个符合规格的服务程序只需满足以下条件:
1. 可运行
2. 启动后监听 9100 端口
3. 接受 HTTP POST 请求
服务程序处理数据的工作流为:
1. 从接收到的 HTTP POST 请求中获取 待处理文件的信息(json 信息) 和 参数信息
2. 从 json 信息中获取到待处理文件的地址,通过 HTTP GET 方法获取文件
3. 根据自定义的方式处理数据
4. 将处理结果以 HTTP Response 的方式返回
您的处理程序所获取到的 json 信息规格如下:
POST /uop HTTP/1.1
Content-Type: application/json
{
"cmd": "<ufop>/<param>",
"src": {
"url": "http://<host>:<port>/<path>",
"mimetype": "<mimetype>",
"fsize": <filesize>,
"bucket": <bucket>,
"key": <key>
}
}
其中:
/uop
:固定的请求规格,您的服务程序可以选择识别或者忽略。cmd
:固定的 QueryString,外部访问时使用的 Ufop 指令(包括参数)会被原样的传入。<ufop>
:cmd 指令的一部分,通常为 Ufop 名称。<param>
:如果您的服务程序需要外部通过参数调整处理方式,那么可以将参数信息放在这里。<url>
:通过该 url 可以获取到待处理的数据,其可能是被访问的资源本身,也可能是前一个 fop 或 Ufop 处理后的输出内容(使用管道)。<mimetype>
:待处理文件的数据类型。<fsize>
:待处理文件的文件大小,以字节为单位。<bucket>
:资源所在的bucket的唯一标识ID(不是bucket name<key>
:资源的key文件名,会剥离文件路径,如 key 为a/b/c.txt
结果就是c.txt
以上面创建的 grepd 这个 Ufop 为例,其接收到的数据规格可能会是这样的:
POST /uop HTTP/1.1
Content-Type: application/json
{
"cmd": "grepd/test-param",
"src": {
"url": "http://123.123.123.123:12345/get/UfHUjifdaJi==",
"mimetype": "text/plain",
"fsize": 129302,
"bucket": bucketname,
"key": keyname
}
}
那么 grepd 只需通过请求 "http://123.123.123.123:12345/get/UfHUjifdaJi==" 这个地址即能获取到待处理的原始文件。
除此之外,还需要提供一个名为ufop.yaml
的 配置文件,用来提供基础镜像,编译,运行等信息。规则如下
image: <base_image>
build_script:
- <command1>
- <command2>
- <command3>
- ...
run: <run_command>
image
: 创建镜像时的基础镜像,ubuntu
或者以前创建好的一个镜像加版本,如test.v7
build_script
: 创建镜像时的脚本,在这里进行安装环境等操作run
: 运行程序的启动命令,对应的服务需要监听9100端口$RESOURCE
: 资源存放目录,其中的资源需要移动到当前目录或者其他需要的路径下,这个目录在运行时不会保留,$PWD
: 当前目录也是以后的的工作目录
NOTE:
- 创建镜像时有sudo权限,运行时只有普通用户权限
假设您有一个简单的字符处理服务 grepd,grepd 在启动后,会监听 9100 端口,其功能是负责从待处理的文件中过滤出特定的字符串并输出。
下面将以 grepd 为例,演示下如何制作一个合格的程序包(注意:除了 ufop.yaml 文件外,其余文件的路径组织方式无需和示例一模一样)。
假设在您本地的工作目录下,相关文件按如下结构组织:
.
├── ufop.yaml
└── dir
├── grepd
└── grepd.conf
其中 grepd.conf 为 grepd 的配置文件。
其中 ufop.yaml 为启动 grepd 的配置文件,其内容如下:
image: ubuntu
build_script:
- echo building...
- mv $RESOURCE/dir/* .
run: ./grepd -f grepd.conf
那么按照如下执行命令,将会创建出一个新版本的ufop:
qufopctl build grepd
执行完build操作后,需要查看镜像信息,以确定编译结果以及已有的版本
qufopctl imageinfo grepd
编译过程中可能出错,这时候需要查看这个版本的编译日志
qufopctl buildlog grepd -v 1
得到最新的ufop版本后,可以把当前版本切换到最新版本(build成功不会自动切换到最新版本)
qufopctl ufopver grepd -c 1
在完成绑定的动作后,由于还没有实例运行,因此Ufop 还未处于未启动状态,下面通过 qufopctl 工具添加 Ufop 运行实例并启动 Ufop:
qufopctl 的实例调整功能,规格如下:
qufopctl resize <Ufop> -num <Instance-Limit>
其中:
<Ufop>
:需要调整实例数的 Ufop 名<Instance-Limit>
:需要调整成的目标实例数
以设置 grepd 的运行实例为例:
qufopctl resize grepd -num 1
这将启动一个 grepd 的运行实例。
使用 qufopctl 工具,可以单独管理某个实例的运行状态,也可以查看某个实例运行的标准输出和错误输出信息。
关闭功能的规格为:
qufopctl stop <Ufop> [-index <Index> | -range <IndexStart:IndexEnd>]
其中:
<Ufop>
:Ufop 名称<Index>
:可选,需要停止的单个实例序号<IndexStart>
:可选,批量操作的起始实例序号<IndexEnd>
:可选,批量操作的终止实例序号
参数说明:
- 实例序号,是指从 1 开始计数的数字。例如如果一个 Ufop 的实例个数为 5 个,那么有效的实例序号区间为:[1,5]。
- 如果不指定 ,也不指定 和 ,那么默认针对所有当前存在的实例进行操作。
使用范例:
以 grepd 这个 ufop 为例,若需要操作第 1 个实例的运行,那么执行:
qufopctl stop grepd -index 1
若需要批量操作从 1 - 5 的实例,那么指定:
qufopctl stop grepd -range 1:5
若需要操作 grepd 的所有实例,那么执行:
qufopctl stop grepd
既可。
注意:下面的 start
和 state
子命令的参数使用方法与此相同。
关闭功能的规格为:
qufopctl start <Ufop> [-index <Index> | -range <IndexStart:IndexEnd>]
其中:
<Ufop>
:Ufop 名称<Index>
:需要启动的单个实例序号<IndexStart>
:批量操作的起始实例序号<IndexEnd>
:批量操作的终止实例序号
状态查看功能的规格为:
qufopctl state <Ufop> [-index <Index> | -range <IndexStart:IndexEnd>]
其中:
<Ufop>
:Ufop 名称<Index>
:需要查看的的单个实例序号<IndexStart>
:批量操作的起始实例序号<IndexEnd>
:批量操作的终止实例序号
使用 qufopctl 可以获得指定实例的运行输出,规格为:
qufopctl logtail <Ufop> -index <Index> [-type <stdout|stderr>] [-tail <RowNum>]
其中:
<Ufop>
:必填,Ufop 名称<Index>
:必填,需要查看输出的实例序号<stdout|stderr>
:选填,选择输出标准输出还是错误输出,默认是 stdout<RowNum>
:选填,选择 tail 输出的行数,默认输出最后 100 行
以 grepd 为例,若需要获得序号为 1 的实例的标准输出的最后 200 行:
qufopctl logtail grepd -index 1 -type stdout -tail 200
注意: 获取的输出信息中,每行开头默认会有自动添加的时间戳。
qufopctl info <Ufop>
其中:
<Ufop>
:必填,Ufop 名称
输出示例:
Ufop name: grepd
Owner: 1366779853
Version: 1
Access mode: PUBLIC
Description: demo ufop
Create time: 2014-11-05 18:49:33 +0800 CST
Instance num: 1
Max instanceNum: 5
Flavor: default
Access list: 1366779853
无需参数,执行以下命令既可:
qufopctl list
注意:该命令显示的 Ufop 列表中可能包含两种 Ufop,一种是属主为您自己的 Ufop,另一种是您有权访问的 Ufop(但您对其没有管理权限)。
至此,您已经完成了 Ufop 的制作和启动,现在可以按以下的方式从外部访问您的 Ufop,这里以 grepd 为例:
直接访问方式:
http://demo.qiniudn.com/demo.txt?grepd/<text-to-grep>
使用管道的方式访问(这里以 exif 的输出作为 grepd 的输入):
http://demo.qiniudn.com/demo.jpg?exif|grepd/<text-to-grep>
当然,如果使用管道,您可以在七牛的 fop 和您有权访问的所有 ufop 之间自由地组合搭配,得到您想要的处理结果。
您的程序将默认运行在 Ubuntu 14.04.1 LTS 的操作系统上。
由于使用了内核级别的资源隔离和访问控制,您无需担心您的运行实例及其相关数据会被相同物理主机上的其他实例非法访问到。
一个理想的 ufop 的程序实例应当是无状态的,因为一个实例在被重启后会丢失前一次启动的运行数据(包括持久化数据)。