roundrobin.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. /*
  2. *
  3. * Copyright 2017 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. // Package roundrobin defines a roundrobin balancer. Roundrobin balancer is
  19. // installed as one of the default balancers in gRPC, users don't need to
  20. // explicitly install this balancer.
  21. package roundrobin
  22. import (
  23. "sync/atomic"
  24. "google.golang.org/grpc/balancer"
  25. "google.golang.org/grpc/balancer/base"
  26. "google.golang.org/grpc/grpclog"
  27. "google.golang.org/grpc/internal/grpcrand"
  28. )
  29. // Name is the name of round_robin balancer.
  30. const Name = "round_robin"
  31. var logger = grpclog.Component("roundrobin")
  32. // newBuilder creates a new roundrobin balancer builder.
  33. func newBuilder() balancer.Builder {
  34. return base.NewBalancerBuilder(Name, &rrPickerBuilder{}, base.Config{HealthCheck: true})
  35. }
  36. func init() {
  37. balancer.Register(newBuilder())
  38. }
  39. type rrPickerBuilder struct{}
  40. func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker {
  41. logger.Infof("roundrobinPicker: Build called with info: %v", info)
  42. if len(info.ReadySCs) == 0 {
  43. return base.NewErrPicker(balancer.ErrNoSubConnAvailable)
  44. }
  45. scs := make([]balancer.SubConn, 0, len(info.ReadySCs))
  46. for sc := range info.ReadySCs {
  47. scs = append(scs, sc)
  48. }
  49. return &rrPicker{
  50. subConns: scs,
  51. // Start at a random index, as the same RR balancer rebuilds a new
  52. // picker when SubConn states change, and we don't want to apply excess
  53. // load to the first server in the list.
  54. next: uint32(grpcrand.Intn(len(scs))),
  55. }
  56. }
  57. type rrPicker struct {
  58. // subConns is the snapshot of the roundrobin balancer when this picker was
  59. // created. The slice is immutable. Each Get() will do a round robin
  60. // selection from it and return the selected SubConn.
  61. subConns []balancer.SubConn
  62. next uint32
  63. }
  64. func (p *rrPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
  65. subConnsLen := uint32(len(p.subConns))
  66. nextIndex := atomic.AddUint32(&p.next, 1)
  67. sc := p.subConns[nextIndex%subConnsLen]
  68. return balancer.PickResult{SubConn: sc}, nil
  69. }