@@ -48,6 +48,9 @@ type ClusterOptions struct {
48
48
// Allows routing read-only commands to the random master or slave node.
49
49
// It automatically enables ReadOnly.
50
50
RouteRandomly bool
51
+ // Allows routing read-only commands to the replica nodes in ronund-robin.
52
+ // It automatically enables ReadOnly
53
+ RouteRoundRobinReplicas bool
51
54
52
55
// Optional function that returns cluster slots information.
53
56
// It is useful to manually create cluster of standalone Redis servers
@@ -584,6 +587,9 @@ func (c *clusterNodes) Random() (*clusterNode, error) {
584
587
type clusterSlot struct {
585
588
start , end int
586
589
nodes []* clusterNode
590
+
591
+ // Allows node selection to use round-robin selection strategy.
592
+ next uint32
587
593
}
588
594
589
595
type clusterSlotSlice []* clusterSlot
@@ -767,7 +773,44 @@ func (c *clusterState) slotRandomNode(slot int) (*clusterNode, error) {
767
773
return nodes [randomNodes [0 ]], nil
768
774
}
769
775
776
+ // slotRoundRobinReplicaNode tries to select a node from the list of replica nodes.
777
+ // if no replica nodes are available, returns the primary node.
778
+ func (c * clusterState ) slotRoundRobinReplicaNode (slot int ) (* clusterNode , error ) {
779
+ cs := c .slotCluster (slot )
780
+ if cs == nil {
781
+ return c .nodes .Random ()
782
+ }
783
+
784
+ switch len (cs .nodes ) {
785
+ case 0 :
786
+ return c .nodes .Random ()
787
+ case 1 :
788
+ return cs .nodes [0 ], nil
789
+ case 2 :
790
+ if replica := cs .nodes [1 ]; ! replica .Failing () {
791
+ return replica , nil
792
+ }
793
+ return cs .nodes [0 ], nil
794
+ default :
795
+ var replica * clusterNode
796
+ for i := 0 ; i < 10 ; i ++ {
797
+ next := atomic .AddUint32 (& cs .next , 1 )
798
+ n := (int (next ))% (len (cs .nodes )- 1 ) + 1
799
+ replica = cs .nodes [n ]
800
+ if ! replica .Failing () {
801
+ return replica , nil
802
+ }
803
+ }
804
+ // All slaves are loading - use master.
805
+ return cs .nodes [0 ], nil
806
+ }
807
+ }
808
+
770
809
func (c * clusterState ) slotNodes (slot int ) []* clusterNode {
810
+ return c .slotCluster (slot ).nodes
811
+ }
812
+
813
+ func (c * clusterState ) slotCluster (slot int ) * clusterSlot {
771
814
i := sort .Search (len (c .slots ), func (i int ) bool {
772
815
return c .slots [i ].end >= slot
773
816
})
@@ -776,8 +819,9 @@ func (c *clusterState) slotNodes(slot int) []*clusterNode {
776
819
}
777
820
x := c .slots [i ]
778
821
if slot >= x .start && slot <= x .end {
779
- return x . nodes
822
+ return x
780
823
}
824
+
781
825
return nil
782
826
}
783
827
@@ -1824,6 +1868,9 @@ func (c *ClusterClient) slotReadOnlyNode(state *clusterState, slot int) (*cluste
1824
1868
if c .opt .RouteRandomly {
1825
1869
return state .slotRandomNode (slot )
1826
1870
}
1871
+ if c .opt .RouteRoundRobinReplicas {
1872
+ return state .slotRoundRobinReplicaNode (slot )
1873
+ }
1827
1874
return state .slotSlaveNode (slot )
1828
1875
}
1829
1876
0 commit comments