goakt

module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2023 License: MIT

README

Go-Akt

build codecov Go Report Card GitHub release (with filter) GitHub tag (with filter)

Distributed Go actor framework to build reactive and distributed system in golang using protocol buffers as actor messages.

GoAkt is highly scalable and available when running in cluster mode. It comes with the necessary features require to build a distributed actor-based system without sacrificing performance and reliability. With GoAkt, you can instantly create a fast, scalable, distributed system across a cluster of computers.

If you are not familiar with the actor model, the blog post from Brian Storti here is an excellent and short introduction to the actor model. Also, check reference section at the end of the post for more material regarding actor model.

Table of Content

Features

  • Actors - The fundamental building blocks of Go-Akt are actors.
    • They are independent, isolated unit of computation with their own state.
    • They can be long-lived actors or be passivated after some period of time that is configured during their creation.
    • They are automatically thread-safe without having to use locks or any other shared-memory synchronization mechanisms.
    • They can be stateful and stateless depending upon the system to build. Every actor in Go-Akt:
      • has a process id PID. Via the process id any allowable action can be executed by the actor.
      • has a lifecycle via the following methods: PreStart, PostStop. It means it can live and die like any other process.
      • handles and responds to messages via the method Receive. While handling messages it can:
        • create other (child) actors via their process id PID SpawnChild method
        • send messages to other actors locally or remotely via their process id PID Ask, RemoteAsk(request/response fashion) and Tell, RemoteTell(fire-and-forget fashion) methods
        • stop (child) actors via their process id PID
        • watch/unwatch (child) actors via their process id PID Watch and UnWatch methods
        • supervise the failure behavior of (child) actors. The supervisory strategy to adopt is set during its creation:
          • Restart and Stop directive are supported at the moment.
        • remotely lookup for an actor on another node via their process id PID RemoteLookup. This allows it to send messages remotely via RemoteAsk or RemoteTell methods
      • can adopt various form using the behavior feature
      • can be restarted (respawned)
      • can be stopped (killed)
      • has few metrics:
        • Mailbox size at a given time. That information can be accessed via the process id PID MailboxSize method
        • Total number of messages handled at a given time. That information can be accessed via the process id PID ReceivedCount method
        • Total number of restart. This is accessible via the process id PID RestartCount method
        • Total number of panic attacks. This is accessible via the process id PID ErrorsCount method
  • ActorSystem - Without an actor system, it is not possible to create actors in Go-Akt. Only a single actor system is allowed to be created per application when using Go-Akt. To create an actor system one just need to use the NewActorSystem method with the various options. Go-Akt ActorSystem has the following characteristics:
    • Actors lifecycle management (Spawn, Kill, ReSpawn)
    • Concurrency and Parallelism - Multiple actors can be managed and execute their tasks independently and concurrently. This helps utilize multicore processors efficiently.
    • Location Transparency - The physical location of actors is abstracted. Remote actors can be accessed via their address once remoting is enabled.
    • Fault Tolerance and Supervision - Set during the creation of the actor system.
    • Actor Addressing - Every actor in the ActorSystem has an address.
  • Message Passing - Communication between actors is achieved exclusively through message passing. In Go-Akt Google Protocol Buffers is used to define messages. The choice of protobuf is due to easy serialization over wire and strong schema definition.
  • Remoting - This helps remote messaging
  • Clustering - This offers simple scalability, partitioning (sharding), and re-balancing out-of-the-box. Go-Akt nodes are automatically discovered. See clustering.
  • Testkit - To help implement unit tests in GoAkt-based applications.
  • Observability - The actor and actor-system metrics as well traces are accessible via the integration with OpenTelemetry.
  • Logging Interface - Custom logger can be implemented
  • Mailbox Interface - Once can implement a custom mailbox. See Mailbox

Use Cases

  • Event-Driven programming
  • Event Sourcing and CQRS - eGo
  • Highly Available, Fault-Tolerant Distributed Systems

Installation

go get github.com/tochemey/goakt

Clustering

The cluster engine depends upon the discovery mechanism to find other nodes in the cluster. Under the hood, it leverages Olric to scale out and guarantee performant, reliable persistence, simple scalability, partitioning (sharding), and re-balancing out-of-the-box.

