rails 3 и activerecord: нужно ли принимать специальные меры предосторожности при блокировке записей для обновления поля счетчика?

#ruby-on-rails #activerecord

#ruby-on-rails #activerecord

Вопрос:

Каждый раз, когда отображается профиль пользователя, мы обновляем целочисленный счетчик в таблице Users.

Я начал думать о ситуациях с высокой степенью совпадения и задался вопросом, что произойдет, если группа людей одновременно зайдет на страницу профиля пользователя: обрабатывает ли rails / activerecord волшебным образом блокировку записей и семафорирование для меня?

Или моему приложению нужно явно вызывать какой-то механизм, чтобы избежать пропуска событий обновления при одновременных вызовах моего метода обновления?

 def profile_was_hit
  self.update_attributes :hitcounter =>  self.hitcount   1
end
  

И в соответствии с этим, когда я должен использовать что-то вроде Users.increment_counter (: счетчик попаданий, self.id ) вместо этого?

Ответ №1:

В конфигурации по умолчанию один экземпляр Rails обрабатывает только один запрос одновременно, поэтому вам не нужно беспокоиться о каких-либо проблемах с параллелизмом на прикладном уровне.

Если у вас запущено несколько экземпляров вашего приложения (что вы, вероятно, делаете / будете делать), все они будут отправлять запросы к базе данных, не обсуждая это друг с другом. Вот почему это обрабатывается на уровне базы данных. MySQL, PostgreSQL и т.д. Все собираются заблокировать строку при записи.

Однако то, как вы справляетесь с этой ситуацией, не идеально с точки зрения производительности, потому что ваше приложение считывает значение, увеличивает его, а затем записывает. Это отставание между чтением и записью действительно позволяет вам пропускать значения. Вы можете избежать этого, перенеся ответственность за приращение в свою базу данных ( UPDATE hitcounter SET hitcount = hitcount 1; ). Я полагаю, что ActiveRecord имеет встроенную поддержку для этого, хотя мне / вам придется покопаться в этом. Обновление: О, да, да, вы хотите использовать increment_counter метод для этого. Справочная информация/Документация.

Как только вы обновите свой процесс, увеличивающий ответственность за передачу в базу данных, я бы некоторое время не беспокоился о производительности. Однажды у меня было PHP-приложение, которое выполняло это один раз за запрос, и оно великолепно масштабировалось для меня до 100 обновлений в секунду (mysqld на том же компьютере, без постоянных подключений и всегда < 10% cpu).

Комментарии:

1. Спасибо за этот исключительно полезный ответ. Это должно помочь многим людям. Итак, основная причина использования increment_counter заключается в том, чтобы перенести его на уровень базы данных, чтобы в среде с несколькими экземплярами (я на heroku) он управлял одновременным обновлением разных экземпляров. Спасибо!