Статьи

Ленты активности на основе Redis

Netzwerk Kinder, Sprechblasen Сегодня каналы активности являются неотъемлемой частью практически всех веб-приложений. Приложения на базе SaaS, социальные приложения и т. П. Нуждаются во временной шкале пользователя. Эти каналы активности и временные рамки пользователей могут легко выйти из-под контроля, если ими не управлять должным образом, особенно при большом количестве пользователей, регулярно регистрирующихся в системе.
Redis в этом случае может быть хорошим выбором для достижения простоты использования, скорости работы, масштабируемости и возможности истечения срока действия данных, если это не требуется после определенного периода времени.

В моем подходе база данных по умолчанию для приложения — MySQL, и я запускаю Redis в своем приложении отдельно для каналов активности. Это архитектурное решение является дискуссионным, поскольку оно увеличивает усилия по управлению двумя отдельными хранилищами данных. Тем не менее, это обеспечивает значительное повышение производительности приложения.

Давайте быстро запустим настройку Redis в нашем приложении. Добавьте самоцвет redis в наш Gemfile и запустите bundle .

 gem 'redis', :git => 'https://github.com/redis/redis-rb.git' bundle install 

Затем в нашей конфигурации / инициализаторах создайте файл с именем redis.rb и инициализируйте соединение с сервером Redis:

 $redis = Redis.new(:host => 'localhost', :port => 6379) 

Давайте загрузим консоль rails и посмотрим, работает ли соединение redis:

 $ rails c Loading development environment (Rails 4.0.0.rc1) 1.9.3-p327 :001 > $redis => #<Redis client v3.0.4 for redis://localhost:6379/0> 1.9.3-p327 :002 > 

Прекрасно работает!

Вот контекст нашего приложения: Приложение позволяет людям создавать и делиться едой с другими. Теперь системная временная шкала будет обеспечивать действия по созданию и обновлению блюд от людей, за которыми они следят.

Мы будем использовать гем шкалы времени Redis для создания шкалы времени на основе Redis. Позже в этой статье мы разберем функции этого драгоценного камня. Драгоценный камень использует after_create вызов after_create чтобы служить событиями для отслеживания определенного действия. Это также дает нам необходимые идентификаторы.

Текущая версия gem поддерживает Rails 3.2 (из-за зависимости от ActiveSupport и ActiveModel 3.2 для обратных вызовов.) Однако я просто разветвил ее и обновил зависимость gemspec для работы с Rails 4.0.0.rc1 здесь . Вы можете использовать мой форк в вашем Gemfile, как показано ниже:

 gem 'redis_timeline', :git => 'https://github.com/saurabhbhatia/redis-timeline.git'</p> <p>bundle install 

Самоцвет redis_timeline требует, чтобы мы сначала настроили актера. Как правило, он связан с нашим классом User, потому что субъект отвечает за действие, а пользователь выполняет все действия в приложении.

 class User < ActiveRecord::Base include Timeline::Actor has_many :meals end 

После настройки актера нам нужно настроить отслеживаемый класс. В нашем случае нам нужно отслеживать методы create и edit класса Meal. Посмотрим, как это сделать.

Сначала мы устанавливаем метод include Timeline::Track для настройки отслеживания на конкретной модели. Теперь вы можете определить метод, который вы хотите «отслеживать», и обратный вызов, который вы хотите, чтобы он «отслеживал».

 class Meal < ActiveRecord::Base include Timeline::Track belongs_to :user track :new_meal, on: :create, actor: :user track :edit_meal, on: :update, actor: :user end 

Давайте загрузим консоль рельсов и посмотрим, работает ли это.

 rails c Loading development environment (Rails 4.0.0.rc1) 1.9.3-p327 :001 > meal = Meal.create(:title => 'Nachos', :description => 'Cheesy & Corny' , :user_id => 1) => #<Meal id: 5, title: "Nachos", description: "Cheesy & Corny", created_at: "2013-06-23 09:13:30", updated_at: "2013-06-23 09:13:30", user_id: 1> 

