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 }