dubbo.apache.org/dubbo-go/v3@v3.1.1/cluster/router/meshrouter/meshrouter.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  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 meshrouter
    19  
    20  import (
    21  	"math/rand"
    22  )
    23  
    24  import (
    25  	"github.com/dubbogo/gost/log/logger"
    26  )
    27  
    28  import (
    29  	"dubbo.apache.org/dubbo-go/v3/cluster/router"
    30  	"dubbo.apache.org/dubbo-go/v3/common"
    31  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    32  	"dubbo.apache.org/dubbo-go/v3/config_center"
    33  	"dubbo.apache.org/dubbo-go/v3/protocol"
    34  	"dubbo.apache.org/dubbo-go/v3/remoting/xds"
    35  )
    36  
    37  const (
    38  	name = "mesh-router"
    39  )
    40  
    41  // MeshRouter have
    42  type MeshRouter struct {
    43  	client *xds.WrappedClientImpl
    44  }
    45  
    46  // NewMeshRouter construct an NewConnCheckRouter via url
    47  func NewMeshRouter() (router.PriorityRouter, error) {
    48  	xdsWrappedClient := xds.GetXDSWrappedClient()
    49  	if xdsWrappedClient == nil {
    50  		logger.Debugf("[Mesh Router] xds wrapped client is not created.")
    51  	}
    52  	return &MeshRouter{
    53  		client: xdsWrappedClient,
    54  	}, nil
    55  }
    56  
    57  // Route gets a list of routed invoker
    58  func (r *MeshRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
    59  	if r.client == nil {
    60  		return invokers
    61  	}
    62  	hostAddr, err := r.client.GetHostAddrByServiceUniqueKey(common.GetSubscribeName(url))
    63  	if err != nil {
    64  		// todo deal with error
    65  		return nil
    66  	}
    67  	rconf := r.client.GetRouterConfig(hostAddr)
    68  
    69  	clusterInvokerMap := make(map[string][]protocol.Invoker)
    70  	for _, v := range invokers {
    71  		meshClusterID := v.GetURL().GetParam(constant.MeshClusterIDKey, "")
    72  		if _, ok := clusterInvokerMap[meshClusterID]; !ok {
    73  			clusterInvokerMap[meshClusterID] = make([]protocol.Invoker, 0)
    74  		}
    75  		clusterInvokerMap[meshClusterID] = append(clusterInvokerMap[meshClusterID], v)
    76  	}
    77  	route, err := r.client.MatchRoute(rconf, invocation)
    78  	if err != nil {
    79  		logger.Errorf("[Mesh Router] not found route,method=%s", invocation.MethodName())
    80  		return nil
    81  	}
    82  
    83  	// Loop through routes in order and select first match.
    84  	if route == nil || route.WeightedClusters == nil {
    85  		logger.Errorf("[Mesh Router] route's WeightedClusters is empty, route: %+v", r)
    86  		return invokers
    87  	}
    88  	invokersWeightPairs := make(invokerWeightPairs, 0)
    89  
    90  	for clusterID, weight := range route.WeightedClusters {
    91  		// cluster -> invokers
    92  		targetInvokers := clusterInvokerMap[clusterID]
    93  		invokersWeightPairs = append(invokersWeightPairs, invokerWeightPair{
    94  			invokers: targetInvokers,
    95  			weight:   weight.Weight,
    96  		})
    97  	}
    98  	return invokersWeightPairs.GetInvokers()
    99  }
   100  
   101  // Process there is no process needs for uniform Router, as it upper struct RouterChain has done it
   102  func (r *MeshRouter) Process(event *config_center.ConfigChangeEvent) {
   103  }
   104  
   105  // Name get name of ConnCheckerRouter
   106  func (r *MeshRouter) Name() string {
   107  	return name
   108  }
   109  
   110  // Priority get Router priority level
   111  func (r *MeshRouter) Priority() int64 {
   112  	return 0
   113  }
   114  
   115  // URL Return URL in router
   116  func (r *MeshRouter) URL() *common.URL {
   117  	return nil
   118  }
   119  
   120  // Notify the router the invoker list
   121  func (r *MeshRouter) Notify(invokers []protocol.Invoker) {
   122  }
   123  
   124  type invokerWeightPair struct {
   125  	invokers []protocol.Invoker
   126  	weight   uint32
   127  }
   128  
   129  type invokerWeightPairs []invokerWeightPair
   130  
   131  func (i *invokerWeightPairs) GetInvokers() []protocol.Invoker {
   132  	if len(*i) == 0 {
   133  		return nil
   134  	}
   135  	totalWeight := uint32(0)
   136  	tempWeight := uint32(0)
   137  	for _, v := range *i {
   138  		totalWeight += v.weight
   139  	}
   140  	randFloat := rand.Float64()
   141  	for _, v := range *i {
   142  		tempWeight += v.weight
   143  		tempPercent := float64(tempWeight) / float64(totalWeight)
   144  		if tempPercent >= randFloat {
   145  			return v.invokers
   146  		}
   147  	}
   148  	return (*i)[0].invokers
   149  }