Поддержка платформы Akka для поиска повторяющихся сообщений

Я пытаюсь построить высокопроизводительную распределенную систему с Akka и Scala.

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

Однако временное окно, в котором может быть запрошено дублирование вычислений, может быть сколь угодно малым. например Я мог получить тысячу или миллион сообщений с запросами на одни и те же дорогостоящие вычисления в одно и то же время для всех практических целей.

Существует коммерческий продукт под названием Gigaspaces, который предположительно решает эту ситуацию.

Однако на данный момент в Akka нет поддержки фреймворка для работы с повторяющимися рабочими запросами. Учитывая, что фреймворк Akka уже имеет доступ ко всем сообщениям, маршрутизируемым через фреймворк, кажется, что решение фреймворка может иметь здесь большой смысл.

Вот что я предлагаю сделать для платформы Akka: 1. Создать трейт, указывающий тип сообщений (скажем, «ExpensiveComputation» или что-то подобное), которые подлежат следующему подходу кэширования. 2. Умело (хэширование и т. д.) идентифицируйте идентичные сообщения, полученные (одними и теми же или разными) субъектами в течение настраиваемого пользователем временного окна. Другие варианты: выберите максимальный размер буфера памяти, который будет использоваться для этой цели, при условии замены (скажем, LRU) и т. д. Akka также может кэшировать только результаты сообщений, которые были дорогими для обработки; сообщения, обработка которых заняла очень мало времени, при необходимости могут быть повторно обработаны; нет необходимости тратить драгоценное буферное пространство на кэширование их и их результатов. 3. При идентификации идентичных сообщений (полученных в пределах этого временного окна, возможно, «в один и тот же момент времени») избегайте ненужных дублирующих вычислений. Фреймворк будет делать это автоматически, и, по сути, дубликаты сообщений никогда не будут получены новым актором для обработки; они бесшумно исчезнут, а результат однократной обработки (независимо от того, было ли это вычисление уже выполнено в прошлом или продолжалось прямо сейчас) будет отправлен всем соответствующим получателям (немедленно, если он уже доступен, и по завершении вычисления, если нет). Обратите внимание, что сообщения следует считать идентичными, даже если поля «ответа» различаются, если семантика/вычисления, которые они представляют, идентичны во всех остальных отношениях. Также обратите внимание, что вычисления должны быть чисто функциональными, то есть свободными от побочных эффектов, чтобы предлагаемая оптимизация кэширования работала и вообще не меняла семантику программы.

Если то, что я предлагаю, не совместимо с тем, как работает Akka, и/или если вы видите веские причины, почему это очень плохая идея, сообщите мне об этом.

Спасибо, это круто, Scala


person scala_is_awesome    schedule 30.11.2011    source источник


Ответы (3)


То, о чем вы спрашиваете, не зависит от фреймворка Akka, а скорее как вы создаете своих участников и сообщения. Сначала убедитесь, что ваши сообщения неизменны и имеют правильно определенные идентификаторы с помощью методов equals/hashCode. Классы Case предоставляют вам оба варианта бесплатно, однако, если у вас есть ActorRefs, встроенные в сообщение для целей ответа, вам придется переопределить методы идентификации. Параметры класса case также должны рекурсивно иметь те же свойства (неизменяемость и правильное тождество).

Во-вторых, вам нужно выяснить, как акторы будут обрабатывать хранение и идентификацию текущих/прошлых вычислений. Самый простой способ — уникально сопоставить запросы участникам. Таким образом, этот актор и только этот актор когда-либо будет обрабатывать этот конкретный запрос. Это можно легко сделать с фиксированным набором участников и хэш-кодом запроса. Бонусные баллы, если набор участников находится под наблюдением, когда супервизор управляет балансировкой нагрузки/сопоставлением и заменой отказавших участников (Akka упрощает эту часть).

Наконец, сам актор может поддерживать поведение кэширования ответов на основе описанных вами критериев. Все потокобезопасно в контексте актора, поэтому кэш LRU с ключом самого запроса (помните хорошие свойства идентификации) легко с любым типом поведения, которое вы хотите.

person Neil Essy    schedule 01.12.2011
comment
существует вариант этого, который зависит от гарантии того, что последнее сообщение является обработанным, а не более ранним в очереди. т.е. я не хочу начинать дорогостоящие вычисления, пока не удостоверюсь, что все сообщения были получены. Я думаю, что описанный выше подход можно изменить с помощью FSM для достижения того же результата. - person dres; 03.10.2016

Как говорит Нил, на самом деле это не функциональность фреймворка, это довольно тривиально реализовать и даже абстрагировать в свою собственную черту.

trait CachingExpensiveThings { self: Actor =>
  val cache = ...
  def receive: Actor.Receive = {
    case s: ExpensiveThing => cachedOrCache(s)
  }

  def cacheOrCached(s: ExpensiveThing) = cache.get(s) match {
    case null => val result = compute(s)
                 cache.put(result)
                 self.reply_?)(result)
    case cached => self.reply_?)(cached)
  }
  def compute(s: ExpensiveThing): Any 
}


class MyExpensiveThingCalculator extends Actor with CachingExpensiveThings {
  def compute(s: ExpensiveThing) = {
    case l: LastDigitOfPi => ...
    case ts: TravellingSalesman => ...
  }
}
person Viktor Klang    schedule 01.12.2011
comment
Я также вычислил последнюю цифру числа Пи, какой вы ее сделали? ;п - person Noel Kennedy; 16.11.2012

Я не знаю, должны ли все эти обязанности выполнять только Акка. Как обычно, все зависит от масштаба, а в частности — от количества атрибутов, определяющих уникальность сообщения.

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

В случае идентичности вместо проверки простого равенства (что может быть узким местом) я скорее буду использовать алгоритм на основе графа, например signal-collect.

person hicolour    schedule 05.12.2014