libgo高性能网络服务器,gnet: 轻量级且高性能的 Golang 网络库

6b77de15c68d82fcfe2d5de492c0c721.png

gnet?style=flat-square

gnet?style=flat-square

1

1

api-reference-blue.svg?style=flat-square

gnet.svg?style=flat-square

项目主页

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

简介

gnet 是一个基于 Event-Loop 事件驱动的高性能和轻量级网络库。这个库直接使用 epoll 和 kqueue 系统调用而非标准 Golang 网络包:net 来构建网络应用,它的工作原理类似两个开源的网络库:libuv 和 libevent。

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

gnet 的亮点在于它是一个高性能、轻量级、非阻塞的纯 Go 实现的传输层(TCP/UDP/Unix-Socket)网络库,开发者可以使用 gnet 来实现自己的应用层网络协议,从而构建出自己的应用层网络应用:比如在 gnet 上实现 HTTP 协议就可以创建出一个 HTTP 服务器 或者 Web 开发框架,实现 Redis 协议就可以创建出自己的 Redis 服务器等等。

gnet 衍生自另一个项目:evio,但是性能更好。

功能

高性能 的基于多线程模型的 Event-Loop 事件驱动

内置 Round-Robin 轮询负载均衡算法

简洁的 APIs

基于 Ring-Buffer 的高效内存利用

支持多种网络协议:TCP、UDP、Unix Sockets

支持两种事件驱动机制:Linux 里的 epoll 以及 FreeBSD 里的 kqueue

支持异步写操作

允许多个网络监听地址绑定在一个 Event-Loop 上

灵活的事件定时器

SO_REUSEPORT 端口重用

核心设计

多线程模型

gnet 重新设计开发了一个新内置的多线程模型:『主从 Reactor 多线程』,这也是 netty 默认的线程模型,下面是这个模型的原理图:

544c59f2e65f71277a5e8f096e9d00b2.png

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

66fcd728811f1c9d974df3e0ab7983c7.png

现在我正在 gnet 里开发一个新的多线程模型:『带线程/go程池的主从 Reactors 多线程』,并且很快就能完成,这个模型的架构图如下所示:

b9cfaf306051200485c5c92b8190967d.png

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

2a8b34d4c5e59aa7699516b1685f5dfa.png

通信机制

gnet 的『主从 Reactors 多线程』模型是基于 Golang 里的 Goroutines的,一个 Reactor 挂载在一个 Goroutine 上,所以在 gnet 的这个网络模型里主 Reactor/Goroutine 与从 Reactors/Goroutines 有海量通信的需求,因此 gnet 里必须要有一个能在 Goroutines 之间进行高效率的通信的机制,我没有选择 Golang 里的主流方案:基于 Channel 的 CSP 模型,而是选择了性能更好、基于 Ring-Buffer 的 Disruptor 方案。

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

自动扩容的 Ring-Buffer

gnet 利用 Ring-Buffer 来缓存 TCP 流数据以及管理内存使用。

e092378989bb8559184d529ec12d9635.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 目前支持的 I/O 事件如下:

OnInitComplete 当 server 初始化完成之后调用。

OnOpened 当连接被打开的时候调用。

OnClosed 当连接被关闭的时候调用。

OnDetached 当主动摘除连接的时候的调用。

React 当 server 端接收到从 client 端发送来的数据的时候调用。(你的核心业务代码一般是写在这个方法里)

Tick 服务器启动的时候会调用一次,之后就以给定的时间间隔定时调用一次,是一个定时器方法。

PreWrite 预先写数据方法,在 server 端写数据回 client 端之前调用。

性能测试

Linux (epoll)

系统参数

Go Version: go1.12.9 linux/amd64

OS: Ubuntu 18.04

CPU: 8 Virtual CPUs

Memory: 16.0 GiB

复制代码

Echo Server

abe47e3eab52b7800d01e14e42d46be8.png

HTTP Server

804083b5f3afdac88ab0d3e486c47307.png

FreeBSD (kqueue)

系统参数

Go Version: go version go1.12.9 darwin/amd64

OS: macOS Mojave 10.14.6

CPU: 4 CPUs

Memory: 8.0 GiB

复制代码

Echo Server

42d98a8ed2d10ebe7837692f65fe458f.png

HTTP Server

2c540823b27c08adb5cffd4ff83b40cf.png

证书

gnet 的源码允许用户在遵循 MIT 开源证书 规则的前提下使用。

待做事项

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

有疑问加站长微信联系(非本文作者)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值