istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/loadbalancersim/mesh/node.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mesh 16 17 import ( 18 "math" 19 "time" 20 21 "istio.io/istio/pkg/test/loadbalancersim/locality" 22 "istio.io/istio/pkg/test/loadbalancersim/network" 23 "istio.io/istio/pkg/test/loadbalancersim/timer" 24 "istio.io/istio/pkg/test/loadbalancersim/timeseries" 25 ) 26 27 var _ network.Connection = &Node{} 28 29 const maxQLatency = 30 * time.Second 30 31 type Node struct { 32 locality locality.Instance 33 helper *network.ConnectionHelper 34 q *timer.Queue 35 serviceTime time.Duration 36 qLatencyEnabled bool 37 qLength timeseries.Instance 38 qLatency timeseries.Instance 39 } 40 41 func newNode(name string, serviceTime time.Duration, enableQueueLatency bool, l locality.Instance) *Node { 42 return &Node{ 43 locality: l, 44 helper: network.NewConnectionHelper(name), 45 q: timer.NewQueue(), 46 serviceTime: serviceTime, 47 qLatencyEnabled: enableQueueLatency, 48 } 49 } 50 51 func (n *Node) Name() string { 52 return n.helper.Name() 53 } 54 55 func (n *Node) QueueLength() *timeseries.Instance { 56 return &n.qLength 57 } 58 59 func (n *Node) QueueLatency() *timeseries.Instance { 60 return &n.qLatency 61 } 62 63 func (n *Node) calcRequestDuration() time.Duration { 64 // Get the current queue length. 65 qLen := n.q.Len() 66 qLatency := n.calcQLatency(qLen) 67 68 // Add the observations 69 tnow := time.Now() 70 n.qLength.AddObservation(float64(qLen), tnow) 71 n.qLatency.AddObservation(qLatency.Seconds(), tnow) 72 73 return n.serviceTime + qLatency 74 } 75 76 func (n *Node) calcQLatency(qlen int) time.Duration { 77 if !n.qLatencyEnabled { 78 return 0 79 } 80 81 // Compute the queue latency in milliseconds. 82 latency := math.Pow(1.2, float64(qlen+1)) 83 84 // Clip the latency at the maximum value. 85 clippedLatency := math.Min(latency, float64(maxQLatency.Milliseconds())) 86 87 // Return the latency as milliseconds. 88 return time.Duration(clippedLatency) * time.Millisecond 89 } 90 91 func (n *Node) TotalRequests() uint64 { 92 return n.helper.TotalRequests() 93 } 94 95 func (n *Node) ActiveRequests() uint64 { 96 return n.helper.ActiveRequests() 97 } 98 99 func (n *Node) Latency() *timeseries.Instance { 100 return n.helper.Latency() 101 } 102 103 func (n *Node) Request(onDone func()) { 104 n.helper.Request(func(wrappedOnDone func()) { 105 deadline := time.Now().Add(n.calcRequestDuration()) 106 107 // Schedule the done function to be called after the deadline. 108 n.q.Schedule(wrappedOnDone, deadline) 109 }, onDone) 110 } 111 112 func (n *Node) Locality() locality.Instance { 113 return n.locality 114 } 115 116 func (n *Node) ShutDown() { 117 n.q.ShutDown() 118 } 119 120 type Nodes []*Node 121 122 func (nodes Nodes) Select(match locality.Match) Nodes { 123 var out Nodes 124 for _, n := range nodes { 125 if match(n.locality) { 126 out = append(out, n) 127 } 128 } 129 return out 130 } 131 132 func (nodes Nodes) Latency() *timeseries.Instance { 133 var out timeseries.Instance 134 for _, n := range nodes { 135 out.AddAll(n.Latency()) 136 } 137 return &out 138 } 139 140 func (nodes Nodes) QueueLatency() *timeseries.Instance { 141 var out timeseries.Instance 142 for _, n := range nodes { 143 out.AddAll(n.QueueLatency()) 144 } 145 return &out 146 } 147 148 func (nodes Nodes) TotalRequests() uint64 { 149 var out uint64 150 for _, n := range nodes { 151 out += n.TotalRequests() 152 } 153 return out 154 } 155 156 func (nodes Nodes) ShutDown() { 157 for _, n := range nodes { 158 n.ShutDown() 159 } 160 }