gain 基于io_uring 的golang 网络框架
io_uring 是linux kernel 从5.1开始支持的新的io 操作模式,性能很不错,gain 是一个golang 实现
参考使用
- main.go
package main
import (
"fmt"
"log"
"net"
"os"
"sync/atomic"
"time"
"github.com/pawelgaczynski/gain"
"github.com/pawelgaczynski/gain/logger"
"github.com/rs/zerolog"
)
const (
port = 8080
numberOfClients = 2
)
var testData = []byte("echo")
type EventHandler struct {
server gain.Server
logger zerolog.Logger
overallBytesSent atomic.Uint64
}
func (e *EventHandler) OnStart(server gain.Server) {
e.server = server
e.logger = zerolog.New(os.Stdout).With().Logger().Level(zerolog.InfoLevel)
}
func (e *EventHandler) OnAccept(conn gain.Conn) {
e.logger.Info().
Int("active connections", e.server.ActiveConnections()).
Str("remote address", conn.RemoteAddr().String()).
Msg("New connection accepted")
}
func (e *EventHandler) OnRead(conn gain.Conn, n int) {
e.logger.Info().
Int("bytes", n).
Str("remote address", conn.RemoteAddr().String()).
Msg("Bytes received from remote peer")
var (
err error
buffer []byte
)
buffer, err = conn.Next(n)
if err != nil {
return
}
_, _ = conn.Write(buffer)
}
func (e *EventHandler) OnWrite(conn gain.Conn, n int) {
e.overallBytesSent.Add(uint64(n))
e.logger.Info().
Int("bytes", n).
Str("remote address", conn.RemoteAddr().String()).
Msg("Bytes sent to remote peer")
err := conn.Close()
if err != nil {
e.logger.Error().Err(err).Msg("Error during connection close")
}
}
func (e *EventHandler) OnClose(conn gain.Conn, err error) {
log := e.logger.Info().
Str("remote address", conn.RemoteAddr().String())
if err != nil {
log.Err(err).Msg("Connection from remote peer closed")
} else {
log.Msg("Connection from remote peer closed by server")
}
if e.overallBytesSent.Load() >= uint64(len(testData)*numberOfClients) {
e.server.AsyncShutdown()
}
}
func runClients() {
for i := 0; i < numberOfClients; i++ {
go func() {
time.Sleep(time.Second)
conn, err := net.DialTimeout("tcp", fmt.Sprintf("127.0.0.1:%d", port), time.Second)
if err != nil {
log.Panic(err)
}
n, err := conn.Write(testData)
if err != nil {
log.Panic()
}
if n != len(testData) {
log.Panic()
}
buffer := make([]byte, len(testData))
n, err = conn.Read(buffer)
if err != nil {
log.Panic()
}
if n != len(testData) {
log.Panic()
}
}()
}
}
func main() {
// runClients()
err := gain.ListenAndServe(
fmt.Sprintf("tcp://0.0.0.0:%d", port), &EventHandler{}, gain.WithLoggerLevel(logger.WarnLevel))
if err != nil {
log.Panic(err)
}
}
以上代码会创建server,监听在8080 端口,对于测试,可以通过telnet 发送echo 数据,如果有异常的服务会关闭
说明
基于io_uring 的网络框架已经有不少了,但是目前国内一般linux kernel 版本都不太高,所以基本上使用是有些问题的
参考资料
https://github.com/pawelgaczynski/gain
https://en.wikipedia.org/wiki/Io_uring
https://developers.redhat.com/articles/2023/04/12/why-you-should-use-iouring-network-io
https://medium.com/better-programming/an-introduction-to-gain-part-1-writing-high-performance-tcp-application-df5f7253e54a
https://betterprogramming.pub/gain-the-new-fastest-go-tcp-framework-40ec111d40e6
https://blog.vmsplice.net/2020/07/rethinking-event-loop-integration-for.html