Проблемы использования памяти на Rails ActiveSupport :: CachingKeyGenerator - PullRequest
2 голосов
/ 21 мая 2019

Чтобы зашифровать и сохранить информацию о пользователях в базе данных, мое приложение Rails использует salt (на пользователя) для генерации key с использованием ActiveSupport::KeyGenerator. Однако итерациями по умолчанию, выполняемыми методом generate_key, является 2**16 [1]. Выполнение генерации ключа с использованием salt пользователя при каждом чтении (для расшифровки) и записи (для шифрования) замедляет работу моего приложения.

Я обнаружил, что ActiveSupport::CachingKeyGenerator может использоваться для кэширования ключа, если salt и length, используемые для генерации ключа, остаются одинаковыми [2]. Внутренне он использует Concurrent::Map [3] для кэширования ключей. Использование ActiveSupport::CachingKeyGenerator увеличило производительность моего приложения, потому что оно не всегда генерирует ключ.

Приведет ли это к увеличению использования памяти моим приложением до уровня, при котором оно может вывести приложение из строя?

Ссылка:

  1. https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/activesupport/lib/active_support/key_generator.rb#L16

  2. https://api.rubyonrails.org/classes/ActiveSupport/CachingKeyGenerator.html

  3. https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/activesupport/lib/active_support/key_generator.rb#L33

1 Ответ

0 голосов
/ 22 мая 2019

Совместное использование "рабочего" решения

Поскольку ActiveSupport::CachingKeyGenerator использует Concurrent::Map, я обнаружил, что ключи кэширования приведут к увеличению использования памяти, пропорциональному количеству пользователей (при условии, что всезапросы как-то направляются на один и тот же узел).

Для решения этой проблемы я написал аналогичный CachingKeyGenerator, который охватывает ActiveSupport::KeyGenerator и ActiveSupport::Cache::MemoryStore.

class CachingKeyGenerator
  BASE = Rails.application.secrets.secret_key_base
  LENGTH = ActiveSupport::MessageEncryptor.key_len
  KEY_EXPIRY = 1.day

  def initialize
    @key_generator = ActiveSupport::KeyGenerator.new(Rails.application.secrets.secret_key_base)
    @keys_cache = ActiveSupport::Cache::MemoryStore.new(expires_in: KEY_EXPIRY)
  end

  def generate_key(salt)
    key = @keys_cache.fetch(salt)
    if key.nil?
      key = @key_generator.generate_key(salt, LENGTH)
      @keys_cache.write(salt, key)
    end
    key
  end
end

Согласно документации Rails, ActiveSupport::Cache::MemoryStore является поточно-ориентированным и реализует механизм очистки на основе LRU [1].Это должно сделать использование памяти кеша детерминированным - до размера, установленного для хранилища памяти (по умолчанию - 32 МБ, может быть определено во время инициализации).

PS: еще для развертывания этого на производстве, обновлюздесь, если у меня возникнут неожиданные проблемы.

[1] http://api.rubyonrails.org/classes/ActiveSupport/Cache/MemoryStore.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...