V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
lesismal
V2EX  ›  Go 编程语言

nbio 近期的一些功能更新,来骗点 star

  •  1
     
  •   lesismal ·
    lesismal · 2022-11-04 16:24:45 +08:00 · 1317 次点击
    这是一个创建于 510 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目地址:

    陈年旧帖:

    支持 UDP

    因为标准库的 UDP 足够好用,所以之前一直没有支持 UDP ,但偶尔还是会有人问 UDP 相关,所以就干脆支持上了,并且相比于标准库和其他 Poller 框架有一点差别、nbio 的 UDP 更方便一些:

    1. 标准库或者其他 Poller 框架每次读数据返回的*UDPConn 是不同的,用户需要自己根据套接口四元组( server 端只需要取对端地址端口)再去做 Session 确认
    2. 在 nbio 中,同一个套接口四元组的 UDP Conn ,在 OnOpen/OnData/OnClose 时传给用户回调的是同一个*Conn 结构体,为用户省去了自己再封装的麻烦

    支持 Unix Socket

    其实本来也是支持的,但需要用户自己进行 Listen ,然后通过 nbio.Engine.AddConn 来实现,现在支持了 NewEngine 时配置 unix 地址的方式,更方便。

    HTTP1.x/Websocket 支持多 IO 模式

    这个是近期较大的更新,主要支持了三种 IO 模式。

    这种支持,缘起自去年鸟窝老师的 2021 年 Go 生态圈 rpc 框架 benchmark 中的讨论,当时有想到这种阻塞与非阻塞 IO 混合使用的方案,以此来提高常规在线量时的相应性能,承载高在线时保持低占用、较好的响应性能和稳定性。

    Poller 框架,IO 与逻辑协程池是分离的,相比于标准库的每个连接至少一个协程循环读取的方案存在较大的差别: | 方案 | 标准库 | Poller | | --------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | 协程数量 | 每个连接至少一个协程 | 数量可控的 IO 协程池与逻辑协程池处理所有连接 | | 协议解析 /编解码 | 同步读取和解析,逻辑更简单,不需要考虑半包的缓存与拼接等 | 异步解析器,逻辑复杂,需要处理半包缓存与拼接 | | buffer 优化 | 同一个协程内循环,one-by-one 读取和解析,buffer 自然复用,如果消息体不大,buffer 为栈内存 | IO 与逻辑协程分离,跨协程 buffer 生命周期管理、复用难度大 | | 内存占用 | 每个连接至少一个协程,高在线量时内存占用高 | 协程数量可控,可以做到 Conn 无请求时不持有 buffer ,内存占用低 | | GC/STW | 高在线量时协程数量变量数量内存占用三高,GC 开销大,容易 STW/OOM | 协程、变量、buffer 数量均可控,GC 、内存都比较稳定,能承载更高在线数 | | 性能 | 在线量不高时响应性能更好,高在线则不稳定 | 简单测试中,在线量不高时响应性能可能不比标准库方案好,实际 IO 场景可能好于标准库;高在线时仍能稳定响应、优于标准库 |

    支持了三种模式后: | IOMod | 说明 | | ---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | IOModNonBlocking | 与原来的纯 Poller 方案没什么区别 | | IOModBlocking | 阻塞模式下,所有连接使用至少一个协程来处理读,Websocket 提供了配置项来开启第二个协程处理写、以此避免广播场景下单个连接写阻塞导致其他连接的等待 | | IOModMixed | 设置了这种模式,还可以通过 Engine.MaxBlockingOnline 来设置阻塞 IO 的连接数量阈值,如果当前阻塞模式处理的连接数量小于这个阈值,则新连接也由阻塞模式处理,否则由 Poller 异步 IO 的方式处理 |

    IOModBlocking 的优势是低 /普通在线场景获得更好的响应性能,我在简单压测中,nbio 的 http1.x 好于标准库,websocket 略好于 gorilla/websocket 。 IOModMixed 的目标是在不同场景、服务活跃程度和负载期间获取更好的性能与资源消耗的平衡,能够承载更大在线量并保持地占用和稳定性,在线数不高时响应性能更高。

    另外,Websocket 也支持了标准库 http server ,使用方式也简单,例子如下:

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    
    	"github.com/lesismal/nbio/nbhttp/websocket"
    )
    
    func echo(w http.ResponseWriter, r *http.Request) {
    	u := websocket.NewUpgrader()
    	u.OnMessage(func(c *websocket.Conn, mt websocket.MessageType, data []byte) {
    		c.WriteMessage(mt, data)
    	})
    	_, err := u.Upgrade(w, r, nil)
    	if err != nil {
    		log.Print("upgrade:", err)
    		return
    	}
    }
    
    func main() {
    	mux := &http.ServeMux{}
    	mux.HandleFunc("/ws", echo)
    	server := http.Server{
    		Addr:    "localhost:8080",
    		Handler: mux,
    	}
    	fmt.Println("server exit:", server.ListenAndServe())
    }
    

    The websocket now also support std http server, and I got a better performance and lower mem/cpu cost than std in a simple load test. The example of using with std http server would be like this:

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    
    	"github.com/lesismal/nbio/nbhttp/websocket"
    )
    
    func echo(w http.ResponseWriter, r *http.Request) {
    	u := websocket.NewUpgrader()
    	u.OnMessage(func(c *websocket.Conn, mt websocket.MessageType, data []byte) {
    		c.WriteMessage(mt, data)
    	})
    	_, err := u.Upgrade(w, r, nil)
    	if err != nil {
    		log.Print("upgrade:", err)
    		return
    	}
    }
    
    func main() {
    	mux := &http.ServeMux{}
    	mux.HandleFunc("/ws", echo)
    	server := http.Server{
    		Addr:    "localhost:8080",
    		Handler: mux,
    	}
    	fmt.Println("server exit:", server.ListenAndServe())
    }
    
    2 条回复    2023-04-18 14:04:25 +08:00
    blackvv666
        1
    blackvv666  
       346 天前   ❤️ 1
    牛!!看源码学习
    lesismal
        2
    lesismal  
    OP
       345 天前
    @blackvv666 感谢支持,欢迎交流,有建议、疑问、bug 之类的随时来 issue
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5824 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 01:55 · PVG 09:55 · LAX 18:55 · JFK 21:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.