3

アイテムが検索またはリスト ページに表示される回数をログに記録して計算することに関心があります。1 日あたり 50,000 のユニークな訪問者がいる場合、1 日あたり 300 万から 400 万の「インプレッション」を生み出すことができると予想しています。

このデータをリアルタイムで読み取る必要はありませんが、毎日の合計を生成し、傾向などを分析できるようにしたいと考えています。ビジネス分析ツールと同様です。

ページがレンダリングされた後、Ajax 投稿でこれを行う予定です。これにより、結果がキャッシュされている場合でも結果をカウントできるようになります。これは、ページごとに 1 つの投稿で行うことができ、コンマで区切られた ID のリストとページ上の位置を送信できます。

これについて、よくある初心者の間違いを避けるのに役立つ、ある種のデザインパターン/宝石/ブログ投稿があることを願っています. また、ログの記録やログの読み取りの経験もあまりありません。

私の現在の戦略 - ログ ファイルにイベントを書き込む何かを作成し、1 日の終わりに結果を集計して結果を mysql に戻すバックグラウンド ジョブを作成します。

4

3 に答える 3

3

わかりました、私はあなたのために3つのアプローチを持っています:

1) キュー

AJAX ハンドラーで、クエリ パラメータをキューにプッシュするための最も簡単な方法 (Rack ミドルウェアまたは Rails Metal を使用) を記述します。次に、キューをポーリングしてメッセージを収集します。

ラック ミドルウェアからのキュー プッシュは、非常に高速です。同様のデータを記録するために、非常にトラフィックの多いサイトでこれを使用します。

ラック ミドルウェアの例を以下に示します (アプリから抽出したもので、2 ミリ秒未満でリクエストを処理できます。

class TrackingMiddleware
  CACHE_BUSTER = {"Cache-Control" => "no-cache, no-store, max-age=0, must-revalidate", "Pragma" => "no-cache", "Expires" => "Fri, 29 Aug 1997 02:14:00 EST"}

  IMAGE_RESPONSE_HEADERS = CACHE_BUSTER.merge("Content-Type" => "image/gif").freeze
  IMAGE_RESPONSE_BODY = [File.open(Rails.root + "public/images/tracker.gif").read].freeze

  def initialize(app)
    @app = app
  end

  def call(env)
    if env["PATH_INFO"] =~ %r{^/track.gif}
      request = Rack::Request.new(env)
      YOUR_QUEUE.push([Time.now, request.GET.symbolize_keys])
      [200, IMAGE_RESPONSE_BODY, IMAGE_RESPONSE_HEADERS]
    else
      @app.call(env)
    end
  end
end

starlingをお勧めするキューについては、私はそれで楽しい時間を過ごしました。

解析の最後には、スーパーポーラーツールキットを使用しますが、私はそれを書きました。

2) ログ

すべてのパラメーターをクエリ パラメーターとして静的ファイル (/1x1.gif?foo=1&bar=2&baz=3) に渡します。これはレール スタックにヒットせず、目がくらむほど高速になります。

データが必要な場合は、ログ ファイルを解析するだけです。

これは、最適なスケーリング ホーム ブリュー アプローチです。

3) Google アナリティクス

グーグルがあなたのためにそれをするのに、なぜ負荷を処理するのですか?自作する前に、Google アナリティクスの優れた機能に驚かれることでしょう。ぜひチェックしてみてください。

Google はあなたよりも早くサーバーを購入するため、これは無限に拡大します。


私はこれについて何年も怒鳴ることができましたが、今行かなければなりません。お役に立てれば!

于 2009-10-20T17:43:15.617 に答える
1

これが私が最終的に行ったことです。今のところ、私たちの使用には十分でした。いくつかの簡単なベンチマークで、私はそれについてOKだと感じています. 結果をお客様に公開する前に、本番環境でどのように動作するかを監視します。

コンポーネント:

class EventsController < ApplicationController
  def create
    logger = Logger.new("#{RAILS_ROOT}/log/impressions/#{Date.today}.log")
    logger.info "#{DateTime.now.strftime} #{params[:ids]}" unless params[:ids].blank?
    render :nothing => true
  end
end

これは、サイト レイアウトの ajax 呼び出しから呼び出されます...

<% javascript_tag do %>
  var list = '';
  $$('div.item').each(function(item) { list += item.id + ','; });
  <%= remote_function(:url => { :controller => :events, :action => :create}, :with => "'ids=' + list" ) %>
<% end %>

次に、これらのカンマ区切りの ID の行をデータベースにインポートする rake タスクを作成しました。これは次の日に実行されます。

desc "Calculate impressions"
task :count_impressions => :environment do
  date = ENV['DATE'] || (Date.today - 1).to_s # defaults to yesterday (yyyy-mm-dd)
  file = File.new("log/impressions/#{date}.log", "r")
  item_impressions = {}
  while (line = file.gets)
    ids_string = line.split(' ')[1]
    next unless ids_string
    ids = ids_string.split(',')
    ids.each {|i| item_impressions[i] ||= 0; item_impressions[i] += 1 }
  end
  item_impressions.keys.each do |id|
    ActiveRecord::Base.connection.execute "insert into item_stats(item_id, impression_count, collected_on) values('#{id}',#{item_impressions[id]},'#{date}')", 'Insert Item Stats'
  end

  file.close
end

注意すべきことの 1 つ - logger 変数は、コントローラー アクションで宣言されます。通常、ロガーで行うように、environment.rb では宣言されません。これをベンチマークしました-10000回の書き込みには約20秒かかりました。平均約 2 ミリ秒の書き込み。environment.rb のファイル名で、約 14 秒かかりました。ファイル名を動的に決定できるように、このトレードオフを行いました。これにより、深夜にファイルを簡単に切り替えることができます。

この時点での主な関心事 - 1 日にいくつの異なるアイテムがカウントされるかわかりません - つまり。尾の長さはわかりません。これにより、毎日データベースに追加される行数が決まります。日次レポートを保持する期間を制限する必要があり、その時点でさらに結果をロールアップする必要があると予想しています.

于 2009-10-22T20:45:30.610 に答える
1

アイテムをリストするために必要なアクションに応じて、コントローラーでそれを実行して往復を節約できる場合があります。after_filter を使用して、追加を目立たなくすることができます。

これは、ログに記録するアイテムをリストするすべてのアクションでパラメーターが必要な場合にのみ機能します。これは、ページ キャッシュがパラメーターを含む GET 要求を無視するためです。

検索アクションで検索データのみをログに記録したいと仮定します。

class ItemsController < ApplicationController
  after_filter :log_searches, :only => :search

  def log_searches
    @items.each do |item|
      # write to log here
    end
  end

  ...
  # rest of controller remains unchanged
  ...
end

それ以外の場合は、AJAX と onload リモート関数を使用して順調に進んでいます。

処理に関しては、cron ジョブによって実行される rake タスクを使用して統計を収集し、場合によってはアイテムの人気度を更新することができます。

いずれにせよ、 Ruby Logging クラスを読みたいと思うでしょう。cron ジョブと rake タスクについて学ぶことも問題ありません。

于 2009-10-20T17:36:44.637 に答える