Чтобы совершить звонок по временной шкале, нам нужно получить актера (в нашем случае пользователя) и timeline звонков.

 1.9.3-p327 :002 > user = User.find(1) 1.9.3-p327 :003 > user.timeline => [#<Timeline::Activity actor=#<Timeline::Activity class="User" display_name="#<User:0x000000049b2900>" id=1> created_at="2013-06-23T17:13:31+08:00" object=#<Timeline::Activity class="Meal" display_name="#<Meal:0x000000051b50f8>" id=5> target=nil verb="new_meal">] 

Объект временной шкалы содержит имя класса, название еды, объект пользователя и глагол. Глагол в основном обозначает отслеживаемое действие.

Это все еще чего-то не хватает. Нам нужно отправить наши обновления подписчикам пользователя. Наш механизм отслеживания также построен на Redis и выглядит примерно так. Для удобства я использовал эту статью для создания этого механизма и определил его в своей пользовательской модели.

 def follow!(user) $redis.multi do $redis.sadd(self.redis_key(:following), user.id) $redis.sadd(user.redis_key(:followers), self.id) end end def unfollow!(user) $redis.multi do $redis.srem(self.redis_key(:following), user.id) $redis.srem(user.redis_key(:followers), self.id) end end def followers user_ids = $redis.smembers(self.redis_key(:followers)) User.where(:id => user_ids) end def following user_ids = $redis.smembers(self.redis_key(:following)) User.where(:id => user_ids) end 

Чтобы отправить обновление пользователя подписчику, мы должны использовать ключ «последователи» и настроить его, как показано в следующем фрагменте. Драгоценный камень содержит параметр под названием `последователи ‘, куда мы можем отправить ключ наших последователей, хранящийся в базе данных Redis.

 track :new_post, on: :create, actor: :user, followers: :followers track :edit_post, on: :update, actor: :user, followers: :followers 

Чтобы отобразить ваш канал, вы можете вызвать метод `current_user` и вызвать канал в вашем контроллере. (Примечание: это предполагает, что вы используете что-то вроде [Devise] (https://github.com/plataformatec/devise), которое предоставляет помощник `current_user`.)

 def index @feed = current_user.timeline end 

Под капотом

Драгоценный камень использует модель «веер при записи» для звонка в магазин Redis. Это реализуется с помощью lpush . Лента сохраняется в виде списка хэшей. Сначала он создает хеш всех отслеживаемых элементов и идентификаторов с помощью установщиков. Затем отправляет их в список с помощью lpush . Вы можете проверить это более подробно в документации по треку .

 def redis_add(list, activity_item) Timeline.redis.lpush list, Timeline.encode(activity_item) end 

Для чтения и записи списка используются кодер и декодер JSON. Это связано с тем, что redis рассматривает все свои объекты как строки, а хеши должны быть сериализованы как строки, прежде чем их можно будет сохранить. Это определено в классе помощника .

В классе помощника также определен метод для чтения списка с использованием lrange .

 def get_list(options={}) Timeline.redis.lrange options[:list_name], options[:start], options[:end] end 

Некоторые хитрости

Другие вещи, которые можно сделать для оптимизации списков:

  1. Обрезать список. Одним из преимуществ использования списка в качестве структуры данных является то, что вы можете его обрезать. Например, если вам нужна обобщенная временная шкала системы и вы хотите отобразить последние 100 объектов, вы можете просто обрезать список до этого.
     LTRIM <user timeline list key> 0 99 
  2. Срок действия списка истекает. Если вам кажется, что поддержка постоянного хранилища системной временной шкалы слишком затратна, вы можете прекратить ее действие в течение заданного интервала времени. Время определяется в секундах.
     EXPIRE <user timeline list key> 3600 

Вывод

Redis — это эффективный способ разработки и управления лентами активности и их изоляции от системы. Это может помочь в масштабировании основного приложения, так как это позволит избежать ненужных записей из основной базы данных. Теперь иди создавать эти каналы активности!