多年来,Erlang/OTP的技术和设计模式得到了验证。现在在戈朗。在网络消息传递方面,比原始的Erlang/OTP快5倍。在Golang中创建OTP-designed应用程序的最简单方法。

Purpose

gen.Servergen.Supervisorgen.Application

Features

image

gen.Servergen.Supervisorgen.Applicationgen.Stagegen.Servergo run ./examples/genstagegen.Sagagen.Sagagen.Raftgen_server:callgen_server:casterlang:sendServerProcess.CallServerProcess.CastProcess.Sendetf.TermIntoStructetf.TermProplistIntoStructetf.TermToStringMarshalUnmarshal

Requirements

  • 转到1.17.x及以上

Versioning

Golang不久前引入了v2规则来解决复杂的依赖性问题。我们发现这个解决方案非常有争议,围绕它还有很多讨论。因此,我们决定保留旧的版本控制方式,但必须使用git标记和v1作为主要版本(由于“v2规则”的限制)。从现在起,我们使用git标记模式1.999.XYZ,其中X-大号,Y-小号,Z-补丁版本。

Changelog

以下是最新版本的更改。有关更多详细信息,请参阅变更日志

v2.1.0 2022-04-19 [tag version v1.999.210]

gen.ProcessSetCompression(enable bool)Compression() boolSetCompressionLevel(level int) boolCompressionLevel() intSetCompressionThreshold(threshold int) boolCompressionThreshold() intnode.OptionsCompressionnode.NodeAddProxyRoute(...)RemoveProxyRoute(...)ProxyRoute(...)ProxyRoutes()NodesIndirect()node.OptionsProxygen.RaftResolverHandshakeProtogen.ProcessNodeUptime()NodeName()NodeStop()gen.ServerProcessMessageCounter()gen.Servergen.ProcessOptionsProcessFallbackgen.MessageFallbackgen.SupervisorChildSpecgen.ApplicationChildSpecgen.ProcessOptionsgen.Process.Sendgen.ServerProcess.Castgen.ServerProcess.Callnode.ErrProcessIncarnationgen.MessageDownincarnationgen.EnvKeynode.EnvKeyNodenode.Nodenode.Options

Benchmarks

下面是一个简单的端到端测试,演示了消息传递子系统的性能

硬件:配备AMD RyzenThreadripper3970X(64)@3.700GHz的工作站

❯❯❯❯ go test -bench=NodeParallel -run=XXX -benchtime=10s
goos: linux
goarch: amd64
pkg: github.com/ergo-services/ergo/tests
cpu: AMD Ryzen Threadripper 3970X 32-Core Processor
BenchmarkNodeParallel-64                 4738918              2532 ns/op
BenchmarkNodeParallelSingleNode-64      100000000              429.8 ns/op

PASS
ok      github.com/ergo-services/ergo/tests  29.596s

这些数字显示,对于通过本地主机的网络消息传递,每秒几乎有500.000个同步请求,对于本地消息传递(在节点内),每秒有10.000.000个同步请求。

Compression

该基准测试显示了(通过网络)在两个节点之间发送1MB消息的压缩性能。

❯❯❯❯ go test -bench=NodeCompression -run=XXX -benchtime=10s
goos: linux
goarch: amd64
pkg: github.com/ergo-services/ergo/tests
cpu: AMD Ryzen Threadripper 3970X 32-Core Processor
BenchmarkNodeCompressionDisabled1MBempty-64         2400           4957483 ns/op
BenchmarkNodeCompressionEnabled1MBempty-64          5769           2088051 ns/op
BenchmarkNodeCompressionEnabled1MBstring-64         5202           2077099 ns/op
PASS
ok      github.com/ergo-services/ergo/tests     56.708s

它显示出2倍以上的改善。

Proxy

该基准测试演示了代理功能和e2e加密如何影响消息传递性能。

