dongzi9196 2015-10-11 08:30
浏览 278

GO:在简单的TCP服务器上超过10000线程?

I need to write a tcp server which can handle more than 500k connections.

I wrote a simple server on golang, but when connections more than 10k, the server crashed with the error message "runtime: program exceeds 10000-thread limit fatal error: thread exhaustion".

Server runs in last linux build. That go can use epoll for tcp connection, to make it async and use few fd. So why does the server exceed the thread limit?!

My simple server:

package main
import (
    "strconv"
    "net"
    "log"
    "time"
    "bufio"
    "io"
)

type Handler struct {
    conn   net.Conn
    closed chan bool
}

func (h *Handler) Listen() { // listen connection for incomming data
    defer h.conn.Close()
    bf := bufio.NewReader(h.conn)
    for {
        line, _, err := bf.ReadLine()
        if err != nil {
            if err == io.EOF {
                log.Println("End connection")
            }
            h.closed <- true // send to dispatcher, that connection is closed
            return
        }

        // ... some business logic with data
    }
}

type Dispatcher struct {
    handlers map[string]*Handler `map[ip]*Handler`
}

func (d *Dispatcher) AddHandler(conn net.Conn) {
    addr := conn.RemoteAddr().String()
    handler := &Handler{conn, make(chan bool, 1)}
    d.handlers[addr] = handler

    go handler.Listen()

    <-handler.closed // when connection closed, remove handler from handlers
    delete(d.handlers, addr)
}

func (d *Dispatcher) ListenHandlers(port int) {
    sport := strconv.Itoa(port)

    ln, err := net.Listen("tcp", ":" + sport)
    if err != nil {
        log.Println(err)
        return
    }

    defer ln.Close()

    for {
        conn, err := ln.Accept() // accept connection
        if err != nil {
            log.Println(err)
            continue
        }

        tcpconn := conn.(*net.TCPConn)
        tcpconn.SetKeepAlive(true)
        tcpconn.SetKeepAlivePeriod(10 * time.Second)

        go d.AddHandler(conn)
    }
}

func main() {
    dispatcher := &Dispatcher{make(map[string]*Handler)}
    dispatcher.ListenHandlers(3000)
}

Update 11.10.2015
The problem was that https://github.com/felixge/tcpkeepalive library. Please do not use it :)

  • 写回答

1条回答 默认 最新

  • dongyi9082 2015-11-19 15:30
    关注

    The problem was that https://github.com/felixge/tcpkeepalive library. This library get socket file descriptor (fd), copy then and worked with new fd, which running in blocked mode. Therefore, go created new thread on every connect. Go don't kill created thread (because this is native golang behavior), and after some times go failed with "Exceeds 10000-thread". That's it ! Please do not use it :)

    评论

报告相同问题?

悬赏问题

  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题
  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度
  • ¥15 c# 使用NPOI快速将datatable数据导入excel中指定sheet,要求快速高效
  • ¥15 再不同版本的系统上,TCP传输速度不一致
  • ¥15 高德地图2.0 版本点聚合中Marker的位置无法实时更新,如何解决呢?
  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题