10000 weighTargets computes the share of traffic each target receives based on its weight and the weight of the other targets. Traffic is first distributed to targets with a fixed weight. If the sum of all fixed weights exceeds 100% then they are normalized to 100%. Targets with a dynamic weight w
()
| 211 | // Targets with a dynamic weight will receive an equal share of the remaining |
| 212 | // traffic if there is any left. |
| 213 | func (r *Route) weighTargets() { |
| 214 | // how big is the fixed weighted traffic? |
| 215 | var nFixed int |
| 216 | var sumFixed float64 |
| 217 | for _, t := range r.Targets { |
| 218 | if t.FixedWeight > 0 { |
| 219 | nFixed++ |
| 220 | sumFixed += t.FixedWeight |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | // if there are no targets with fixed weight then each target simply gets |
| 225 | // an equal amount of traffic |
| 226 | if nFixed == 0 { |
| 227 | w := 1.0 / float64(len(r.Targets)) |
| 228 | for _, t := range r.Targets { |
| 229 | t.Weight = w |
| 230 | } |
| 231 | r.wTargets = r.Targets |
| 232 | return |
| 233 | } |
| 234 | |
| 235 | // normalize fixed weights up (sumFixed < 1) or down (sumFixed > 1) |
| 236 | scale := 1.0 |
| 237 | if sumFixed > 1 || (nFixed == len(r.Targets) && sumFixed < 1) { |
| 238 | scale = 1 / sumFixed |
| 239 | } |
| 240 | |
| 241 | // compute the weight for the targets with dynamic weights |
| 242 | dynamic := (1 - sumFixed) / float64(len(r.Targets)-nFixed) |
| 243 | if dynamic < 0 { |
| 244 | dynamic = 0 |
| 245 | } |
| 246 | |
| 247 | // assign the actual weight to each target |
| 248 | for _, t := range r.Targets { |
| 249 | if t.FixedWeight > 0 { |
| 250 | t.Weight = t.FixedWeight * scale |
| 251 | } else { |
| 252 | t.Weight = dynamic |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | // distribute the targets on a ring suitable for weighted round-robin |
| 257 | // distribution |
| 258 | // |
| 259 | // This is done in two steps: |
| 260 | // |
| 261 | // Step one determines the necessary ring size to distribute the targets |
| 262 | // according to their weight with reasonable accuracy. For example, two |
| 263 | // targets with 50% weight fit in a ring of size 2 whereas two targets with |
| 264 | // 10% and 90% weight require a ring of size 10. |
| 265 | // |
| 266 | // To keep it simple we allocate 10000 slots which provides slots to all |
| 267 | // targets with at least a weight of 0.01%. In addition, we guarantee that |
| 268 | // every target with a weight > 0 gets at least one slot. The case where |
| 269 | // all targets get an equal share of traffic is handled earlier so this is |
| 270 | // for situations with some fixed weight. |