0a04a9e18e73420ea9bd785ea0588049.png

项目主页

https://github.com/panjf2000/gnet

欢迎大家围观~~,目前还在持续更新,感兴趣的话可以 star 一下暗中观察哦。

简介

gnet

这个项目存在的价值是提供一个在网络包处理方面能和 Redis[6]、Haproxy[7] 这两个项目具有相近性能的Go 语言网络服务器框架。

gnetgnetgnet
gnetevio

功能

•高性能[8] 的基于多线程模型的 Event-Loop 事件驱动•内置 Round-Robin 轮询负载均衡算法•简洁的 APIs•基于 Ring-Buffer 的高效内存利用•支持多种网络协议:TCP、UDP、Unix Sockets•支持两种事件驱动机制:Linux 里的 epoll 以及 FreeBSD 里的 kqueue•支持异步写操作•允许多个网络监听地址绑定在一个 Event-Loop 上•灵活的事件定时器•SO_REUSEPORT 端口重用

核心设计

多线程模型

gnetnetty

e8c7882d7d1eece7735d4a6a934a6ca5.png

它的运行流程如下面的时序图:

b2a6d3f732ae097cbae7ad48a2dd7d63.png

gnet

1899efce62cb60ec42d01635b74e025b.png

它的运行流程如下面的时序图:

2febea561f731f020074991c38685129.png

通信机制

gnetgnetgnet

所以我最终选择了 go-disruptor[9]:高性能消息分发队列 LMAX Disruptor 的 Golang 实现。

自动扩容的 Ring-Buffer

gnet

0621480054639a5e1d4678c0d94dc901.gif

开始使用

安装

$ go get -u github.com/panjf2000/gnet

使用示例

// ======================== Echo Server implemented with gnet ===========================

package main

import (
    "flag"
    "fmt"
    "log"
    "strings"

    "github.com/panjf2000/gnet"
    "github.com/panjf2000/gnet/ringbuffer"
)

func main() {
    var port int
    var loops int
    var udp bool
    var trace bool
    var reuseport bool

    flag.IntVar(&port, "port", 5000, "server port")
    flag.BoolVar(&udp, "udp", false, "listen on udp")
    flag.BoolVar(&reuseport, "reuseport", false, "reuseport (SO_REUSEPORT)")
    flag.BoolVar(&trace, "trace", false, "print packets to console")
    flag.IntVar(&loops, "loops", 0, "num loops")
    flag.Parse()

    var events gnet.Events
    events.NumLoops = loops
    events.OnInitComplete = func(srv gnet.Server) (action gnet.Action) {
        log.Printf("echo server started on port %d (loops: %d)", port, srv.NumLoops)
        if reuseport {
            log.Printf("reuseport")
        }
        return
    }
    events.React = func(c gnet.Conn, inBuf *ringbuffer.RingBuffer) (out []byte, action gnet.Action) {
        top, tail := inBuf.PreReadAll()
        out = append(top, tail...)
        inBuf.Reset()

        if trace {
            log.Printf("%s", strings.TrimSpace(string(top)+string(tail)))
        }
        return
    }
    scheme := "tcp"
    if udp {
        scheme = "udp"
    }
    log.Fatal(gnet.Serve(events, fmt.Sprintf("%s://:%d", scheme, port)))
}

I/O 事件

gnet
OnInitCompleteOnOpenedOnClosedOnDetachedReactTickPreWrite

性能测试

Linux (epoll)

系统参数

Go Version: go1.12.9 linux/amd64OS:         Ubuntu 18.04CPU:        8 Virtual CPUsMemory:     16.0 GiB

Echo Server

f79da4bf04b99dba435092b74b2d16c3.png

HTTP Server

50e1e129de0e8f4745beaec580c83942.png

FreeBSD (kqueue)

系统参数

Go Version: go version go1.12.9 darwin/amd64OS:         macOS Mojave 10.14.6CPU:        4 CPUsMemory:     8.0 GiB

Echo Server

1a892673d2af1a72a62fe8a367e5242e.png

HTTP Server

7ba312814602b0041146d234c2b70b39.png

证书

gnet

待做事项

gnet 还在持续开发的过程中,所以这个仓库的代码和文档会一直持续更新,如果你对 gnet 感兴趣的话,欢迎给这个开源库贡献你的代码~~

References

[1][2][3][4][5][6][7][8][9][10]