nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/test/scale_test.go (about) 1 // +build !race 2 // Copyright 2018 The Mangos Authors 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use file except in compliance with the License. 6 // You may obtain a copy of the license at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package test 17 18 // This simple test just fires off a crapton of inproc clients, to see 19 // how many connections we could handle. We do this using inproc, because 20 // we would absolutely exhaust TCP ports before we would hit any of the 21 // natural limits. The inproc transport has no such limits, so we are 22 // effectively just testing goroutine scalability, which is what we want. 23 // The intention is to demonstrate that mangos can address the C10K problem 24 // without breaking a sweat. 25 26 import ( 27 "errors" 28 "math/rand" 29 "sync" 30 "testing" 31 "time" 32 33 "nanomsg.org/go/mangos/v2" 34 "nanomsg.org/go/mangos/v2/protocol/rep" 35 "nanomsg.org/go/mangos/v2/protocol/req" 36 _ "nanomsg.org/go/mangos/v2/transport/inproc" 37 ) 38 39 func scalabilityClient(errp *error, loops int, wg *sync.WaitGroup) { 40 defer wg.Done() 41 sock, err := req.NewSocket() 42 if err != nil { 43 *errp = err 44 return 45 } 46 defer sock.Close() 47 if err := sock.Dial("inproc://atscale"); err != nil { 48 *errp = err 49 return 50 } 51 52 for i := 0; i < loops; i++ { 53 // Inject a random sleep to avoid pounding the CPU too hard. 54 time.Sleep(time.Duration(rand.Int31n(1000)) * time.Microsecond) 55 56 msg := mangos.NewMessage(3) 57 msg.Body = append(msg.Body, []byte("ping")...) 58 if err := sock.SendMsg(msg); err != nil { 59 *errp = err 60 return 61 } 62 63 if msg, err = sock.RecvMsg(); err != nil { 64 *errp = err 65 return 66 } 67 if string(msg.Body) != "pong" { 68 *errp = errors.New("response mismatch") 69 return 70 } 71 msg.Free() 72 } 73 } 74 75 func scalabilityServer(sock mangos.Socket) { 76 defer sock.Close() 77 for { 78 msg, e := sock.RecvMsg() 79 if e != nil { 80 return 81 } 82 msg.Body = append(msg.Body[:0], []byte("pong")...) 83 e = sock.SendMsg(msg) 84 if e != nil { 85 return 86 } 87 } 88 } 89 90 func TestScalability(t *testing.T) { 91 // Beyond this things get crazy. 92 // Note that the thread count actually indicates that you will 93 // have this many client sockets, and an equal number of server 94 // side pipes. On my Mac, 20K leads to around 30 sec to run the 95 // program, whereas 10k can run in under 10 sec. This proves we 96 // can handle 10K connections. 97 loops := 1 98 threads := 10000 99 100 errs := make([]error, threads) 101 102 ssock, e := rep.NewSocket() 103 if e != nil { 104 t.Fatalf("Cannot make server socket: %v", e) 105 } 106 if e = ssock.Listen("inproc://atscale"); e != nil { 107 t.Fatalf("Cannot listen: %v", e) 108 } 109 time.Sleep(time.Millisecond * 100) 110 go scalabilityServer(ssock) 111 wg := &sync.WaitGroup{} 112 wg.Add(threads) 113 for i := 0; i < threads; i++ { 114 go scalabilityClient(&errs[i], loops, wg) 115 } 116 117 wg.Wait() 118 for i := 0; i < threads; i++ { 119 if errs[i] != nil { 120 t.Fatalf("Test failed: %v", errs[i]) 121 } 122 } 123 }