Поддержка инфраструктуры Akka для поиска дублирующихся сообщений - PullRequest
5 голосов
/ 01 декабря 2011

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

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

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

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

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

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

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

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

Ответы [ 3 ]

11 голосов
/ 01 декабря 2011

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

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

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

5 голосов
/ 01 декабря 2011

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

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 => ...
  }
}
0 голосов
/ 05 декабря 2014

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

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

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

...