Переопределение Rails.logger и проблемы с ним
Часто один и тот же rails-проект используется и для web-части, и для каких-то других задач, выполняемых по расписанию или для создания демонов. В таких случаях иногда хочется, чтобы логи разных частей писались в разные файлы.
Готового способа для этого я не нашел. Например, посмотрим на такой пример:
$ ./script/console
Loading development environment (Rails 2.3.5)
>> ActiveRecord::Base.logger = Logger.new(STDOUT)
=> #<Logger:0xb192594 @progname=nil, @level=0, @default_formatter=#<Logger::Formatter:0xb19255c @datetime_format=nil>, formatternil, logdev#<Logger::LogDevice:0xb19247c @shift_size=nil, @shift_age=nil, @filename=nil, @dev=#<IO:<STDOUT>, mutex#<Logger::LogDevice::LogDeviceMutex:0xb192444 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0xb19240c>
>> User.first
=> #<User id: 1, email: "seeduser@scalaxy.ru" ...>
>>
И где же логи, спросите вы?
Автоматизация vim с помощью pathogen
Извечная проблема о том, как добавлять и обновлять плагины в vim решилась благодаря легендарному Tim Pope.
Сегодня утром узнал от Ярослава Маркина о существовании pathogen.
Статья на английском о том, как им пользоваться, лежит здесь. Правда, я потратил полчаса, чтобы
догадаться, что надо добавить call pathogen#runtime_append_all_bundles()
в файл ~/.vimrc
.
После установки pathogen.vim в
можно хранить все плагины в папке /.vim/autoload/.vim/bundle
, причем каждый в своей папке.
А еще огромный плюс - в конце этой статьи код, который позволяет обновлять все плагины одной командой.
Использование ruby-debug
Использование дебаггера при разработке — это плохой тон. Это значит, что вы не понимаете, как работает ваша программа. Но иногда жизнь без дебаггера становится невыносимой.
Есть отличный плагин vim-ruby-debugger для редактора vim. Но он пока сыроват и не все возможности в нем есть. По крайней мере в моем случае, чтобы понять, что происходить внутри спека, он не помог.
Тогда я воспользовался старым дедовским способом:
require 'ruby-debug'
Debugger.start
И вставил вызов debugger в том месте, где мне это необходимо.
PgQ и Londiste
Хотя я так и не написал толком, как пользоваться PgQ и Londiste, но уже написал плагин, который облегчает его использование вместе с рельсами.
http://github.com/evtuhovich/pgq/tree/master
В README всё написано на плохом английском (с хорошим английским у меня плохо).
Совсем скоро я добавлю туда возможность прогонять миграции на master и slave базах данных одновременно. Тогда при очередной выкатке необходимо будет сделать только rake londiste:update в самом конце, после того, как все миграции прогонятся.
Проблема с проверкой уникальности какого-то поля в rails
Пусть в модели User у нас описана валидация для поля email
validates_uniqueness_of :email, :case_sensitive => false,
:message => i18n_proxy(:email_already_registered)
Следующий код генерирует вот такой запрос к базе данных:
SELECT * FROM users WHERE lower(email) = 'thmth' LIMIT 1
А на таблице users у нас индекс по полю email. В postgresql запрос, что вверху, не будет использовать индекс. Представьте, что будет, когда в таблице users десятки тысяч записей, а на каждое изменение любого поля в users вызывается такой запрос.
Именно это я наблюдал совсем недавно на нашей живой базе. Проблема решается
просто, например, убрать :case_sensetive
, а email всегда
предварительно переводить в нижние буквы.
Перенос таблицы в другую базу данных postgres без простоя приложения
В продолжении темы о нескольких базах данных в одном rails-приложении расскажу о том, как изящно перенести одну большую таблицу в другую БД postgresql.
Пусть у нас есть таблица messages с большим количеством данных (10 миллионов записей), которые мы решили перенести на другой сервер. Мы сделали, как написано в статье, указанной выше, а также создали в новой БД таблицу messages с такой же структурой.
Теперь с помощью londiste настраиваем репликацию из первой БД во вторую для таблицы messages (об этом я напишу подробнее попозже, пока же можно прочитать об этом у Андрея Стихеева в рассылке ror2ru).
Несколько баз данных
В некоторых ситуациях необходимо использовать более чем одну базу данных в проекте. Например, статистику и большие таблицы хранить на другом сервере, у которого большой и медленный диск, а данные, которые нужны постоянно, хранить на основном сервере с маленьким и быстрым диском.
В нашем случае хотелось унести большие таблицы на другой сервер, чтобы в дисковом кэше (а у главного сервера БД 32 Гб оперативной памяти) хранились все рабочие таблицы и никогда оттуда не убегали.
Рекурсивные особенности to_yaml
Если необходимо сериализовать/десериализовать какой-то объект, то yaml формат хорошо для этого подходит.
В моем проекте мы записывали объекты в очередь, использую yaml-сериализацию. На тестах все было хорошо. Но на живом эта самая сериализация стала выполняться очень долго.
Оказалось, что если у объекта есть связные объекты, то он их тоже засовывает в yaml, а если таких объектов очень много, то это будет сложная операция. Понятно, что в примитивных тестах этого было не видно, а подумать хорошо головой в тот раз не получилось.
Конкурентное пересоздание индексов в postgresql
На таблице postgresql с большим количеством данных невозможно быстро создать либо пересоздать индекс. При создании индекса таблица блокируется для операций INSERT, UPDATE и DELETE. В таких случаях может помочь конкурентное создание индекса. Иногда на postgresql стоит пересоздавать индексы, чтобы уменьшить их фрагментацию (и увеличить скорость). Создание конкурентного индекса будет частным случаем его пересоздания.
Пусть имеется таблица orders с 1 миллионом записей (приблизительно) в которой хранятся заказы. И в этой таблице есть поля country_id, region_id, city_id, на которых создан индекс.
Использование очередей в высоконагруженных проектах
При большом количестве запросов к приложению (в широком смысле этого слова) иногда целесообразно ``размазать’’ пиковую нагрузку во времени. Для этого удобно использовать очереди. То есть, если какое-то запрос наверняка должен быть выполнен, но не имеет значение произойдет это прямо сейчас или чуть попозже, можно создать событие в очереди. И когда до этого события дойдет очередь —– оно будет выполнено. Таким образом можно развести сложные запросы во времени.
Очереди подходят для таких задач, как, например, рассылка большого количества сообщений и обновление различных счетчиков в БД (если их актуальность не очень критична). Использование такого подхода позволяет контролировать пиковую нагрузку, за счет чего сделать систему более стабильной в работе и отказоустойчивой. Также это позволяет оставить приемлемое время ответа сервиса, потому что он сможет отвечать что-то до фактического завершения длинной операции.