V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rockuw
V2EX  ›  Ruby

阿里云 OSS Ruby SDK 开发手记

  •  
  •   rockuw · 2016-03-14 19:52:57 +08:00 · 5392 次点击
    这是一个创建于 3210 天前的主题,其中的信息可能已经有所发展或是发生改变。

    阿里云 OSS是一个对象存储服务,类似于 Amazon 的 S3 。相比于自建存储,使用 OSS 能够迅速帮您搞定存储,并且大大地节省成本,提升可靠性和安全性。

    现在,喜欢 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 目前绝大部分功能,主要的 highlights 包括:

    • 顾名思义的接口 put_object/get_object/list_buckets/list_objects
    • block 风格的代码
    • iterator 形式的列表
    • 流式上传 /下载
    • 断点续传上传 /下载

    下面我们随便挑几个来聊一聊:

    1. 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') }
    

    是不是非常方便?

    2. 流式上传

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

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

    注意:这里并不是要 100 万个数字都生成完后再发送,而是一边生成一边发送的。

    要做到上面的效果并不容易,试想一下,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 代码

    3. 断点上传

    在上传大文件时如果中途失败了,要重新上传是不是很沮丧?有了断点上传,中途失败后可以接着上次的进度继续上传。在 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/

    一个简单的 demo

    借助 rails ,可以在 15 分钟内搭建一个oss 文件管理器,可以查看 /上传 /下载文件,效果图如下:

    QQ20151202_0

    更多

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2773 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 06:35 · PVG 14:35 · LAX 22:35 · JFK 01:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.