Ruby で高速に OAuth で認証して アクセス する方法

結論から言うと、強力な CPU と大容量のメモリを用意して Thread を大量に作るのが一番速い。
ださいことこの上無いが、これが速いんだから仕方ない。

def self.post
  tokens = []
  User.all.each do |u|
    tokens << OAuth::AccessToken.new(consumer, u.token, u.secret_token)
  end
  tokens.each do |a|
    @t = Thread.start do
      res = a.post('/statuses/update.json', {:status => "なるほど四時じゃねーの"}) rescue nil
    end
  end
  @t.join
end

こんなの。本当にださいのだけど、これで十分なのだからしょうがない。というか Ruby でやる限りこれが一番速い。うちのそれなりのサーバーで twitter 相手で 100req/s ぐらいは出る。 CPU 使用率 70% ぐらいをうろうろする。

なるほど四時じゃねーの(http://4ji.ssig33.com)は今このだっさいコードで動いています。

ちなみに同じことを EventMachine でやるとこんな感じかな。

def self.oquno
  EM.run do
    multi = EventMachine::MultiRequest.new
    User.all.each do |u|
      request = EventMachine::HttpRequest.new('http://twitter.com/statuses/update.json')
      http = request.post(:body => {'status' => 'なるほど四時じゃねーの'}, :head => {"Content-Type" => "application/x-www-form-urlencoded"}) do |client|
        consumer.sign!(client, OAuth::AccessToken.new(consumer, u.token, u.secret_token))
      end
      multi.add http
    end
    multi.callback do
      EM.stop_event_loop
    end
  end
end

なにがボトルネックになってるのかは知らんが、 em-http-request を使うと、 twitter 相手に 35req/s ぐらいしか出ない。ちなみに何も考えないでシリアルにアクセスすると 1req/s ぐらいしか出ない。

twitter が十分に遅いというのを勘案しても、驚異的に遅い。ちなみに curl を使ってパラレルに HTTP アクセスする typhoeus は OAuth にろくに対応していない。

じゃあ em-http-request に使い道は無いかというとそうではなくて、 Twitter Streaming API を OAuth 経由でアクセスするのに使えます。

def self.fuba
  EM.run do
    u = User.find_by_name('ssig33')
    request = EventMachine::HttpRequest.new('http://betastream.twitter.com/1/statuses/filter.json?track=http')
    http = request.get(:head => {"Content-Type" => "application/x-www-form-urlencoded"}) do |client|
      consumer.sign!(client, OAuth::AccessToken.new(consumer, u.token, u.secret_token))
    end
    http.stream { |chunk| print chunk }
  end
end

BASIC 認証はそのうち廃止されるらしいので、 Streaming API にアクセスしているコードは、順次このように OAuth に置き換えるのがよいでしょう。 http://nl.amatz.com/ とかで em-http 使った Streaming Access を実際に投入してる。