@@ -48,6 +48,9 @@ type ClusterOptions struct {
4848 // Allows routing read-only commands to the random master or slave node.
4949 // It automatically enables ReadOnly.
5050 RouteRandomly bool
51+ // Allows routing read-only commands to the replica nodes in ronund-robin.
52+ // It automatically enables ReadOnly
53+ RouteRoundRobinReplicas bool
5154
5255 // Optional function that returns cluster slots information.
5356 // It is useful to manually create cluster of standalone Redis servers
@@ -584,6 +587,9 @@ func (c *clusterNodes) Random() (*clusterNode, error) {
584587type clusterSlot struct {
585588 start , end int
586589 nodes []* clusterNode
590+
591+ // Allows node selection to use round-robin selection strategy.
592+ next uint32
587593}
588594
589595type clusterSlotSlice []* clusterSlot
@@ -767,7 +773,44 @@ func (c *clusterState) slotRandomNode(slot int) (*clusterNode, error) {
767773 return nodes [randomNodes [0 ]], nil
768774}
769775
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+
770809func (c * clusterState ) slotNodes (slot int ) []* clusterNode {
810+ return c .slotCluster (slot ).nodes
811+ }
812+
813+ func (c * clusterState ) slotCluster (slot int ) * clusterSlot {
771814 i := sort .Search (len (c .slots ), func (i int ) bool {
772815 return c .slots [i ].end >= slot
773816 })
@@ -776,8 +819,9 @@ func (c *clusterState) slotNodes(slot int) []*clusterNode {
776819 }
777820 x := c .slots [i ]
778821 if slot >= x .start && slot <= x .end {
779- return x . nodes
822+ return x
780823 }
824+
781825 return nil
782826}
783827
@@ -1824,6 +1868,9 @@ func (c *ClusterClient) slotReadOnlyNode(state *clusterState, slot int) (*cluste
18241868 if c .opt .RouteRandomly {
18251869 return state .slotRandomNode (slot )
18261870 }
1871+ if c .opt .RouteRoundRobinReplicas {
1872+ return state .slotRoundRobinReplicaNode (slot )
1873+ }
18271874 return state .slotSlaveNode (slot )
18281875}
18291876
0 commit comments