Skip to content

Instantly share code, notes, and snippets.

@lintianzhi
Last active January 21, 2016 03:55
Show Gist options
  • Save lintianzhi/20b3214129bdc81ca5bb to your computer and use it in GitHub Desktop.
Save lintianzhi/20b3214129bdc81ca5bb to your computer and use it in GitHub Desktop.
ufop 完全指南

Table of Contents generated with DocToc

Ufop 完全操作指南

====

1. Ufop 是什么?

Ufop 的全称是 User-defined File OPeration

顾名思义,Ufop 是用户自定义的一种计算方式,当七牛暨有的 fop 功能不能满足用户对文件资源的操作时,可以将自定义的计算能力通过 ufop 的方式体现出来。用户自定义的 ufop 使用方式和七牛暨有 fop 的方式完全一致,因此用户添加到 Ufop 的功能能够无缝地融合到七牛的 fop 功能中。所以和七牛现有的 fop 一样,Ufop 也支持管道处理、持久化、预处理操作等所有特性。

对于文件处理,您当然也可自行将文件下载下来后进行处理,但如果使用 Ufop,那么可以将您的计算搬移至离您数据最近的地方,以最优的访问速度和最短的时间得到处理结果。

2. Ufop 如何工作?

2.1 Ufop 数据处理工作流

数据处理是 Ufop 的核心功能和价值,因此,每个 Ufop 需要做的事情非常简单,即专注数据处理本身:

  • 获取输入数据
  • 处理输入数据
  • 输出处理结果

正是基于如此简单的单元结构,七牛才能使用特有的管道机制自由地将多个 fop/Ufop 的输入和输出像搭积木一样串起来,获得多样化、个性化的数据处理结果。

3. 动手制作一个 Ufop

制作一个完整可用的 ufop,只需以下几步:

1. 注册一个有效可用的 ufop 名。
2. 通过工具上传符合规格(具体规格见下描述)的程序包。
3. 设置 ufop 的运行实例(实例将会自动启动运行)。

以上步骤所需要的唯一工具:qufopctl

当一个 Ufop 启动运行时,会根据您提供的程序包启动您的程序。

3.1 首先,要先注册一个 Ufop

qufopctl 的注册规格为:

qufopctl reg <Ufop> -mode <AclMode> -desc <Desc>

其中:

  • <Ufop>: 填写需要注册的 ufop 名称
  • <AclMode>:设置该 ufop 的访问权限:0 - 完全公开,1 - 半公开,2 - 私有
  • <Desc>:可选,对该 ufop 的描述文字

注意:当前普通用户只允许申请 AclMode 为 1 或者 2 的 ufop

3.1.1 关于 Ufop 的命名

Ufop 的命名是全局的,和七牛暨有的 fop 处于相同的名字空间。因此,用户当前无法注册:

1. 七牛暨有的 fop 名
2. 其他用户已经注册的 ufop 名

命名规则:

1. UTF-8 编码
2. 长度限制:[5, 20]
3. 必须由 小写字母、数字、减号、下划线 中的一种或多种类型的字符组合而成

3.1.2 关于 Ufop 的权限控制

ufop 的拥有者可以选择设置某 Ufop 的权限为 完全公开、半公开、私有:

1. 完全公开的 Ufop:可以被任意其他用户的资源访问,所有用户默认都能够使用。例如 七牛官方公开的 Ufop。
2. 半公开的 Ufop:其他用户默认不可访问,但均可主动添加该 Ufop 到自己的可访问 Ufop 列表中。
3. 私有的 Ufop:其他用户无权使用和访问,只有 Ufop 的属主的资源能够使用。

这里以注册一个名为 grepd、权限为半公开 的 Ufop 为例:

qufopctl reg grepd -mode 1 -desc "demo ufop"

3.2 创建镜像

Ufop 注册成功后,您还需要提供一个由二进制服务程序和一个编译脚本形成的程序包

3.2.1 二进制服务程序

一个符合规格的服务程序只需满足以下条件:

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==" 这个地址即能获取到待处理的原始文件。

3.2.2 编译脚本 ufop.yaml

除此之外,还需要提供一个名为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权限,运行时只有普通用户权限

3.2.3 示例

假设您有一个简单的字符处理服务 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

3.2.4 查看镜像信息

执行完build操作后,需要查看镜像信息,以确定编译结果以及已有的版本

qufopctl imageinfo grepd

3.2.5 查看镜像编译日志

编译过程中可能出错,这时候需要查看这个版本的编译日志

qufopctl buildlog grepd -v 1

3.2.6 切换版本

得到最新的ufop版本后,可以把当前版本切换到最新版本(build成功不会自动切换到最新版本)

qufopctl ufopver grepd -c 1

3.3 启动 Ufop 运行实例

在完成绑定的动作后,由于还没有实例运行,因此Ufop 还未处于未启动状态,下面通过 qufopctl 工具添加 Ufop 运行实例并启动 Ufop:

qufopctl 的实例调整功能,规格如下:

qufopctl resize <Ufop> -num <Instance-Limit>

其中:

  • <Ufop>:需要调整实例数的 Ufop 名
  • <Instance-Limit>:需要调整成的目标实例数

以设置 grepd 的运行实例为例:

qufopctl resize grepd -num 1

这将启动一个 grepd 的运行实例。

3.4 查看和调试服务程序

使用 qufopctl 工具,可以单独管理某个实例的运行状态,也可以查看某个实例运行的标准输出和错误输出信息。

3.4.1 关闭指定的运行实例

关闭功能的规格为:

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

既可。

注意:下面的 startstate 子命令的参数使用方法与此相同。

3.4.2 启动指定的运行实例

关闭功能的规格为:

qufopctl start <Ufop> [-index <Index> | -range <IndexStart:IndexEnd>]

其中:

  • <Ufop>:Ufop 名称
  • <Index>:需要启动的单个实例序号
  • <IndexStart>:批量操作的起始实例序号
  • <IndexEnd>:批量操作的终止实例序号

3.4.3 查看指定的实例当前运行状态

状态查看功能的规格为:

qufopctl state <Ufop> [-index <Index> | -range <IndexStart:IndexEnd>]

其中:

  • <Ufop>:Ufop 名称
  • <Index>:需要查看的的单个实例序号
  • <IndexStart>:批量操作的起始实例序号
  • <IndexEnd>:批量操作的终止实例序号

3.4.4 获得指定实例的标准输出/错误输出

使用 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

注意: 获取的输出信息中,每行开头默认会有自动添加的时间戳。

3.5 查看 Ufop 的相关信息

3.5.1 查看指定 Ufop 的基本信息

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

3.6.2 查看您有权访问的所有 Ufop 列表

无需参数,执行以下命令既可:

qufopctl list

注意:该命令显示的 Ufop 列表中可能包含两种 Ufop,一种是属主为您自己的 Ufop,另一种是您有权访问的 Ufop(但您对其没有管理权限)。

4. 访问和使用您的 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 之间自由地组合搭配,得到您想要的处理结果。

5. Ufop 运行实例的环境和资源限制

5.1 操作系统

您的程序将默认运行在 Ubuntu 14.04.1 LTS 的操作系统上。

5.2 运行数据安全

由于使用了内核级别的资源隔离和访问控制,您无需担心您的运行实例及其相关数据会被相同物理主机上的其他实例非法访问到。

6. 建议和注意事项:

一个理想的 ufop 的程序实例应当是无状态的,因为一个实例在被重启后会丢失前一次启动的运行数据(包括持久化数据)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment