diff --git a/pkg/model/cluster.go b/pkg/model/cluster.go index 8d0e8ca2..7bd3c736 100644 --- a/pkg/model/cluster.go +++ b/pkg/model/cluster.go @@ -733,12 +733,15 @@ type ServiceClusters interface { GetExtendedCacheValue(pluginIndex int) interface{} // SetExtendedCacheValue 设置扩展的缓存值,需要预初始化好,否则会有并发修改的问题 SetExtendedCacheValue(pluginIndex int, value interface{}) + // GetInstancesWithMetaValuesNotEqual 获取该标签不等于指定标签值的实例集合 + GetInstancesWithMetaValuesNotEqual(location Location, metaKey string, metavalue string) map[string]string } // LocationBasedMetaKey 基于某个地域信息的元数据查询key type LocationBasedMetaKey struct { location Location metaKey string + keyType int // 0: equal, 1: not equal } // metaDataInService 标签缓存信息 @@ -1014,6 +1017,42 @@ func (c *clusterCache) SetExtendedCacheValue(pluginIndex int, value interface{}) c.extendedCacheValues.Store(pluginIndex, value) } +// GetInstancesWithMetaValuesNotEqual 获取该标签不等于指定标签值的实例集合 +func (c *clusterCache) GetInstancesWithMetaValuesNotEqual(location Location, metaKey string, metaValue string) map[string]string { + var value interface{} + var exists bool + locationKey := LocationBasedMetaKey{location: location, metaKey: metaKey, keyType: 1} + value, exists = c.svcLevelMetadata.metaDataSet.Load(locationKey) + if exists { + return value.(map[string]string) + } + // 按需构建指定地域的实例元数据集合 + instances := c.svcInstances.GetInstances() + metaValueSet := make(map[string]string, 0) + for _, instance := range instances { + if !matchLocation(instance, location) { + continue + } + if instance.IsIsolated() || instance.GetWeight() == 0 || !instance.IsHealthy() { + continue + } + metadata := instance.GetMetadata() + if len(metadata) == 0 { + continue + } + val, ok := metadata[metaKey] + if !ok { + continue + } + if val == metaValue { + continue + } + metaValueSet[val] = buildComposedValue(metaKey, val) + } + value, _ = c.svcLevelMetadata.metaDataSet.LoadOrStore(locationKey, metaValueSet) + return value.(map[string]string) +} + // matchMetadata 标签匹配 func (c *Cluster) matchMetadata(instance Instance) bool { if c.MetaCount == 0 { diff --git a/plugin/servicerouter/rulebase/base.go b/plugin/servicerouter/rulebase/base.go index ea25f2ee..05f6d320 100644 --- a/plugin/servicerouter/rulebase/base.go +++ b/plugin/servicerouter/rulebase/base.go @@ -359,14 +359,19 @@ func (g *RuleBasedInstancesFilter) matchDstMetadata(routeInfo *servicerouter.Rou // 首先如果元数据的value无法获取,直接匹配失败 return nil, false, "", nil } + // 全匹配类型直接返回全量实例 if ruleMetaValueStr == matchAll && ruleMetaValue.ValueType == apimodel.MatchString_TEXT { return cls, true, "", nil } - metaValues := svcCache.GetInstanceMetaValues(cls.Location, ruleMetaKey) - if len(metaValues) == 0 { - // 不匹配 - return nil, false, "", nil + // 如果是“不等于”类型,需要单独处理 + var metaValues map[string]string + if ruleMetaValue.Type != apimodel.MatchString_NOT_EQUALS { + metaValues = svcCache.GetInstanceMetaValues(cls.Location, ruleMetaKey) + if len(metaValues) == 0 { + // 不匹配 + return nil, false, "", nil + } } switch ruleMetaValue.Type { case apimodel.MatchString_REGEX: @@ -399,6 +404,17 @@ func (g *RuleBasedInstancesFilter) matchDstMetadata(routeInfo *servicerouter.Rou if !hasMatchedValue { return nil, false, "", nil } + + case apimodel.MatchString_NOT_EQUALS: + metaValues = svcCache.GetInstancesWithMetaValuesNotEqual(cls.Location, ruleMetaKey, ruleMetaValueStr) + if len(metaValues) == 0 { + return cls, false, "", nil + } + for k, v := range metaValues { + cls.RuleAddMetadata(ruleMetaKey, k, v) + } + metaChanged = true + // parameter、variable、text 的 exact 最终都是要精确匹配,只是匹配的值来源不同 default: // 校验从上一个路由插件继承下来的规则是否符合该目标规则