Hollywood-это ультрастрадечная сборка двигателя актера для скорости и применения с низкой задержкой. Подумайте о игровых серверах, рекламных брокерах, торговых двигателях и т. Д. ... Он может обрабатывать 10 миллионов сообщений менее чем за 1 секунду .
Модель актера представляет собой вычислительную модель, используемая для создания высоко одновременных и распределенных систем. Он был представлен Карлом Хьюиттом в 1973 году как способ обработки сложных систем более масштабируемым и устойчивым к неисправности.
В модели актера базовый строительный блок - это актер, который иногда называют получателем в Голливуде, которая является независимой единицей вычислений, которая связывается с другими участниками путем обмена сообщениями. У каждого актера есть свое состояние и поведение, и он может общаться с другими актерами только путем отправки сообщений. Эта парадигма, передаваемая сообщением, позволяет создавать очень децентрализованную и устойчивую систему, поскольку актеры могут продолжать работать независимо, даже если другие участники терпят неудачу или становятся недоступными.
Актеры могут быть организованы в иерархии, а участники более высокого уровня контролируют и координируют субъекта более низкого уровня. Это позволяет создавать сложные системы, которые могут обрабатывать сбои и ошибки изящным и предсказуемым способом.
Используя модель актера в вашем приложении, вы можете создать высоко масштабируемые и устойчивые к неисправности системы, которые могут обрабатывать большое количество одновременных пользователей и сложных взаимодействий.
Гарантированная доставка сообщений об отказа актеров (буферный механизм)
Fire & Forget или запрос и ответ обмен сообщениями, или оба
Высокопроизводительный DRPC в качестве транспортного слоя
Оптимизированные прото -буферы без размышлений
Легкий и очень настраиваемый
Кластерная поддержка для написания распределенных актеров самообучения
make bench
spawned 10 engines spawned 2000 actors per engine Send storm starting, will send for 10s using 20 workers Messages sent per second 3244217 .. Messages sent per second 3387478 Concurrent senders: 20 messages sent 35116641, messages received 35116641 - duration: 10s messages per second: 3511664 deadletters: 0
go get github.com/anthdm/hollywood/...
Голливуд требует Голанга версии
1.21
Мы рекомендуем вам начать с написания нескольких примеров, которые работают локально. Запуск локально немного проще, так как компилятор может выяснить используемые типы. При удаленном запуске вам нужно будет предоставить определения Protobuffer для компилятора.
Давайте рассмотрим сообщение Hello World. Полный пример доступен в папке Hello World. Давайте начнем с главного:
двигатель, err: = actor.newengine (actor.newengineconfig ())
Это создает новый двигатель. Двигатель является ядром Голливуда. Он отвечает за актеры нереста, отправка сообщений и обработку жизненного цикла актеров. Если Голливуд не сможет создать двигатель, он вернет ошибку. Для разработки вы не должны использовать для передачи любых вариантов двигателю, чтобы вы могли пройти ноль. Мы посмотрим на варианты позже.
Далее нам нужно создать актера. Это иногда называют Receivers после интерфейса, который они должны реализовать. Давайте создадим нового актера, который напечатает сообщение, когда он получит сообщение.
pid: = ingin.spawn (newhelloer, "Привет")
Это заставит двигатель породить актера с идентификатором «Привет». Актер будет создан предоставленной функцией newHelloer . Идентификаторы должны быть уникальными. Это вернет указатель на пид. PID - это идентификатор процесса. Это уникальный идентификатор для актера. Большую часть времени вы используете PID для отправки сообщений актеру. Против удаленных систем вы используете идентификатор для отправки сообщений, но в локальных системах вы в основном используете PID.
Давайте посмотрим на функцию newHelloer и актер, которую она возвращает.
введите helloer struct {} func newhelloer () actor.receiver {return & helloer {}
} Достаточно просто. Функция newHelloer возвращает нового актера. Актер - это структура, которая реализует актера. Давайте посмотрим на метод Receive .
введите сообщение struct {} func (h *helloer) ceat (ctx *actor.context) {switch msg: = ctx.message (). (type) {case actor.initialized: fmt.println («Helloer инициализирован»). Actor.started: FMT.Println («Helloer начал») Case Actor.stopped: fmt.println ("helloer остановил") Дело *Сообщение: fmt.println ("Привет, мир", msg.data)
}
}Вы можете видеть, что мы определяем структуру сообщения. Это сообщение, которое мы отправим актеру позже. Метод приема также обрабатывает несколько других сообщений. Эти сообщения жизненного цикла отправляются двигателем актеру, вы используете их для инициализации своего актера
Двигатель передает Actor.context методу Receive . Этот контекст содержит сообщение, PID отправителя и некоторые другие зависимости, которые вы можете использовать.
Теперь давайте отправим сообщение актеру. Мы отправим message , но вы можете отправить любые сообщения, которые вы хотите. Единственным требованием является то, что актер должен иметь возможность обрабатывать сообщение. Для того, чтобы сообщения, чтобы иметь возможность пересечь проволоку, они должны быть сериализуемыми. Чтобы ProtoBuf имел возможность сериализовать сообщение, это должно быть указатель. Локальные сообщения могут быть любого типа.
Наконец, давайте отправим сообщение актеру.
Engine.send (pid, "Привет, мир!")
Это отправит сообщение актеру. Голливуд направит сообщение в правильный актер. Затем актер напечатает сообщение на консоли.
Папка «Примеры» - лучшее место для изучения и дальнейшего изучения Голливуда.
Когда вы порождаете актера, вам нужно будет предоставить функцию, которая возвращает нового актера. Поскольку актер появляется, есть несколько настроенных вариантов, которые вы можете предоставить.
E.spawn (newfoo, "myactorname")
Иногда вы захотите передать аргументы конструктору актера. Это можно сделать с помощью закрытия. В примере запроса есть пример этого. Давайте посмотрим на код.
Конструктор по умолчанию будет выглядеть примерно так:
func newnameresponder () actor.receiver {return & nameroponder {name: "noname"}
}Чтобы построить нового актера с именем, вы можете сделать следующее:
func newcustomnammeresponder (name string) actor.producer {return func () actor.receiver {return & nameresponder {name}
}
}Затем вы можете создать актера со следующим кодом:
PID: = Engine.spawn (NewCustomManmerSponder («Энтони»), «Имя-ответчик»)
E.spawn (newfoo, "myactorname", actor.withmaxrestarts (4), actor.withinboxsize (1024 * 2), actor.withid ("bar"),
)
)Варианты должны быть довольно самостоятельными. Вы можете установить максимальное количество перезапусков, что сообщает двигателю, сколько раз данный актер должен быть перезапущен в случае паники, размер почтового ящика, который устанавливает ограничение на то, как и необработанные сообщения, которые может удерживать входящие. чтобы заблокировать.
Актеры без государства могут быть порождены как функция, потому что это быстро и просто.
e.spawnfunc (func (c *actor.context) {switch msg: = c.message (). (type) {case actor.started: fmt.println ("Starting") _ = MSG
}
}, "foo")Актеры могут общаться друг с другом по сети с удаленным пакетом. Это работает так же, как и местные актеры, но «над проволокой». Голливуд поддерживает сериализацию с протобуфом.
remote.new () принимает адрес прослушивания и remote.config struct.
Вы создадите создание нового удаленного дистанционного управления с помощью следующего кода:
tlsconfig: = tlsconfig: & tls.config {сертификаты: [] tls.certificate {cert},
} config: = remote.newConfig (). withTls (tlsconfig) remote: = remote.new ("0.0.0.0.0:2222", конфигурация) двигатель, err: = actor.newengine (actor.newengineconfig (). )Посмотрите на примеры удаленного актера и клиент и сервер чата для получения дополнительной информации.
В производственной системе в конечном итоге пойдет не так. Актеры потерпят крушение, машины потерпят неудачу, сообщения в конечном итоге окажутся в очереди. Вы можете создать программное обеспечение, которое может справиться с этими событиями изящным и предсказуемым способом, используя поток событий.
Eventtream - это мощная абстракция, которая позволяет вам создавать гибкие и подключаемые системы без зависимостей.
Подпишитесь на любого актера на различный список системных событий
Транслируйте свои пользовательские события всем подписчикам
Обратите внимание, что события, которые не обрабатываются каким -либо актером, будут отброшены. У вас должен быть актер, подписанный на поток событий, чтобы получить события. Как минимум, вы захотите справиться с DeadLetterEvent . Если Голливуд не сможет доставить сообщение актеру, он отправит DeadLetterEvent в потоку событий.
Любое событие, которое выполняет интерфейс actor.LogEvent будет зарегистрировано в регистраторе по умолчанию, с уровнем серьезности, сообщением и атрибутами события, установленным методом actor.LogEvent log() .
actor.ActorInitializedEvent , актер был инициализирован, но не обработал своего actor.Started message
actor.ActorStartedEvent , актер начал
actor.ActorStoppedEvent , актер остановился
actor.DeadLetterEvent , сообщение не было доставлено актеру
actor.ActorRestartedEvent , актер перезапустил после аварии/паники.
actor.RemoteUnreachableEvent , отправляя сообщение через проволоку на удаленную дистанционную службу, который не может быть достижимы.
cluster.MemberJoinEvent , новый участник присоединяется к кластеру
cluster.MemberLeaveEvent , новый участник, оставил кластер
cluster.ActivationEvent , новый актер активируется на кластере
cluster.DeactivationEvent , актер деактивируется на кластере
Существует пример мониторинга Eventtream, который показывает вам, как использовать поток событий. В нем участвуют два актера, один нестабилен и будет рухнуть каждую секунду. Другой актер подписан на потоку событий и поддерживает несколько счетчиков для различных событий, таких как сбои и т. Д.
Приложение будет работать в течение нескольких секунд, а яд нестабильного актера. Затем он запрашивает монитор с помощью запроса. Поскольку актеры плавают внутри двигателя, именно так вы взаимодействуете с ними. Затем Main будет распечатать результат запроса, и приложение выйдет.
Мы используем шаблон опции функции. Все параметры функций находятся в пакете актера и запускают свое имя с «EngineOpt». В настоящее время единственный вариант - предоставить удаленный. Это делается
r: = remote.new (remote.config {listenaddr: addr}) двигатель, err: = actor.newengine (actor.engineoptremote (r))Addr - это строка с форматом «хост: порт».
Вы можете добавить пользовательское промежуточное программное обеспечение к своим приемникам. Это может быть полезно для хранения метрик, сохранения и загрузки данных для ваших приемников на actor.Started и actor.Stopped .
Для примеров того, как реализовать пользовательское промежуточное программное обеспечение, ознакомьтесь с папкой промежуточной программы в примерах
У Голливуда есть встроенная журнала. Он будет использовать журнал по умолчанию из пакета log/slog . Вы можете настроить журнал по своему вкусу, установив журнал по умолчанию с помощью slog.SetDefaultLogger() . Это позволит вам настроить уровень, формат и вывод журнала. Пожалуйста, смотрите пакет slog для получения дополнительной информации.
Обратите внимание, что некоторые события могут быть зарегистрированы в регистраторе по умолчанию, такие как DeadLetterEvent и ActorStartedEvent поскольку эти события выполняют интерфейс actor.LogEvent . См. Раздел EventStream выше для получения дополнительной информации.
make test
Присоединяйтесь к нашему сообществу Discord с более чем 2000 участниками по вопросам и хорошему чату.
Этот проект в настоящее время используется в производстве следующими организациями/проектами:
Sensora IoT
Голливуд лицензирован по лицензии MIT.