Как да знам, че не блокирам Ruby eventmachine с операция mongodb

Работя върху приложение, базирано на машина за събития, което периодично проверява за промени в съхранени документи на MongoDB.

Един опростен кодов фрагмент може да изглежда така:

require 'rubygems'
require 'eventmachine'
require 'em-mongo'
require 'bson'

EM.run {

  @db       = EM::Mongo::Connection.new('localhost').db('foo_development')
  @posts    = @db.collection('posts')
  @comments = @db.collection('comments')

  def handle_changed_posts
    EM.next_tick do
      cursor = @posts.find(state: 'changed')
      resp = cursor.defer_as_a

      resp.callback do |documents|
        handle_comments documents.map{|h| h["comment_id"]}.map(&:to_s) unless documents.length == 0
      end

      resp.errback do |err|
        raise *err
      end
    end
  end

  def handle_comments comment_ids
    meta_product_ids.each do |id|
      cursor = @comments.find({_id: BSON::ObjectId(id)})
      resp = cursor.defer_as_a

      resp.callback do |documents|
        magic_value = documents.first['weight'].to_i * documents.first['importance'].to_i
      end

      resp.errback do |err|
        raise *err
      end
    end
  end

  EM.add_periodic_timer(1) do
    puts "alive: #{Time.now.to_i}"
  end

  EM.add_periodic_timer(5) do
    handle_changed_posts
  end
}

Така че на всеки 5 секунди EM преглежда всички публикации и избира променените. За всяка променена публикация той съхранява comment_id в масив. Когато е готово, този масив се предава на handle_comments, който зарежда всеки коментар и прави някои изчисления.

Сега имам някои трудности в разбирането:

  1. Знам, че този цикъл load_posts->load_comments->calculate отнема 3 секунди в Rails конзола с 20 000 публикации, така че няма да е много по-бързо в EM. Планирам метода handle_changed_posts на всеки 5 секунди, което е добре, освен ако броят на публикациите не се увеличи и изчислението не отнеме повече от 5 секунди, след които същото изпълнение се планира отново. В такъв случай скоро ще имам проблем. Как да избегнем това?

  2. Вярвам на em-mongo, но не се доверявам на знанията си за ЕМ. За да наблюдавам, че EM все още работи, аз puts клеймо за време всяка секунда. Това изглежда работи добре, но става малко неравномерно на всеки 5 секунди, когато изчислението ми се изпълнява. Това знак ли е, че блокирам цикъла?

  3. Има ли някакъв общ начин да разбера дали блокирам цикъла?

  4. Трябва ли да усъвършенствам своя процес на eventmachine с -19, за да му дам най-добрата операционна система преди винаги?


person GeorgieF    schedule 15.11.2013    source източник


Отговори (2)


Не бях склонен да отговоря тук, тъй като досега нямах опит с mongo, но като се има предвид, че никой не отговаря и някои от нещата тук са общи EM неща, може би мога да помогна:

  1. планирайте следващото сканиране в края на първото сканиране (resp.callback и resp.errback в handle_changed_posts изглеждат добри кандидати за верижно следващо сканиране), или с add_timer, или с next_tick
  2. вероятно, опитайте да управлявате вашите монго пътувания по-често, така че те да обработват по-малки части от данни, всеки цикъл на процесора във вашия реактор би направил цикъла на реактора ви твърде зает, за да приема събития като периодични отметки на таймера
  3. няма лесен начин, не. Една идея би била да се измери разликата от Time.now до next_tick{Time.now}, да се направи сравнителен анализ и след това да се проследят възможните виновници, когато разликата премине прага. Симулирането на бавни заявки (Симулиране на бавни заявки в mongodb? ?) и много паралелни връзки е добра идея
  4. Честно казано, не знам, никога не съм срещал хора, които правят това, очаквам, че зависи от други неща, работещи на този сървър
person bbozo    schedule 14.01.2014

За да разширим отговора на bbozo, по-специално във връзка с втория ви въпрос, няма момент, когато изпълнявате код, който да не блокира цикъла. Според моя опит, когато говорим за „неблокиращ“ код, това, което наистина имаме предвид е „код, който не блокира много дълго“. Обикновено това са много кратки периоди от време (по-малко от милисекунда), но те все пак блокират по време на изпълнение.

Освен това, единственото нещо, което next_tick наистина прави, е да каже „направи това, но не точно сега“. Това, което наистина искате да направите, както спомена bbozo, е да разделите обработката си на множество отметки, така че всяка итерация да блокира възможно най-малко време.

За да използвате вашите собствени показатели, ако обработката на 20 000 записа отнема около 3 секунди, 4000 записа трябва да отнеме около 0,6 секунди. Това би било достатъчно кратко, за да не повлияе обикновено на сърдечния ви ритъм от 1 секунда. Бихте могли да го разделите още повече, за да намалите количеството на блокирането и да направите реактора да работи по-гладко, но това наистина зависи от това колко паралелност имате нужда от реактора.

person Chris Hall    schedule 04.02.2014