github.com/polarismesh/polaris@v1.17.8/plugin/ratelimit/token/resource_limiter.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package token
    19  
    20  import (
    21  	"fmt"
    22  
    23  	lru "github.com/hashicorp/golang-lru"
    24  	"golang.org/x/time/rate"
    25  
    26  	"github.com/polarismesh/polaris/plugin"
    27  )
    28  
    29  // 资源限制器
    30  type resourceRatelimit struct {
    31  	typStr    string
    32  	resources *lru.Cache
    33  	whiteList map[string]bool
    34  	config    *ResourceLimitConfig
    35  }
    36  
    37  // 新建资源限制器
    38  func newResourceRatelimit(typ plugin.RatelimitType, config *ResourceLimitConfig) (*resourceRatelimit, error) {
    39  	r := &resourceRatelimit{typStr: plugin.RatelimitStr[typ]}
    40  	if err := r.initialize(config); err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	return r, nil
    45  }
    46  
    47  // initialize
    48  func (r *resourceRatelimit) initialize(config *ResourceLimitConfig) error {
    49  	r.config = config
    50  	if config == nil || !config.Open {
    51  		log.Infof("[Plugin][%s] resource(%s) ratelimit is not open", PluginName, r.typStr)
    52  		return nil
    53  	}
    54  
    55  	if config.Global == nil {
    56  		return fmt.Errorf("resource(%s) global ratelimit rule is empty", r.typStr)
    57  	}
    58  	if config.Global.Bucket <= 0 || config.Global.Rate <= 0 {
    59  		return fmt.Errorf("resource(%s) ratelimit global bucket or rate invalid", r.typStr)
    60  	}
    61  	if config.MaxResourceCacheAmount <= 0 {
    62  		return fmt.Errorf("resource(%s) max resource amount is invalid", r.typStr)
    63  	}
    64  
    65  	cache, err := lru.New(config.MaxResourceCacheAmount)
    66  	if err != nil {
    67  		log.Errorf("[Plugin][%s] resource(%s) ratelimit create new lru cache err: %s",
    68  			PluginName, r.typStr, err.Error())
    69  		return err
    70  	}
    71  	r.resources = cache
    72  
    73  	r.whiteList = make(map[string]bool)
    74  	for _, item := range config.WhiteList {
    75  		r.whiteList[item] = true
    76  	}
    77  
    78  	log.Infof("[Plugin][%s] resource(%s) ratelimit open", PluginName, r.typStr)
    79  	return nil
    80  }
    81  
    82  // 限流是否开启
    83  func (r *resourceRatelimit) isOpen() bool {
    84  	return r.config != nil && r.config.Open
    85  }
    86  
    87  // 检查是否属于白名单,属于的话,则不限流
    88  func (r *resourceRatelimit) isWhiteList(key string) bool {
    89  	_, ok := r.whiteList[key]
    90  	return ok
    91  }
    92  
    93  // 实现limiter
    94  func (r *resourceRatelimit) allow(key string) bool {
    95  	if ok := r.isOpen(); !ok {
    96  		return true
    97  	}
    98  	if ok := r.isWhiteList(key); ok {
    99  		return true
   100  	}
   101  
   102  	value, ok := r.resources.Get(key)
   103  	if !ok {
   104  		r.resources.ContainsOrAdd(key,
   105  			rate.NewLimiter(rate.Limit(r.config.Global.Rate), r.config.Global.Bucket))
   106  		// 上面已经加了value,这里正常情况会有value
   107  		value, ok = r.resources.Get(key)
   108  		if !ok {
   109  			// 还找不到,打印日志,返回true
   110  			log.Warnf("[Plugin][%s] not found the resources(%s) key(%s) in the cache",
   111  				PluginName, r.typStr, key)
   112  			return true
   113  		}
   114  	}
   115  
   116  	return value.(*rate.Limiter).Allow()
   117  }