[开源] gev(支持 websocket 啦): Go 实现基于 Reactor 模式的非阻塞网络库 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
xuxu555
V2EX    分享创造

[开源] gev(支持 websocket 啦): Go 实现基于 Reactor 模式的非阻塞网络库

  •  
  •   xuxu555
    Allenxuxu 2019-10-24 10:39:15 +08:00 3696 次点击
    这是一个创建于 2187 天前的主题,其中的信息可能已经有所发展或是发生改变。

    https://github.com/Allenxuxu/gev

    gev 是一个轻量、快速、高性能的基于 Reactor 模式的非阻塞网络库,底层并不使用 golang net 库,而是使用 epoll 和 kqueue。

    现在它支持 WebSocket 啦!

    支持定时任务,延时任务!

    特点

    • 基于 epoll 和 kqueue 实现的高性能事件循环
    • 支持多核多线程
    • 动态扩容 Ring Buffer 实现的读写缓冲区
    • 异步读写
    • SO_REUSEPORT 端口重用支持
    • 支持 WebSocket
    • 支持定时任务,延时任务

    性能测试

    测试环境 Ubuntu18.04

    • gev
    • gnet
    • eviop
    • evio
    • net (标准库)

    吞吐量测试

    null

    null

    evio 压测方式:

    限制 GOMAXPROCS=1,1 个 work 协程

    image.png

    限制 GOMAXPROCS=1,4 个 work 协程

    image.png

    限制 GOMAXPROCS=4,4 个 work 协程

    image.png

    安装

    go get -u github.com/Allenxuxu/gev 

    示例

    TCP

    package main import ( "flag" "strconv" "log" "github.com/Allenxuxu/gev" "github.com/Allenxuxu/gev/connection" "github.com/Allenxuxu/ringbuffer" ) type example struct{} func (s *example) OnConnect(c *connection.Connection) { log.Println(" OnConnect: ", c.PeerAddr()) } func (s *example) OnMessage(c *connection.Connection, buffer *ringbuffer.RingBuffer) (out []byte) { //log.Println("OnMessage") first, end := buffer.PeekAll() out = first if len(end) > 0 { out = append(out, end...) } buffer.RetrieveAll() return } func (s *example) OnClose() { log.Println("OnClose") } func main() { handler := new(example) var port int var loops int flag.IntVar(&port, "port", 1833, "server port") flag.IntVar(&loops, "loops", -1, "num loops") flag.Parse() s, err := gev.NewServer(handler, gev.Network("tcp"), gev.Address(":"+strconv.Itoa(port)), gev.NumLoops(loops)) if err != nil { panic(err) } s.Start() } 

    WebSocket

    package main import ( "flag" "github.com/Allenxuxu/gev/ws" "log" "math/rand" "strconv" "github.com/Allenxuxu/gev" "github.com/Allenxuxu/gev/connection" ) type example struct{} func (s *example) OnConnect(c *connection.Connection) { log.Println(" OnConnect: ", c.PeerAddr()) } func (s *example) OnMessage(c *connection.Connection, data []byte) (messageType ws.MessageType, out []byte) { log.Println("OnMessage:", string(data)) messageType = ws.MessageBinary switch rand.Int() % 3 { case 0: out = data case 1: if err := c.SendWebsocketData(ws.MessageText, data); err != nil { if e := c.CloseWebsocket(err.Error()); e != nil { panic(e) } } case 2: if e := c.CloseWebsocket("close"); e != nil { panic(e) } } return } func (s *example) OnClose(c *connection.Connection) { log.Println("OnClose") } func main() { handler := new(example) var port int var loops int flag.IntVar(&port, "port", 1833, "server port") flag.IntVar(&loops, "loops", -1, "num loops") flag.Parse() s, err := gev.NewWebSocketServer(handler, gev.Network("tcp"), gev.Address(":"+strconv.Itoa(port)), gev.NumLoops(loops)) if err != nil { panic(err) } s.Start() } 

    相关文章

    仓库地址: https://github.com/Allenxuxu/gev

    11 条回复    2019-10-26 13:10:15 +08:00
    zeromake
        1
    zeromake  
       2019-10-24 10:45:20 +08:00
    能解释一下为啥要内置定时能力,而不是让调用方使用外部库来实现呢?
    xuxu555
        2
    xuxu555  
    OP
       2019-10-24 10:49:21 +08:00
    @zeromake 其实并非内置,定时功能也是使用了外部库。 因为有小伙伴提了这个需求,所以就加上去了方便使用。
    agui2200
        3
    agui2200  
       2019-10-24 12:21:57 +08:00
    这个名字很有灵性啊
    xuxu555
        4
    xuxu555  
    OP
       2019-10-24 15:43:01 +08:00
    @agui2200 有种不好的感觉,啥灵性啊
    agui2200
        5
    agui2200  
       2019-10-24 16:10:04 +08:00
    @xuxu555 看到 gev 就想到 gay,(狗头
    xuxu555
        6
    xuxu555  
    OP
       2019-10-24 18:05:02 +08:00
    @agui2200 心里 gay 看什么都 gay
    codehz
        7
    codehz  
       2019-10-24 21:44:02 +08:00
    定时任务似乎没有使用 timerfd,这样就不能利用单一 epoll 的优势了(
    Aether
        8
    Aether  
       2019-10-25 12:03:30 +08:00
    定时内容都是放在内存里的,可能会丢失,是这样吗?
    xuxu555
        9
    xuxu555  
    OP
       2019-10-26 11:19:35 +08:00
    @Aether 是,丢失的情况是进程都挂了啊
    xuxu555
        10
    xuxu555  
    OP
       2019-10-26 11:21:44 +08:00
    @codehz 是的,timerfd 考虑过,但是考虑到 go 协程比线程廉价的多,开个协程搞个 timingwheel 实现定时更简洁方便。
    Aether
        11
    Aether  
       2019-10-26 13:10:15 +08:00
    @xuxu555 对。我发现类似解决方案有一个算是痛点的部分,就是有些需求是希望可以从中断恢复。之前看了一圈,比较轻量,开箱即用的解决方案似乎不多,或者说就没有……。然后这些方案肯定需要依赖外部数据储存,比如 redis 之类的。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2641 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 08:09 PVG 16:09 LAX 01:09 JFK 04:09
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86