golang高性能轻量级Actor模型引擎插件库Hollywood的使用
Golang高性能轻量级Actor模型引擎插件库Hollywood的使用
Hollywood是一个为速度和低延迟应用构建的ULTRA快速Actor引擎。适用于游戏服务器、广告代理、交易引擎等场景,可以在1秒内处理1000万条消息。
什么是Actor模型?
Actor模型是一种用于构建高度并发和分布式系统的计算模型。它由Carl Hewitt在1973年提出,作为处理复杂系统的一种更可扩展和容错的方式。
在Actor模型中,基本构建块是一个actor(在Hollywood中有时称为receiver),它是一个独立的计算单元,通过交换消息与其他actor通信。每个actor都有自己的状态和行为,只能通过发送消息与其他actor通信。
特性
- 编译为WASM!支持GOOS=js和GOOS=wasm32
- 保证消息在actor故障时的传递(缓冲机制)
- 支持发送即忘或请求响应消息,或两者兼有
- 高性能dRPC作为传输层
- 优化无反射的protobuf
- 轻量级且高度可定制
- 集群支持,用于编写分布式自发现actor
性能基准
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/...
Hollywood需要Golang版本1.21或更高
快速入门
Hello World示例
package main
import (
"fmt"
"github.com/anthdm/hollywood/actor"
)
// 定义消息类型
type message struct {
data string
}
// 定义actor
type helloer struct{}
func newHelloer() actor.Receiver {
return &helloer{}
}
// 实现Receive方法
func (h *helloer) Receive(ctx *actor.Context) {
switch msg := ctx.Message().(type) {
case actor.Initialized:
fmt.Println("helloer has initialized")
case actor.Started:
fmt.Println("helloer has started")
case actor.Stopped:
fmt.Println("helloer has stopped")
case *message:
fmt.Println("hello world", msg.data)
}
}
func main() {
// 创建引擎
engine, err := actor.NewEngine(actor.NewEngineConfig())
if err != nil {
panic(err)
}
// 生成actor
pid := engine.Spawn(newHelloer, "hello")
// 发送消息给actor
engine.Send(pid, &message{data: "hello, world!"})
}
生成Actor
使用默认配置
e.Spawn(newFoo, "myactorname")
向构造函数传递参数
func newCustomNameResponder(name string) actor.Producer {
return func() actor.Receiver {
return &nameResponder{name}
}
}
// 生成actor
pid := engine.Spawn(newCustomNameResponder("anthony"), "name-responder")
使用自定义配置
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("started")
_ = msg
}
}, "foo")
远程Actor
Actor可以通过Remote包在网络上相互通信。这与本地Actor的工作方式相同,但是"通过网络"。
配置
tlsConfig := TlsConfig: &tls.Config{
Certificates: []tls.Certificate{cert},
}
config := remote.NewConfig().WithTLS(tlsConfig)
remote := remote.New("0.0.0.0:2222", config)
engine, err := actor.NewEngine(actor.NewEngineConfig().WithRemote(remote))
事件流
在生产系统中,事情最终会出错。Actor会崩溃,机器会故障,消息最终会进入死信队列。您可以通过使用事件流构建能够优雅且可预测地处理这些事件的软件。
内部系统事件列表
actor.ActorInitializedEvent
- actor已初始化但尚未处理其actor.Started
消息actor.ActorStartedEvent
- actor已启动actor.ActorStoppedEvent
- actor已停止actor.DeadLetterEvent
- 消息未传递给actoractor.ActorRestartedEvent
- actor在崩溃/panic后已重新启动actor.RemoteUnreachableEvent
- 通过网络向不可达的远程发送消息cluster.MemberJoinEvent
- 新成员加入集群cluster.MemberLeaveEvent
- 新成员离开集群cluster.ActivationEvent
- 集群上激活新actorcluster.DeactivationEvent
- 集群上停用actor
自定义引擎
我们使用函数选项模式。所有函数选项都在actor包中,名称以"EngineOpt"开头。目前,唯一的选项是提供一个远程。
r := remote.New(remote.Config{ListenAddr: addr})
engine, err := actor.NewEngine(actor.EngineOptRemote(r))
中间件
您可以向Receivers添加自定义中间件。这对于存储指标、在actor.Started
和actor.Stopped
时为Receivers保存和加载数据非常有用。
日志记录
Hollywood有一些内置日志记录。它将使用log/slog
包中的默认记录器。您可以通过使用slog.SetDefaultLogger()
设置默认记录器来配置记录器。这将允许您自定义日志级别、格式和输出。
测试
make test
社区和讨论
加入我们的Discord社区,有超过2000名成员可以进行问题讨论和友好聊天。
生产中使用
以下组织/项目目前在生产中使用此项目:
- Sensora IoT
- Market Monkey Terminal
许可证
Hollywood根据MIT许可证授权。
更多关于golang高性能轻量级Actor模型引擎插件库Hollywood的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang高性能轻量级Actor模型引擎插件库Hollywood的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Hollywood - Golang高性能轻量级Actor模型引擎
Hollywood是一个轻量级的Golang Actor模型实现库,它提供了高性能的消息传递和并发处理能力。下面我将详细介绍Hollywood的使用方法。
安装
go get github.com/anthdm/hollywood
基本概念
- Actor:并发执行的基本单元
- PID:Actor的唯一标识符
- Message:Actor之间通信的基本单位
- Engine:Actor系统的运行时环境
快速开始
1. 创建Actor
package main
import (
"fmt"
"log"
"github.com/anthdm/hollywood/actor"
)
type Greeter struct{}
func (g *Greeter) Receive(c *actor.Context) {
switch msg := c.Message().(type) {
case string:
fmt.Printf("Received: %s\n", msg)
}
}
func main() {
// 创建引擎
e := actor.NewEngine()
// 定义Actor配置
config := actor.Config{
Producer: func() actor.Receiver { return &Greeter{} },
}
// 创建Actor并获取PID
pid := e.Spawn(&config, "greeter")
// 发送消息
e.Send(pid, "Hello, Hollywood!")
// 等待消息处理
time.Sleep(time.Second)
}
2. 请求-响应模式
type Request struct {
Query string
}
type Response struct {
Result string
}
type QueryActor struct{}
func (q *QueryActor) Receive(c *actor.Context) {
switch msg := c.Message().(type) {
case *Request:
// 处理请求并返回响应
c.Respond(&Response{Result: "Processed: " + msg.Query})
}
}
func main() {
e := actor.NewEngine()
pid := e.Spawn(actor.FromInstance(&QueryActor{}), "query")
// 发送请求并等待响应
resp, err := e.Request(pid, &Request{Query: "test"}, time.Second)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Response: %+v\n", resp)
}
3. 监督策略
Hollywood支持监督策略来处理Actor的异常:
type Worker struct{}
func (w *Worker) Receive(c *actor.Context) {
switch c.Message().(type) {
case string:
panic("something went wrong")
}
}
func main() {
e := actor.NewEngine()
// 配置监督策略
config := actor.Config{
Producer: func() actor.Receiver { return &Worker{} },
MaxRestarts: 3, // 最大重启次数
}
pid := e.Spawn(&config, "worker")
e.Send(pid, "trigger panic")
time.Sleep(time.Second)
}
4. 集群支持
Hollywood支持分布式Actor系统:
func main() {
// 创建本地引擎
localEngine := actor.NewEngine()
// 配置集群
clusterConfig := cluster.Config{
ListenAddr: "127.0.0.1:3000",
Regions: []string{"127.0.0.1:3001"},
}
// 创建集群
c := cluster.New(localEngine, clusterConfig)
// 启动集群
if err := c.Start(); err != nil {
log.Fatal(err)
}
// 在集群中注册Actor
pid := localEngine.Spawn(actor.FromInstance(&Greeter{}), "clusterGreeter", actor.WithClusterID("myapp"))
// 可以从其他节点发送消息到这个Actor
// ...
}
性能优化技巧
- 批量处理消息:在Actor的Receive方法中批量处理消息
- 避免阻塞操作:将耗时操作委托给其他Actor或goroutine
- 合理设置邮箱大小:根据负载调整Actor的邮箱容量
- 使用本地通信:同一进程内的Actor通信优先使用本地消息传递
// 批量处理示例
type BatchProcessor struct {
batch []string
}
func (b *BatchProcessor) Receive(c *actor.Context) {
switch msg := c.Message().(type) {
case string:
b.batch = append(b.batch, msg)
if len(b.batch) >= 100 {
// 处理批量数据
processBatch(b.batch)
b.batch = nil
}
case actor.SystemMessage:
// 处理系统消息
}
}
func processBatch(batch []string) {
// 批量处理逻辑
}
最佳实践
- 保持Actor无状态:尽可能使Actor成为无状态组件
- 消息不可变:确保消息是不可变的
- 合理划分职责:每个Actor应该只负责单一职责
- 监控和日志:实现适当的日志记录和监控
Hollywood是一个轻量但功能强大的Actor模型实现,特别适合需要高并发处理的Golang应用程序。通过合理设计Actor和消息流,可以构建出高性能、可扩展的并发系统。