dubbo.apache.org/dubbo-go/v3@v3.1.1/cluster/router/polaris/router.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 polaris 19 20 import ( 21 "context" 22 "errors" 23 "fmt" 24 "strings" 25 "sync" 26 "time" 27 ) 28 29 import ( 30 "github.com/dubbogo/gost/log/logger" 31 32 "github.com/polarismesh/polaris-go" 33 "github.com/polarismesh/polaris-go/pkg/model" 34 v1 "github.com/polarismesh/polaris-go/pkg/model/pb/v1" 35 ) 36 37 import ( 38 "dubbo.apache.org/dubbo-go/v3/cluster/router" 39 "dubbo.apache.org/dubbo-go/v3/common" 40 "dubbo.apache.org/dubbo-go/v3/common/constant" 41 "dubbo.apache.org/dubbo-go/v3/config" 42 "dubbo.apache.org/dubbo-go/v3/protocol" 43 remotingpolaris "dubbo.apache.org/dubbo-go/v3/remoting/polaris" 44 "dubbo.apache.org/dubbo-go/v3/remoting/polaris/parser" 45 ) 46 47 var ( 48 _ router.PriorityRouter = (*polarisRouter)(nil) 49 ) 50 51 var ( 52 ErrorPolarisServiceRouteRuleEmpty = errors.New("service route rule is empty") 53 ) 54 55 func newPolarisRouter() (*polarisRouter, error) { 56 if err := remotingpolaris.Check(); errors.Is(err, remotingpolaris.ErrorNoOpenPolarisAbility) { 57 return &polarisRouter{ 58 openRoute: false, 59 }, nil 60 } 61 62 routerAPI, err := remotingpolaris.GetRouterAPI() 63 if err != nil { 64 return nil, err 65 } 66 consumerAPI, err := remotingpolaris.GetConsumerAPI() 67 if err != nil { 68 return nil, err 69 } 70 71 return &polarisRouter{ 72 openRoute: true, 73 routerAPI: routerAPI, 74 consumerAPI: consumerAPI, 75 }, nil 76 } 77 78 type polarisRouter struct { 79 openRoute bool 80 81 routerAPI polaris.RouterAPI 82 consumerAPI polaris.ConsumerAPI 83 84 cancel context.CancelFunc 85 86 lock sync.RWMutex 87 instances map[string]model.Instance 88 } 89 90 // Route Determine the target invokers list. 91 func (p *polarisRouter) Route(invokers []protocol.Invoker, url *common.URL, 92 invoaction protocol.Invocation) []protocol.Invoker { 93 94 if !p.openRoute { 95 logger.Debug("[Router][Polaris] not open polaris route ability") 96 return invokers 97 } 98 99 if len(invokers) == 0 { 100 logger.Warn("[Router][Polaris] invokers from previous router is empty") 101 return invokers 102 } 103 104 service := getService(url) 105 instanceMap := p.buildInstanceMap(service) 106 if len(instanceMap) == 0 { 107 return invokers 108 } 109 110 invokersMap := make(map[string]protocol.Invoker, len(invokers)) 111 targetIns := make([]model.Instance, 0, len(invokers)) 112 for i := range invokers { 113 invoker := invokers[i] 114 instanceID := invoker.GetURL().GetParam(constant.PolarisInstanceID, "") 115 if len(instanceID) == 0 { 116 continue 117 } 118 invokersMap[instanceID] = invoker 119 if val, ok := instanceMap[instanceID]; ok { 120 targetIns = append(targetIns, val) 121 } 122 } 123 124 req, err := p.buildRouteRequest(service, url, invoaction) 125 if err != nil { 126 return invokers 127 } 128 req.DstInstances = model.NewDefaultServiceInstances(model.ServiceInfo{ 129 Service: service, 130 Namespace: remotingpolaris.GetNamespace(), 131 }, targetIns) 132 133 resp, err := p.routerAPI.ProcessRouters(&req) 134 if err != nil { 135 return invokers 136 } 137 138 ret := make([]protocol.Invoker, 0, len(resp.GetInstances())) 139 for i := range resp.GetInstances() { 140 if val, ok := invokersMap[resp.GetInstances()[i].GetId()]; ok { 141 ret = append(ret, val) 142 } 143 } 144 145 return ret 146 } 147 148 func getService(url *common.URL) string { 149 applicationMode := false 150 for _, item := range config.GetRootConfig().Registries { 151 if item.Protocol == constant.PolarisKey { 152 applicationMode = item.RegistryType == constant.ServiceKey 153 } 154 } 155 156 service := url.Interface() 157 if applicationMode { 158 service = config.GetApplicationConfig().Name 159 } 160 161 return service 162 } 163 164 func (p *polarisRouter) buildRouteRequest(svc string, url *common.URL, 165 invocation protocol.Invocation) (polaris.ProcessRoutersRequest, error) { 166 167 routeReq := polaris.ProcessRoutersRequest{ 168 ProcessRoutersRequest: model.ProcessRoutersRequest{ 169 SourceService: model.ServiceInfo{ 170 Metadata: map[string]string{}, 171 }, 172 }, 173 } 174 175 attachement := invocation.Attachments() 176 arguments := invocation.Arguments() 177 178 labels, err := p.buildTrafficLabels(svc) 179 if err != nil { 180 return polaris.ProcessRoutersRequest{}, err 181 } 182 183 for i := range labels { 184 label := labels[i] 185 if strings.Compare(label, model.LabelKeyPath) == 0 { 186 routeReq.AddArguments(model.BuildPathArgument(getInvokeMethod(url, invocation))) 187 continue 188 } 189 if strings.HasPrefix(label, model.LabelKeyHeader) { 190 if val, ok := attachement[strings.TrimPrefix(label, model.LabelKeyHeader)]; ok { 191 routeReq.SourceService.Metadata[label] = fmt.Sprintf("%+v", val) 192 routeReq.AddArguments(model.BuildArgumentFromLabel(label, fmt.Sprintf("%+v", val))) 193 } 194 } 195 if strings.HasPrefix(label, model.LabelKeyQuery) { 196 if val := parser.ParseArgumentsByExpression(label, arguments); val != nil { 197 routeReq.AddArguments(model.BuildArgumentFromLabel(label, fmt.Sprintf("%+v", val))) 198 } 199 } 200 } 201 202 return routeReq, nil 203 } 204 205 func (p *polarisRouter) buildTrafficLabels(svc string) ([]string, error) { 206 req := &model.GetServiceRuleRequest{} 207 req.Namespace = remotingpolaris.GetNamespace() 208 req.Service = svc 209 req.SetTimeout(time.Second) 210 engine := p.routerAPI.SDKContext().GetEngine() 211 resp, err := engine.SyncGetServiceRule(model.EventRouting, req) 212 if err != nil { 213 logger.Errorf("[Router][Polaris] ns:%s svc:%s get route rule fail : %+v", req.GetNamespace(), req.GetService(), err) 214 return nil, err 215 } 216 217 if resp == nil || resp.GetValue() == nil { 218 logger.Errorf("[Router][Polaris] ns:%s svc:%s get route rule empty", req.GetNamespace(), req.GetService()) 219 return nil, ErrorPolarisServiceRouteRuleEmpty 220 } 221 222 routeRule := resp.GetValue().(*v1.Routing) 223 labels := make([]string, 0, 4) 224 labels = append(labels, collectRouteLabels(routeRule.GetInbounds())...) 225 labels = append(labels, collectRouteLabels(routeRule.GetInbounds())...) 226 227 return labels, nil 228 } 229 230 func getInvokeMethod(url *common.URL, invoaction protocol.Invocation) string { 231 applicationMode := false 232 for _, item := range config.GetRootConfig().Registries { 233 if item.Protocol == constant.PolarisKey { 234 applicationMode = item.RegistryType == constant.ServiceKey 235 } 236 } 237 238 method := invoaction.MethodName() 239 if applicationMode { 240 method = url.Interface() + "/" + invoaction.MethodName() 241 } 242 243 return method 244 } 245 246 func collectRouteLabels(routings []*v1.Route) []string { 247 ret := make([]string, 0, 4) 248 249 for i := range routings { 250 route := routings[i] 251 sources := route.GetSources() 252 for p := range sources { 253 source := sources[p] 254 for k := range source.GetMetadata() { 255 ret = append(ret, k) 256 } 257 } 258 } 259 260 return ret 261 } 262 263 func (p *polarisRouter) buildInstanceMap(svc string) map[string]model.Instance { 264 resp, err := p.consumerAPI.GetAllInstances(&polaris.GetAllInstancesRequest{ 265 GetAllInstancesRequest: model.GetAllInstancesRequest{ 266 Service: svc, 267 Namespace: remotingpolaris.GetNamespace(), 268 }, 269 }) 270 if err != nil { 271 logger.Errorf("[Router][Polaris] ns:%s svc:%s get all instances fail : %+v", remotingpolaris.GetNamespace(), svc, err) 272 return nil 273 } 274 275 ret := make(map[string]model.Instance, len(resp.GetInstances())) 276 277 for i := range resp.GetInstances() { 278 ret[resp.GetInstances()[i].GetId()] = resp.GetInstances()[i] 279 } 280 281 return ret 282 } 283 284 // URL Return URL in router 285 func (p *polarisRouter) URL() *common.URL { 286 return nil 287 } 288 289 // Priority Return Priority in router 290 // 0 to ^int(0) is better 291 func (p *polarisRouter) Priority() int64 { 292 return 0 293 } 294 295 // Notify the router the invoker list 296 func (p *polarisRouter) Notify(invokers []protocol.Invoker) { 297 if !p.openRoute { 298 return 299 } 300 if len(invokers) == 0 { 301 return 302 } 303 service := getService(invokers[0].GetURL()) 304 if service == "" { 305 logger.Error("url service is empty") 306 return 307 } 308 309 req := &model.GetServiceRuleRequest{} 310 req.Namespace = remotingpolaris.GetNamespace() 311 req.Service = service 312 req.SetTimeout(time.Second) 313 314 engine := p.routerAPI.SDKContext().GetEngine() 315 _, err := engine.SyncGetServiceRule(model.EventRouting, req) 316 if err != nil { 317 logger.Errorf("[Router][Polaris] ns:%s svc:%s get route rule fail : %+v", req.GetNamespace(), req.GetService(), err) 318 return 319 } 320 321 _, err = p.consumerAPI.GetAllInstances(&polaris.GetAllInstancesRequest{ 322 GetAllInstancesRequest: model.GetAllInstancesRequest{ 323 Service: service, 324 Namespace: remotingpolaris.GetNamespace(), 325 }, 326 }) 327 if err != nil { 328 logger.Errorf("[Router][Polaris] ns:%s svc:%s get all instances fail : %+v", req.GetNamespace(), req.GetService(), err) 329 return 330 } 331 }