❯❯❯❯ go test -bench=NodeProxy -run=XXX -benchtime=10s
goos: linux
goarch: amd64
pkg: github.com/ergo-services/ergo/tests
cpu: AMD Ryzen Threadripper 3970X 32-Core Processor
BenchmarkNodeProxy_NodeA_to_NodeC_direct_Message_1KB-64                     1908477       6337 ns/op
BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1KB-64                  1700984       7062 ns/op
BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1KB_Encrypted-64        1271125       9410 ns/op
PASS
ok      github.com/ergo-services/ergo/tests     45.649s


Ergo框架与原始Erlang/OTP

硬件:配备Intel(R)Core(TM)i5-8265U(4核。8核,配备HT)的笔记本电脑

benchmarks

这些基准的来源如下

EPMD

Ergo框架嵌入了EPMD实现,以便在不需要外部EPMD过程的情况下运行您的节点。默认情况下,它作为客户端与erlang的epmd守护进程或其他ergo节点一起工作。

使嵌入式EPMD不同的一点是处理连接挂起的行为——如果ergo节点作为EPMD客户端运行,并且连接丢失,它会尝试运行自己的嵌入式EPMD服务或恢复丢失的连接。

Observer

这是一个标准的Erlang工具。观测器是一种用于观察Erlang系统特性的图形工具。刀具观察器显示系统信息、应用程序监控器树和过程信息。

在这里,您可以使用以下示例之一看到此功能的实际应用:

observer demo

Examples

下面的代码是gen.Server模式示例/simple的简单实现

package main

import (
	"fmt"
	"time"

	"github.com/ergo-services/ergo"
	"github.com/ergo-services/ergo/etf"
	"github.com/ergo-services/ergo/gen"
	"github.com/ergo-services/ergo/node"
)

// simple implementation of Server
type simple struct {
	gen.Server
}

func (s *simple) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
	value := message.(int)
	fmt.Printf("HandleInfo: %#v \n", message)
	if value > 104 {
		return gen.ServerStatusStop
	}
	// sending message with delay
	process.SendAfter(process.Self(), value+1, time.Duration(1*time.Second))
	return gen.ServerStatusOK
}

func main() {
	// create a new node
	node, _ := ergo.StartNode("node@localhost", "cookies", node.Options{})

	// spawn a new process of gen.Server
	process, _ := node.Spawn("gs1", gen.ProcessOptions{}, &simple{})

	// send a message to itself
	process.Send(process.Self(), 100)

	// wait for the process termination.
	process.Wait()
	fmt.Println("exited")
	node.Stop()
}

这是这个代码的输出

$ go run ./examples/simple
HandleInfo: 100
HandleInfo: 101
HandleInfo: 102
HandleInfo: 103
HandleInfo: 104
HandleInfo: 105
exited
examples/
  • 具有TLS的节点
  • 具有HTTP服务器的节点

Elixir Phoenix Users

Elixir Phoenix框架的用户在尝试将Phoenix节点连接到ergo节点时可能会遇到超时。原因是,除了global_name_server和net_kernel之外,Phoenix还试图将消息广播到pg2 PubSub处理程序

要使用Phoenix节点,您必须创建并注册一个专用的pg2 GenServer,并在节点内生成它。生成进程必须将“pg2”作为进程名称:

type Pg2GenServer struct {
    gen.Server
}

func main() {
    // ...
    pg2 := &Pg2GenServer{}
    node1, _ := ergo.StartNode("node1@localhost", "cookies", node.Options{})
    process, _ := node1.Spawn("pg2", gen.ProcessOptions{}, pg2, nil)
    // ...
}

开发和调试

您可能希望使用已经定义的选项

-ergo.trace-ergo.norecover-ergo.warning
go rungo build--tags debug
go run --tags debug ./examples/genserver/demoGenServer.go

http://localhost:9009/debug/pprof

要检查测试覆盖率:

go test -coverprofile=cover.out ./...
go tool cover -html=cover.out -o coverage.html

要使用清理的测试缓存运行测试,请执行以下操作:

go vet
go clean -testcache
go test -v ./...

要运行基准测试:

go test -bench=Node -run=X -benchmem

公司正在使用Ergo框架

Kaspersky RingCentral LilithGames

你的公司使用Ergo吗?在此处添加您的公司徽标/名称

Commercial support