背景
作为阿里云的明星存储产品,越来越多的用户选择OSS作为数据源,用来存储网页、视频、图片、文本等静态文件,并选择OSS的图片服务、rtmp推流截帧等功能进行进一步的数据处理,极大的方便了用户对数据的深加工。但是互联网对数据的处理需求是无止境的,总有各种各样的场合需要对OSS上的数据做定制化的处理,比如以下三个实际碰到的场景:
场景1:美柚是一家专注于女性健康生活的公司,使用了阿里云的OSS服务作为相关文件的存储系统。现在美柚需要识别OSS上图片的二维码,计算图片的hash值等,但是OSS已有的图片服务并不支持这两个功能,该怎么办呢?
场景2:某款优秀的云音乐软件,其很多数据也是存储在OSS上。现在其需要对OSS上的图片用特定的算法裁剪出其中的人脸部分区域,但是OSS目前并不支持,该怎么办呢?
场景3:九游是阿里UC优视旗下的一项重要战略业务,其发行平台最初的游戏渠道打包业务方案,是将原始包处理成不同的渠道包后分别上传至OSS,再供玩家下载安装,带来的问题是一个原始包会扩展成多个设置上百个渠道包,极大的增加了存储成本,同时处理的过程也需要多台ECS,增加成本,而且先处理后上传的方案造成玩家不能及时下载安装包,是否有更加节省成本、提高效率的方案呢?
如果是之前,美柚、云音乐公司和九游必须通过阿里云的客户经理将需求反馈到OSS,然后由OSS评估、设计方案、开发代码、上线功能。其中存在一些问题:第一,沟通的成本较高,从提出需求到最后上线验证,中间需要较长时间去沟通;第二,有些算法比如人脸裁剪的算法涉及到专利,不希望其他厂商了解,因此OSS很难按照用户的特定需求去开发;第三,用户基于目前的接口设计出的方案可能不太理想,增加了额外的存储和计算成本。
为了解决用户的这些痛点,OSS开发了UDF(User Defined
Function,用户自定义函数)功能,搭建了一个能够实现用户定制数据处理的框架,满足用户针对特定场景的数据处理需求,整个开发和上线的流程完全由用户决定,不需要提需求给OSS,极大的缩短了功能上线的周期,在互联网瞬息万变的今天,抢时间就是抢的发展的先机。下文将给大家详细介绍UDF。
术语
UDF(User Defined Function):用户自定义函数,指OSS提供的实现用户自定义数据处理的框架
镜像(image):用户实现自定义处理需要提供的资源打包文件,至少包括一个可执行文件,以及一个名称为udf.yaml的文件,这个yaml格式的文件描述了可执行文件的执行环境以及启动方式
应用(application):用户的资源管理单位,用户可以通过创建应用将镜像部署起来并执行
实例(instance):用户的可执行文件运行的最小资源单位。一个应用下面可以起多个实例,一个实例内部按照镜像描述启动用户的可执行文件
UDF框架概述
UDF作为OSS的一个功能,其整体框架如图一所示。
用户发起了一个OSS请求后,如果指定了udf处理参数,则OSS会将用户访问的资源等相关信息组织成一个POST请求,发送给用户的UDF程序,UDF程序需要监听固定的端口(9000),并响应这个POST请求,UDF根据OSS发送的请求内容对数据做处理后返回给OSS,OSS同步的返回给客户端,这样就实现了用户自定义的数据处理功能。
以GetObject为例,假设用户定义了一个UDF叫做udf-example,这个UDF的功能是将文件中的所有单词“Hello”找出来。用户有一个bucket叫做bucket-1,存储有一个文件object-1,文件内容是”Hello world! Hello word!”,那么用户调用GetObject接口访问这个文件的时候,可以传入请求参数”?x-oss-process=udf/udf-example”,那么OSS收到这个请求后,就会发送一个POST请求给UDF,POST的消息体包括了这个文件的访问地址,UDF就可以访问这个地址拿到object-1这个文件,过滤出”Hello”并返回给OSS,OSS就会返回客户端,在这个例子中客户端就会收到”HelloHello”,从而实现了用户的定制需求。
UDF与OSS的通信协议
因为UDF是用户自己实现的功能,OSS需要与UDF通信,就需要定义一套固定的协议。我们约定以下协议:
1. OSS通过http协议与UDF通信
2. UDF需要监听9000端口
3. UDF需要响应POST /udf请求,即相应POST方法,uri为”/udf”,OSS会将数据发送到这个资源地址
4. UDF需要响应GET /CheckHealthy请求,用作健康检查。如果程序正常运行,只需要返回200 OK即可
5. OSS发送给UDF的POST请求的消息体是一个json格式的数据,字段定义如下:
{
“version”:”1.0”, //版本号,目前为1.0
“udfName”:””, //访问的UDF的名称,比如为例子中的udf-example
“udfParam”:””, //UDF参数,访问时在跟在udfName后面并以”,”分隔的参数部分
“resUrl”:””, //此次请求访问的资源地址,UDF可以通过http的GET方法去访问这个地址,拿到需要处理的数据
“bucket”:””, //用户发送的请求访问的bucket
“object”:””, //用户发送的请求访问的object
“owner”:””, //用户访问的bucket和object的owner
“fileSize”:, //用户访问的资源的大小
“reqId”:”” //请求的requestid
}
6、 UDF正常处理POST请求后,需要返回200
OK给OSS,其他的http状态码会被OSS认为是异常状态,从而报错(如果客户端发起的是GetObject请求,那么UDF还可以返回206)
UDF的调用方式
用户可以通过请求参数或者请求头的方式调用自己创建的UDF,格式如下:
x-oss-process=udf/udfName,udfParams
其中x-oss-process为请求参数的key或者请求header的key,”udf/”为固定字符串,表示调用UDF,udfName为需要调用的UDF名称,比如”udf-example”,udfParams则是UDF的参数,通过逗号与UDF名称相连,根据OSS与UDF之间的通信协议,POST消息体中的udfName字段即为此处的udfName,udfParams字段即为此处的udfParams。
举个例子,假设用户在杭州有一个bucket为my-bucket,其中有一个object为my-object,创建了一个UDF为udf-example,那么用户可以通过以下url访问UDF:
my-bucket.oss-cn-hangzhou.aliyuncs.com/my-object?x-oss-process=udf/udf-example,p1_v1,p2_v2
OSS收到这个GetObject请求后,会向udf-example这个UDF的9000端口发送一个POST请求,请求的内容为
{
“version”:”1.0”,
“udfName”:”udf-example”,
“udfParam”:”p1_v1,p2_v2”,
“resUrl”:”<此处为一个资源地址,可以访问到my-object这个文件>”,
“bucket”:”my-bucket”,
“object”:”my-object”,
“owner”:”12345678901234”,
“fileSize”:23,
“reqId”:”
58CCA609F1D225BA0E00004C”
}
udf-example这个UDF收到请求后,就可以下载resUrl指定的数据,根据自己的需要处理后返回,OSS会同步等待UDF并将数据返回给客户端,因此用户就可以接收到UDF处理过的数据了。
实战
下面以一个具体的例子来梳理从开发到使用的完整流程。假设我需要实现一个功能,将OSS文件中的某字符串替换成另外的一个字符串,因此我们将开发一个叫做replace的UDF,完整的步骤如下:
1. 开发UDF程序,编译出可执行文件。用户需要根据OSS与UDF之间的通信协议,开发出一个实现定制功能的可执行文件,这个可执行文件其实是一个webserver,监听9000端口,响应POST /udf和GET /CheckHealthy请求。我们使用go语言编写,文件名为udf-replace.go,完整的代码见附件。通过编译命令 go build udf-replace.go编译出udf-replace可执行文件。
2. 创建一个名称为”udf.yaml”的文件,文件是yaml格式,描述了程序运行的环境和启动方式,此例中udf.yaml文件内容为:
image: ubuntu
run:
./udf-replace
将udf.yaml文件和可执行文件udf-replace放在同一个目录下,并在这个目录中执行命令tar zcf udf-replace.tar.gz ./,生成压缩文件udf-replace.tar.gz
3. 控制台上创建一个UDF,确定名称为replace
4. 制作镜像。将步骤2中创建的udf-replace.tar.gz文件通过控制台的制作镜像按钮上传到这个UDF上,等待镜像制作完成。
5. 创建应用。比如在杭州区域,选择刚才制作的镜像去创建应用,需要选择实例的规格、数量等参数,等待应用创建完成。
6. 应用创建完成后,即可在杭州区域调用replace这个UDF。假设我有一个public-read的bucket是my-bucket,里面有一个文件my-object,内容是”Hello World!”,那么访问下面的链接”my-bucket.oss-cn-hangzhou.aliyuncs.com/my-object?x-oss-process=udf/replace,o_O”,将会返回” HellO
WOrld!”,如果我们想将Hello换成Bye,只需要访问这个链接即可”my-bucket.oss-cn-hangzhou.aliyuncs.com/my-object?x-oss-process=udf/replace,Hello_Bye”
安全性
1. 不同的UDF实例之间通内核级别的隔离保证运行环境的安全性,网络方面通过安全组的方式只开放某一端口,阻断其他端口,并且OSS与UDF之间通过签名验证的方式保证请求都来自于OSS
2. UDF目前只开放private级别的权限,即只有能够访问自己的bucket的用户才能访问自己的UDF,保证UDF不会被其他用户随意访问,当然我们也提供了机制将自己的UDF授权给其他用户访问。如果需要创建public级别的所有用户都可以自由调用的UDF,请联系OSS
UDF的优点
1. UDF是OSS提供的一套自定义数据处理的框架,可以完全由用户根据需要定制数据处理方式,并且快速部署上线、迭代升级,功能和节奏完全由自己掌控
2. 所需的计算资源不需要自己维护,完全由OSS运维。如果不使用UDF,意味着用户需要自己购买机器,下载并处理OSS上的文件并再次上传到OSS上,既需要运维机器资源,还将面临新建账号体系等安全问题、QoS、延迟等许多的性能问题,UDF框架则完全解决了这些问题,用户只需要将精力放在定制的数据处理本身的实现上
3. 调用方式简单。与OSS的图片处理等既有的数据处理调用方式一样,都是通过x-oss-process这个请求参数或者请求头来调用。用户调用自己的UDF,就像调用OSS的图片服务等固有功能一样简单
4. 易于第三方平台的接入。第三方的功能可以通过UDF框架计入到OSS中,提供给所有的OSS用户使用,比如场景标签、鉴黄暴恐、人物识别等等第三方厂商提供的功能
结语
美柚和某云音乐公司通过OSS的UDF平台,完美的实现了其需求,而且以后想添加新的功能,只需要再升级UDF的镜像版本即可,非常快捷。九游通过UDF框架改进了原有方案,极大的减少了打包和存储的成本,缩短了从基础包上传到玩家下载渠道包的时间(九游的详细改进方案参见九游:通过OSS UDF提升交付能力及降低成本)。还有许多其他的场景,比如压缩和解压缩、图片打标、鉴黄等等,都通过UDF得以实现。非常欢迎大家使用,有任何的咨询和使用方面的问题、意见和建议,欢迎加入OSS的旺旺技术交流群(1421921057)。