AlexStocks commented on a change in pull request #1187: URL: https://github.com/apache/dubbo-go/pull/1187#discussion_r627501685
########## File path: cluster/router/v3router/uniform_rule.go ########## @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v3router + +import ( + "math/rand" + "time" +) + +import ( + perrors "github.com/pkg/errors" +) + +import ( + "github.com/apache/dubbo-go/cluster/router/v3router/match_judger" + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/config" + "github.com/apache/dubbo-go/protocol" +) + +// VirtualServiceRule is item of virtual service, it aims at judge if invocation context match it's condition, and +// if match, get result destination key, which should be defined in DestinationRule yaml file +type VirtualServiceRule struct { + // routerItem store match router list and destination list of this router + routerItem *config.DubboServiceRouterItem + + // uniformRule is the upper struct ptr + uniformRule *UniformRule +} + +// match read from vsr's Match config +// it judges if this invocation matches the router rule request defined in config one by one +func (vsr *VirtualServiceRule) match(url *common.URL, invocation protocol.Invocation) bool { + for _, v := range vsr.routerItem.Match { + // method match judge + if v.Method != nil { + methodMatchJudger := match_judger.NewMethodMatchJudger(v.Method) + if !methodMatchJudger.Judge(invocation) { + return false + } + } + + // source label match judge + if !match_judger.JudgeUrlLabel(url, v.SourceLabels) { + return false + } + + // atta match judge + if v.Attachment != nil { + attachmentMatchJudger := match_judger.NewAttachmentMatchJudger(v.Attachment) + if attachmentMatchJudger.Judge(invocation) { + return false + } + } + // threshold match judge + // todo + + // reserve match judge + // todo + } + return true +} + +// tryGetSubsetFromRouterOfOneDestination is a recursion function +// try from destination 's header to final fallback destination, when success, it return result destination, else return error +func (vsr *VirtualServiceRule) tryGetSubsetFromRouterOfOneDestination(desc *config.DubboDestination, invokers []protocol.Invoker) ([]protocol.Invoker, int, error) { + subSet := desc.Destination.Subset + labels, ok := vsr.uniformRule.DestinationLabelListMap[subSet] + resultInvokers := make([]protocol.Invoker, 0) + if ok { + for _, v := range invokers { + if match_judger.JudgeUrlLabel(v.GetURL(), labels) { + resultInvokers = append(resultInvokers, v) + } + } + if len(resultInvokers) != 0 { + return resultInvokers, desc.Destination.Weight, nil + } + } + + if desc.Destination.Fallback != nil { + return vsr.tryGetSubsetFromRouterOfOneDestination(desc.Destination.Fallback, invokers) + } + return nil, 0, perrors.New("No invoker matches and no fallback destination to choose!") +} + +//weightInvokersPair stores weight and invoker list. +type weightInvokersPair struct { + weight int + invokerList []protocol.Invoker +} + +type weightInvokerPairResults struct { + pairs []weightInvokersPair +} + +func (w *weightInvokerPairResults) getTargetInvokers() []protocol.Invoker { + if len(w.pairs) == 0 { + return []protocol.Invoker{} + } + + if len(w.pairs) == 1 { + return w.pairs[0].invokerList + } + rand.Seed(time.Now().UnixNano()) + target := rand.Intn(100) + // noweight means all weigh is zero, random choose one invoker list + noWeight := true + // check if empty + for _, v := range w.pairs { + if v.weight != 0 { + noWeight = false // user defined weight + break + } + } + if noWeight { + // random choose one list + weitUnit := 100/len(w.pairs) + 1 + return w.pairs[target/weitUnit].invokerList + } else { + total := 0 + for _, v := range w.pairs { + total += v.weight + if total > target { + return v.invokerList + } + } + } + // invalid weight set: total is smaller than 100, choose first + return w.pairs[0].invokerList +} + +func (vsr *VirtualServiceRule) getRuleTargetInvokers(invokers []protocol.Invoker) ([]protocol.Invoker, error) { + // weightInvokerPairResult is the collection routerDesc of all destination fields, + weightInvokerPairResult := weightInvokerPairResults{} + for _, v := range vsr.routerItem.Router { + // v is one destination 's header e.g. + /* + route: + - destination: # v is here + host: demo + subset: v1 + fallback: + destination: + host: demo + subset: v2 + fallback: + destination: + host: demo + subset: v3 + - destination: + host: demo + subset: v4 + fallback: + destination: + host: demo + subset: v5 + fallback: + destination: + host: demo + subset: v6 + */ + invokerListOfOneDest, weight, err := vsr.tryGetSubsetFromRouterOfOneDestination(v, invokers) + if err != nil { + return nil, err + } + // combination of all destination field e.g. + /* + - destination: + host: demo + subset: na61 + - destination: + host: demo + subset: na610 + */ + weightInvokerPairResult.pairs = append(weightInvokerPairResult.pairs, weightInvokersPair{ + weight: weight, + invokerList: invokerListOfOneDest, + }) + } + + return weightInvokerPairResult.getTargetInvokers(), nil +} + +// UniformRule +type UniformRule struct { + services []*config.StringMatch + virtualServiceRules []VirtualServiceRule + DestinationLabelListMap map[string]map[string]string +} + +// NewDefaultConnChecker constructs a new DefaultConnChecker based on the url +func newUniformRule(dubboRoute *config.DubboRoute, destinationMap map[string]map[string]string) (*UniformRule, error) { + matchItems := dubboRoute.RouterDetail + virtualServiceRules := make([]VirtualServiceRule, 0) + newUniformRule := &UniformRule{ + DestinationLabelListMap: destinationMap, + services: dubboRoute.Services, + } + for _, v := range matchItems { + virtualServiceRules = append(virtualServiceRules, VirtualServiceRule{ + routerItem: v, + uniformRule: newUniformRule, + }) + } + newUniformRule.virtualServiceRules = virtualServiceRules + return newUniformRule, nil +} + +func (u *UniformRule) route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker { + // service rule + destination -> filter + resultInvokers := make([]protocol.Invoker, 0) + var err error + matchService := false + for _, v := range u.services { + // check if match service field + if match_judger.NewStringMatchJudger(v).Judge(url.ServiceKey()) { + matchService = true + break + } + } + if !matchService { + // if not match, jump this rule + return resultInvokers + } + // match service field, route Details level(service level) match + // then, check all sub rule, if match, get destination rule target invokers, else do fail back logic + for _, rule := range u.virtualServiceRules { + if rule.match(url, invocation) { + // match this rule, do get target logic + resultInvokers, err = rule.getRuleTargetInvokers(invokers) + if err != nil { + logger.Error("getRuleTargetInvokers from rule err = ", err) + return nil + } + return resultInvokers + } + } + logger.Error("no match rule!") Review comment: logger.Error("no match rule for invokers %+v", invokers) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@dubbo.apache.org For additional commands, e-mail: notifications-h...@dubbo.apache.org