** 原创文章,请勿转载 **
并发服务器是一个老生常谈的话题,今天这里也写一个。
1. 目标:
同时在线连接20万(c20w)。
开发语言:重要的事情说三遍,GOLANG, GOLANG, GOLANG!
那为什么是20W,不是30W或其它? 这个数字随意。 :)
2. 环境:
虚拟机(xenserver), 虚出6台机器(OS: CentOS 6.6 64bit) :
. 一台服务器8核CPU,2G内存
. 五台客户端2核CPU,2G内存
3. 改centos几个参数, 6台机器一样:
# ulimit -a
看 open files
改成300000(大于20W就行) :
# ulimit -n 300000
改端口范围
# echo 1025 65000 > /proc/sys/net/ipv4/ip_local_port_range
4. golang代码
服务端: server.go
package main import ( "log" "net" "sync" "time" ) func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":5000") if err != nil { log.Fatalln("net.ResolveTCPAddr fail", err) } listener, err := net.ListenTCP("tcp4", tcpAddr) if err != nil { log.Println("server failed to start...") return } defer listener.Close() go print() log.Println("begin listening, addr : ", tcpAddr) for { conn, err := listener.Accept() if err != nil { log.Println("socket accept failed. reason: ", err) continue } go handleConnection(conn) } } func print() { ticker := time.NewTicker(5 * time.Second) for { <-ticker.C log.Println(len(clients.Map)) } } var num = 0 var num2 = 0 var clients = Clients{Map: make(map[string]int, 0)} type Clients struct { sync.RWMutex Map map[string]int } func (c *Clients) Add(ip string) { c.Lock() c.Map[ip] = 1 c.Unlock() } func (c *Clients) Del(ip string) { c.Lock() delete(c.Map, ip) c.Unlock() } func handleConnection(conn net.Conn) { ip := conn.RemoteAddr().String() clients.Add(ip) buf := make([]byte, 64) for { _, err := conn.Read(buf) //log.Println("n=", n) if err != nil { //log.Println(err) conn.Close() clients.Del(ip) } } }
客户端: client.go
package main import ( "log" "net" ) func main() { for i := 0; i < 40000; i++ { conn, err := net.Dial("tcp", "x.x.x.x:5000") if err != nil { log.Println(err) return } go Read(conn) } log.Println("ok") select {} } func Read(conn net.Conn) { buf := make([]byte, 64) for { _, err := conn.Read(buf) if err != nil { log.Println(err) return } } }
结论:
开始时,服务器是2核,2G内存, 达到8W连接左右,接受新连接的速度就慢了。后来改成8核,20W连接无压力。
最终5个客户端,每个客户端发起40000个连接, 共20W连接。
服务器单进程, 接受20W个连接。CPU,内存压力都很小。
时间: 2024-10-14 06:22:26