Ruby 阿里云 OSS 发布 Ruby SDK 啦,支持 STS/Callback~~~

rockuw · 2015年12月10日 · 最后由 aelf.io 回复于 2020年01月14日 · 5147 次阅读

喜欢 Ruby 的同学终于可以优雅地使用 OSS 了。先看看 Rubyist 如何上传和下载文件吧:

require 'aliyun/oss'
bucket = Aliyun::OSS::Client.new(
  endpoint: 'http://oss-cn-hangzhou.aliyuncs.com',
  access_key_id: 'xxx',
  access_key_secret: 'yyy').get_bucket('bucket')

bucket.put_object('ruby') { |s| s << 'hello world' }
bucket.get_object('ruby') { |c| puts c }

bucket.put_object('rails', :file => '/tmp/x')
bucket.get_object('rails', :file => '/tmp/y')

是不是 so easy?OSS SDK for Ruby 支持 OSS 99.9% 的功能,主要的 highlights 包括:

  • 简洁的接口 put_object/get_object/list_buckets/list_objects
  • block 风格的代码
  • iterator 形式的列表
  • 流式上传/下载
  • 断点续传上传/下载
  • 支持 STS
  • 支持 OSS Callback(上传回调)

下面我们介绍其中几个:

iterator 形式的列表

OSS 用户在一个 bucket 下可能有成千上万的 objects,所以 OSS 不会将 object 列表一次性全部返回,每次最多返回 1000 条。如果我要列出前 1001 个 object 怎么办?一般来说用户可能要调用两次接口。但是在 ruby 中你只需要一行:

bucket.list_objects.take(1001)

再比如用户要找 files/下文件名包含'ruby'的文件:

bucket.list_objects(prefix: 'files/').find { |x| x.key.include?('ruby') }

是不是非常方便?

流式上传

流式上传允许用户动态地一边生成内容,一边上传到 OSS,上传的数据可以 generate on the fly。如下面的例子:

bucket.put_object('numbers') do |stream|
  (1..1_000_000).each { |i| stream << i << "\n" }
end

注意:这里并不是要 100 万个数字都生成完后再发送,而是一边生成一边发送的。多线程?No。是协程(Fiber)。

上面的代码看似简单,但是实现起来却并不简单。试想一下,put_object如何调用接受的 block?如果调用那么 100 万个数字都一口气生成完了。如何能做到对一个函数调用一半?这就需要用到 Fiber:

def hello
  puts 'hello'
  Fiber.yield
  puts 'world'
end

def world
  fiber = Fiber.new { hello }

  puts 'first'
  fiber.resume # puts 'hello'
  puts 'second'
  fiber.resume # puts 'world'
end

world

类似上面的代码,stream#<<内每接受一部分内容,会将自己 yield 出去,这样已经接受的内容就可以立即发送出去。有兴趣可以查看 SDK 代码(见文章末尾链接)。

断点上传

在上传大文件时如果中途失败了,要重新上传是不是很沮丧?有了断点上传,中途失败后可以接着上次的进度继续上传。在 ruby 中只需要:

bucket.resumable_upload('object_key', 'local_file')

断点上传依赖于 OSS 提供的 multipart 功能,类似于一个事务:

  • 开启一个 multipart 上传 (begin transaction)
  • 将文件分成多个 part 分别上传 (do modify)
  • 完成此次 multipart 上传 (commit transaction)

只有最后一步成功后文件才算上传成功,在此之前文件对用户是不可见的。

文件被中断后如何恢复上传?如何知道哪些 parts 已经上传成功?这需要记录事务的状态信息。SDK 的做法是将这些信息(称为 checkpoint)保存在一个本地的 json 文件中。每上传完一个 part 就更新一次 checkpoint。恢复上传时从 checkpoint 文件中恢复上传的进度。

另外断点上传/下载中也利用多线程实现加速,先看结果:

$ruby tests/test_large_file.rb -n test_large_file_1gb                                                                                                                                                     
Run options: -n test_large_file_1gb --seed 7587

# Running:

user     system      total        real
Upload with put_object:           20.810000   1.880000  22.690000 ( 62.843336)
Upload with resumable_upload:     28.720000   9.740000  38.460000 ( 33.963555)
Download with get_object:         17.300000   4.550000  21.850000 ( 47.132476)
Download with resumable_download:  23.260000   9.530000  32.790000 ( 31.883211)

Ruby 或者 Python 的多线程一直是个“迷”,但是对于这种重 IO 场景,用多线程效果还是很明显的。因为进行 IO 的标准库函数在需要等待 IO 时会将当前线程切出去。参考:http://yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/

使用 STS 授权

[STS][aliyun-sts] 是阿里云提供的临时授权服务,一般应用于在移动端场景中:应用服务器持有阿里云 OSS 的账号,移动端需要访问 OSS 时,向应用服务器申请一个临时 TOKEN。应用服务器向 STS 申请一个临时 Token,这样做的好处是:

  1. 可以为不同的移动端设置不同的权限
  2. 可以隔离不同的移动端的存储目录,例如社交应用只具有sns/*目录的权限,而支付应用具有pay/*目录的权限
  3. 返回给移动端的临时 TOKEN 有失效期限(默认 1 小时),减小泄露的风险

更多使用 STS 的例子请参考:https://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/using-sts.html

使用 Callback

OSS 支持 [上传回调][oss-callback]:文件上传成功后,OSS 会向用户指定的服务器地址发起一个 HTTP POST 请求,以通知应用服务器相应的事件发生了。通知的内容可以携带上传成功的文件名,Bucket 名等信息。应用服务器在收到通知后可以做相应的动作,例如更新数据库、增加统计信息等。

更多使用 Callback 的例子请参考:https://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/put-object.html

一个简单的 rails demo

使用 OSS Ruby SDK 和 rails 可以在半小时内搭建一个 oss 文件管理器,可以查看/上传/下载文件。效果图如下:

QQ20151202_0

手把手教程:https://help.aliyun.com/document_detail/oss/sdk/ruby-sdk/rails-application.html

更多

[aliyun-sts]: https://help.aliyun.com/document_detail/ram/intro/concepts.html [oss-callback]: https://help.aliyun.com/document_detail/oss/user_guide/upload_object/upload_callback.html

这个有和 carrierwave 结合的例子吗

我比较关心什么时候出 ruby 的 ACE 啊

#1 楼 @awking 近期就会提供的,敬请关注。

@rockuw 短点续传这部分,客户端这边可以实现文件分片之后,请求服务器上传吗?之前我使用的是 aliyun-oss-ruby-sdk, 逻辑比较清楚

@rockuw 给你提了个 pr

#4 楼 @geekontheway 你要的是底层接口吗?也可以通过Protocol对象去操作。但是resumable_upload把能做的事情都帮你做了(分片,保存断点,多线程),为什么还需要底层操作呢?

您好,我这边有需求做 Ruby SDK,五千,您如果有兴趣可以联系我,微信:a439714

需要 登录 后方可回复, 如果你还没有账号请 注册新账号