At the moment the following providers are implemented:

Note: One can add additional discovery providers using the following interface

In addition, one needs to set the following environment variables irrespective of the discovery provider to help identify the host node on which the cluster service is running:

  • NODE_NAME: the node name. For instance in kubernetes one can just get it from the metadata.name
  • NODE_IP: the node host address. For instance in kubernetes one can just get it from the status.podIP
  • GOSSIP_PORT: the gossip protocol engine port
  • CLUSTER_PORT: the cluster port to help communicate with other GoAkt nodes in the cluster
  • REMOTING_PORT: help remoting communication between actors
Operations Guide

The following outlines the cluster mode operations which can help have a healthy GoAkt cluster:

  • One can start a single node cluster or a multiple nodes cluster.
  • One can add more nodes to the cluster which will automatically discover the cluster.
  • One can remove nodes. However, to avoid losing data, one need to scale down the cluster to the minimum number of nodes which started the cluster.
Built-in Discovery Providers
Kubernetes Discovery Provider setup

To get the kubernetes discovery working as expected, the following pod labels need to be set:

  • app.kubernetes.io/part-of: set this label with the actor system name
  • app.kubernetes.io/component: set this label with the application name
  • app.kubernetes.io/name: set this label with the application name

In addition, each node is required to have three different ports open with the following ports name for the cluster engine to work as expected:

  • gossip-port: help the gossip protocol engine. This is actually the kubernetes discovery port
  • cluster-port: help the cluster engine to communicate with other GoAkt nodes in the cluster
  • remoting-port: help for remoting messaging between actors
Role Based Access

You’ll also have to grant the Service Account that your pods run under access to list pods. The following configuration can be used as a starting point. It creates a Role, pod-reader, which grants access to query pod information. It then binds the default Service Account to the Role by creating a RoleBinding. Adjust as necessary:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: pod-reader
rules:
  - apiGroups: [""] # "" indicates the core API group
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-pods
subjects:
  # Uses the default service account. Consider creating a new one.
  - kind: ServiceAccount
    name: default
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
Sample Project

A working example can be found here with a small doc showing how to run it.

mDNS Discovery Provider setup
  • Service Name: the service name
  • Domain: The mDNS discovery domain
  • Port: The mDNS discovery port
  • IPv6: States whether to lookup for IPv6 addresses.

Examples

Kindly check out the examples' folder.

Contribution

Contributions are welcome! The project adheres to Semantic Versioning and Conventional Commits. This repo uses Earthly.

To contribute please:

  • Fork the repository
  • Create a feature branch
  • Submit a pull request
Test & Linter

Prior to submitting a pull request, please run:

earthly +test

Benchmark Result

One can run the benchmark test: go test -bench=. -benchtime 2s -count 5 -benchmem -cpu 8 -run notest from the bench package

goos: darwin
goarch: arm64
pkg: github.com/tochemey/goakt/bench
BenchmarkActor/tell(send_only)-8         	 5521537	       421.7 ns/op	     176 B/op	       4 allocs/op
BenchmarkActor/tell(send_only)-8         	 5954017	       400.6 ns/op	     176 B/op	       4 allocs/op
BenchmarkActor/tell(send_only)-8         	 6015830	       425.8 ns/op	     176 B/op	       4 allocs/op
BenchmarkActor/tell(send_only)-8         	 5857168	       424.2 ns/op	     176 B/op	       4 allocs/op
BenchmarkActor/tell(send_only)-8         	 5609856	       426.0 ns/op	     176 B/op	       4 allocs/op
BenchmarkActor/ask(send/reply)-8         	 2770830	       851.1 ns/op	     552 B/op	      10 allocs/op
BenchmarkActor/ask(send/reply)-8         	 2818917	       851.3 ns/op	     552 B/op	      10 allocs/op
BenchmarkActor/ask(send/reply)-8         	 2980618	       853.3 ns/op	     552 B/op	      10 allocs/op
BenchmarkActor/ask(send/reply)-8         	 2830461	       859.2 ns/op	     552 B/op	      10 allocs/op
BenchmarkActor/ask(send/reply)-8         	 2893876	       828.0 ns/op	     552 B/op	      10 allocs/op
PASS
ok  	github.com/tochemey/goakt/bench	32.245s

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL