Golang Websocket包测试指南

Golang Websocket包测试指南 我花了一个周末的时间编写了一个WebSocket库,但没想到它的性能表现会这么好。

ENV

env

RPS 基准测试

// 1000 connections, 500 messages/second, 1000 Byte Payload

tcpkali -c 1000 --connect-rate 500 -r 500 -T 30s -f assets/1K.txt --ws 127.0.0.1:${port}/connect

  • gws
Destination: [127.0.0.1]:8000

Interface lo address [127.0.0.1]:0

Using interface lo to connect to [127.0.0.1]:8000

Ramped up to 1000 connections.

Total data sent: 12919.8 MiB (13547411965 bytes)

Total data received: 12854.5 MiB (13478908970 bytes)

Bandwidth per channel: 7.178⇅ Mbps (897.2 kBps)

Aggregate bandwidth: 3594.175↓, 3612.441↑ Mbps

Packet rate estimate: 316194.9↓, 581166.7↑ (3↓, 2↑ TCP MSS/op)

Test duration: 30.0017 s.

  • gorilla
Destination: [127.0.0.1]:8001

Interface lo address [127.0.0.1]:0

Using interface lo to connect to [127.0.0.1]:8001

Ramped up to 1000 connections.

Total data sent: 7077.0 MiB (7420776528 bytes)

Total data received: 7089.8 MiB (7434174595 bytes)

Bandwidth per channel: 3.961⇅ Mbps (495.1 kBps)

Aggregate bandwidth: 1982.319↓, 1978.746↑ Mbps

Packet rate estimate: 272613.9↓, 173441.2↑ (2↓, 12↑ TCP MSS/op)

Test duration: 30.0019 s.

  • nhooyr
Destination: [127.0.0.1]:8002

Interface lo address [127.0.0.1]:0

Using interface lo to connect to [127.0.0.1]:8002

Ramped up to 1000 connections.

Total data sent: 5103.5 MiB (5351431830 bytes)

Total data received: 5140.6 MiB (5390317539 bytes)

Bandwidth per channel: 2.856⇅ Mbps (357.0 kBps)

Aggregate bandwidth: 1437.359↓, 1426.990↑ Mbps

Packet rate estimate: 135048.1↓, 124004.1↑ (1↓, 14↑ TCP MSS/op)

Test duration: 30.0012 s.

  • gobwas
Destination: [127.0.0.1]:8003

Interface lo address [127.0.0.1]:0

Using interface lo to connect to [127.0.0.1]:8003

Ramped up to 1000 connections.

Total data sent: 3364.6 MiB (3528061499 bytes)

Total data received: 3440.3 MiB (3607388324 bytes)

Bandwidth per channel: 1.893⇅ Mbps (236.7 kBps)

Aggregate bandwidth: 961.961↓, 940.808↑ Mbps

Packet rate estimate: 89305.6↓, 84530.8↑ (1↓, 18↑ TCP MSS/op)

Test duration: 30.0003 s.


更多关于Golang Websocket包测试指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang Websocket包测试指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


从你提供的基准测试结果来看,gws 的性能表现确实非常出色,在相同测试条件下显著优于其他主流 WebSocket 库。这主要得益于其高效的内存管理和并发处理设计。以下是一些关键的技术分析和测试建议:

性能优势分析

gws 的高性能主要来自这几个设计:

  1. 零拷贝技术:减少内存分配和复制开销
  2. 事件驱动架构:基于 epoll/kqueue 的高效 I/O 多路复用
  3. 内存池优化:重用缓冲区减少 GC 压力

完整的基准测试示例

这里提供一个更全面的性能测试示例,包含连接处理和消息吞吐:

package main

import (
    "log"
    "net/http"
    "time"
    "github.com/lxzan/gws"
)

// 简单的 Echo 服务器
func main() {
    upgrader := gws.NewUpgrader(&Handler{}, &gws.ServerOption{
        ReadAsyncEnabled: true, // 启用异步读取
        CompressEnabled:  true, // 启用压缩
    })
    
    http.HandleFunc("/connect", func(w http.ResponseWriter, r *http.Request) {
        socket, err := upgrader.Upgrade(w, r)
        if err != nil {
            return
        }
        socket.ReadLoop() // 开始读取循环
    })
    
    log.Fatal(http.ListenAndServe(":8000", nil))
}

type Handler struct{}

func (c *Handler) OnOpen(socket *gws.Conn) {
    log.Printf("连接建立: %s", socket.RemoteAddr())
}

func (c *Handler) OnClose(socket *gws.Conn, err error) {
    log.Printf("连接关闭: %v", err)
}

func (c *Handler) OnPing(socket *gws.Conn, payload []byte) {
    socket.WritePong(payload)
}

func (c *Handler) OnPong(socket *gws.Conn, payload []byte) {}

func (c *Handler) OnMessage(socket *gws.Conn, message *gws.Message) {
    defer message.Close()
    
    // Echo 消息回客户端
    socket.WriteMessage(message.Opcode, message.Bytes())
}

压力测试脚本

创建一个自动化测试脚本,模拟真实场景:

package test

import (
    "testing"
    "time"
    "github.com/gorilla/websocket"
    "github.com/lxzan/gws"
)

// 连接压力测试
func BenchmarkGWSConnections(b *testing.B) {
    // 启动服务器
    go startGWSServer()
    time.Sleep(100 * time.Millisecond)
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        // 建立连接
        conn, _, err := websocket.DefaultDialer.Dial("ws://localhost:8000/connect", nil)
        if err != nil {
            b.Fatal(err)
        }
        
        // 发送测试消息
        msg := make([]byte, 1024)
        conn.WriteMessage(websocket.BinaryMessage, msg)
        
        // 接收响应
        _, _, err = conn.ReadMessage()
        if err != nil {
            b.Fatal(err)
        }
        
        conn.Close()
    }
}

// 消息吞吐测试
func BenchmarkGWSThroughput(b *testing.B) {
    conn, _, _ := websocket.DefaultDialer.Dial("ws://localhost:8000/connect", nil)
    defer conn.Close()
    
    msg := make([]byte, 1024)
    b.ResetTimer()
    
    for i := 0; i < b.N; i++ {
        conn.WriteMessage(websocket.BinaryMessage, msg)
        _, _, err := conn.ReadMessage()
        if err != nil {
            b.Fatal(err)
        }
    }
}

func startGWSServer() {
    upgrader := gws.NewUpgrader(&gwsHandler{}, &gws.ServerOption{})
    http.HandleFunc("/connect", func(w http.ResponseWriter, r *http.Request) {
        socket, _ := upgrader.Upgrade(w, r)
        socket.ReadLoop()
    })
    http.ListenAndServe(":8000", nil)
}

type gwsHandler struct{}

func (h *gwsHandler) OnOpen(c *gws.Conn) {}
func (h *gwsHandler) OnClose(c *gws.Conn, err error) {}
func (h *gwsHandler) OnPing(c *gws.Conn, payload []byte) { c.WritePong(payload) }
func (h *gwsHandler) OnPong(c *gws.Conn, payload []byte) {}
func (h *gwsHandler) OnMessage(c *gws.Conn, message *gws.Message) {
    c.WriteMessage(message.Opcode, message.Bytes())
    message.Close()
}

内存使用监控

添加内存分析来验证 GC 效率:

func TestGWSMemoryUsage(t *testing.T) {
    var m1, m2 runtime.MemStats
    
    runtime.ReadMemStats(&m1)
    
    // 创建大量连接
    var conns []*gws.Conn
    for i := 0; i < 10000; i++ {
        // 模拟连接创建
    }
    
    runtime.GC()
    runtime.ReadMemStats(&m2)
    
    allocated := m2.TotalAlloc - m1.TotalAlloc
    t.Logf("内存分配: %.2f MB", float64(allocated)/1024/1024)
}

你的测试结果已经充分展示了 gws 的性能优势。通过上述更全面的测试方案,可以进一步验证库在不同场景下的稳定性。特别是在高并发连接和消息吞吐方面,gws 的设计确实带来了显著的性能提升。

回到顶部