From 125ed009bf9c25c0012d042472522b35a565d86c Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Sun, 29 Sep 2019 23:09:47 +0800 Subject: [PATCH 01/12] Define the interface of TpsLimitFilter --- filter/impl/tps_limit_filter.go | 54 ++++++++++++++++++++ filter/impl/tps_limit_filter_test.go | 18 +++++++ filter/impl/tps_limiter.go | 27 ++++++++++ filter/impl/tps_limiter_fixed_window_impl.go | 35 +++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 filter/impl/tps_limit_filter.go create mode 100644 filter/impl/tps_limit_filter_test.go create mode 100644 filter/impl/tps_limiter.go create mode 100644 filter/impl/tps_limiter_fixed_window_impl.go diff --git a/filter/impl/tps_limit_filter.go b/filter/impl/tps_limit_filter.go new file mode 100644 index 0000000000..6ada1aa61a --- /dev/null +++ b/filter/impl/tps_limit_filter.go @@ -0,0 +1,54 @@ +/* + * 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 impl + +import ( + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/protocol" +) + +const ( + TpsLimitFilterKey = "tps" +) + +func init() { + extension.SetFilter(TpsLimitFilterKey, GetAccessLogFilter) +} + +/** + * + */ +type TpsLimitFilter struct { + +} + +func (t TpsLimitFilter) Invoke(invoker protocol.Invoker,invocation protocol.Invocation) protocol.Result { + invoker.GetUrl() + invoker.IsAvailable() + return invoker.Invoke(invocation) +} + +func (t TpsLimitFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + return result +} + +func GetTpsLimitFilter() filter.Filter { + var tpsLimitFilter = TpsLimitFilter{} + return tpsLimitFilter +} diff --git a/filter/impl/tps_limit_filter_test.go b/filter/impl/tps_limit_filter_test.go new file mode 100644 index 0000000000..2ac8beceba --- /dev/null +++ b/filter/impl/tps_limit_filter_test.go @@ -0,0 +1,18 @@ +/* + * 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 impl diff --git a/filter/impl/tps_limiter.go b/filter/impl/tps_limiter.go new file mode 100644 index 0000000000..ee24c8c1b2 --- /dev/null +++ b/filter/impl/tps_limiter.go @@ -0,0 +1,27 @@ +/* + * 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 impl + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/protocol" +) + +type TpsLimiter interface { + IsAllowable(common.URL, protocol.Invocation) +} \ No newline at end of file diff --git a/filter/impl/tps_limiter_fixed_window_impl.go b/filter/impl/tps_limiter_fixed_window_impl.go new file mode 100644 index 0000000000..6f4a3360f9 --- /dev/null +++ b/filter/impl/tps_limiter_fixed_window_impl.go @@ -0,0 +1,35 @@ +/* + * 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 impl + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/protocol" +) + +type FixedWindowTpsLimiterImpl struct { + +} + +func (limiter FixedWindowTpsLimiterImpl) IsAllowable(common.URL, protocol.Invocation) { + panic("implement me") +} + +func NewInstance() TpsLimiter { + return FixedWindowTpsLimiterImpl{} +} From 225b90d109fedd03fa80cb0c537f4566b69fa78f Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Mon, 14 Oct 2019 18:24:41 +0800 Subject: [PATCH 02/12] TpsLimiter, RejectedExecutionHandler, TpsLimitFilter --- common/constant/default.go | 2 +- common/constant/key.go | 33 +++-- common/extension/tps_limit.go | 65 +++++++++ filter/impl/access_log_filter.go | 2 +- .../only_log_rejected_execution_handler.go | 61 ++++++++ filter/impl/tps_limit_filter.go | 30 +++- filter/impl/tps_limit_filter_test.go | 79 ++++++++++ .../impl/tps_limiter_method_service_impl.go | 136 ++++++++++++++++++ ...miter.go => rejected_execution_handler.go} | 9 +- filter/rejected_execution_handler_mock.go | 65 +++++++++ ...d_window_impl.go => tps_limit_strategy.go} | 22 +-- filter/tps_limiter.go | 39 +++++ filter/tps_limiter_mock.go | 65 +++++++++ go.mod | 5 +- go.sum | 7 + 15 files changed, 577 insertions(+), 43 deletions(-) create mode 100644 common/extension/tps_limit.go create mode 100644 filter/impl/only_log_rejected_execution_handler.go create mode 100644 filter/impl/tps_limiter_method_service_impl.go rename filter/{impl/tps_limiter.go => rejected_execution_handler.go} (86%) create mode 100644 filter/rejected_execution_handler_mock.go rename filter/{impl/tps_limiter_fixed_window_impl.go => tps_limit_strategy.go} (71%) create mode 100644 filter/tps_limiter.go create mode 100644 filter/tps_limiter_mock.go diff --git a/common/constant/default.go b/common/constant/default.go index 4363e3efd5..9b69226318 100644 --- a/common/constant/default.go +++ b/common/constant/default.go @@ -46,7 +46,7 @@ const ( const ( DEFAULT_KEY = "default" PREFIX_DEFAULT_KEY = "default." - DEFAULT_SERVICE_FILTERS = "echo,token,accesslog" + DEFAULT_SERVICE_FILTERS = "echo,token,accesslog,tps" DEFAULT_REFERENCE_FILTERS = "" GENERIC_REFERENCE_FILTERS = "generic" GENERIC = "$invoke" diff --git a/common/constant/key.go b/common/constant/key.go index 3006f44732..dc24c2b5db 100644 --- a/common/constant/key.go +++ b/common/constant/key.go @@ -48,19 +48,26 @@ const ( ) const ( - TIMESTAMP_KEY = "timestamp" - REMOTE_TIMESTAMP_KEY = "remote.timestamp" - CLUSTER_KEY = "cluster" - LOADBALANCE_KEY = "loadbalance" - WEIGHT_KEY = "weight" - WARMUP_KEY = "warmup" - RETRIES_KEY = "retries" - BEAN_NAME = "bean.name" - FAIL_BACK_TASKS_KEY = "failbacktasks" - FORKS_KEY = "forks" - DEFAULT_FORKS = 2 - DEFAULT_TIMEOUT = 1000 - ACCESS_LOG_KEY = "accesslog" + TIMESTAMP_KEY = "timestamp" + REMOTE_TIMESTAMP_KEY = "remote.timestamp" + CLUSTER_KEY = "cluster" + LOADBALANCE_KEY = "loadbalance" + WEIGHT_KEY = "weight" + WARMUP_KEY = "warmup" + RETRIES_KEY = "retries" + BEAN_NAME = "bean.name" + FAIL_BACK_TASKS_KEY = "failbacktasks" + FORKS_KEY = "forks" + DEFAULT_FORKS = 2 + DEFAULT_TIMEOUT = 1000 + ACCESS_LOG_KEY = "accesslog" + TPS_LIMITER_KEY = "tps.limiter" + TPS_REJECTED_EXECUTION_HANDLER_KEY = "tps.limit.rejected.handler" + TPS_LIMIT_RATE_KEY = "tps.limit.rate" + DEFAULT_TPS_LIMIT_RATE = "-1" + TPS_LIMIT_INTERVAL_KEY = "tps.limit.interval" + DEFAULT_TPS_LIMIT_INTERVAL = "60000" + TPS_LIMIT_STRATEGY_KEY = "tps.limit.strategy" ) const ( diff --git a/common/extension/tps_limit.go b/common/extension/tps_limit.go new file mode 100644 index 0000000000..3427201831 --- /dev/null +++ b/common/extension/tps_limit.go @@ -0,0 +1,65 @@ +/* + * 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 extension + +import "github.com/apache/dubbo-go/filter" + +var ( + tpsLimitStrategy = make(map[string]func(rate int, interval int) filter.TpsLimitStrategy) + tpsLimiter = make(map[string]func() filter.TpsLimiter) + tpsRejectedExecutionHandler = make(map[string]func() filter.RejectedExecutionHandler) +) + +func SetTpsLimiter(name string, creator func() filter.TpsLimiter) { + tpsLimiter[name] = creator +} + +func GetTpsLimiter(name string) filter.TpsLimiter { + var creator = tpsLimiter[name] + if creator == nil { + panic("TpsLimiter for " + name + " is not existing, make sure you have import the package " + + "and you have register it by invoking extension.SetTpsLimiter.") + } + return creator() +} + +func SetTpsLimitStrategy(name string, creator func(rate int, interval int) filter.TpsLimitStrategy) { + tpsLimitStrategy[name] = creator +} + +func GetTpsLimitStrategyCreator(name string) func(rate int, interval int) filter.TpsLimitStrategy { + var creator = tpsLimitStrategy[name] + if creator == nil { + panic("TpsLimitStrategy for " + name + " is not existing, make sure you have import the package " + + "and you have register it by invoking extension.SetTpsLimitStrategy.") + } + return creator +} + +func SetTpsRejectedExecutionHandler(name string, creator func() filter.RejectedExecutionHandler) { + tpsRejectedExecutionHandler[name] = creator +} + +func GetTpsRejectedExecutionHandler(name string) filter.RejectedExecutionHandler { + var creator = tpsRejectedExecutionHandler[name] + if creator() == nil { + panic("TpsRejectedExecutionHandler for " + name + " is not existing, make sure you have import the package " + + "and you have register it by invoking extension.SetTpsRejectedExecutionHandler.") + } + return creator() +} \ No newline at end of file diff --git a/filter/impl/access_log_filter.go b/filter/impl/access_log_filter.go index 75c0582937..89fa34952f 100644 --- a/filter/impl/access_log_filter.go +++ b/filter/impl/access_log_filter.go @@ -132,7 +132,7 @@ func (ef *AccessLogFilter) writeLogToFile(data AccessLogData) { logFile, err := ef.openLogFile(accessLog) if err != nil { - logger.Warnf("Can not open the access log file: %s, %v", accessLog, err) + logger.Warnf("Can not open the access log file: %s, %v", accessLog, err) return } logger.Debugf("Append log to %s", accessLog) diff --git a/filter/impl/only_log_rejected_execution_handler.go b/filter/impl/only_log_rejected_execution_handler.go new file mode 100644 index 0000000000..8ce4a44593 --- /dev/null +++ b/filter/impl/only_log_rejected_execution_handler.go @@ -0,0 +1,61 @@ +/* + * 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 impl + +import ( + "sync" + + "github.com/prometheus/common/log" + + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/protocol" +) + +const HandlerName = "log" + +func init() { + extension.SetTpsRejectedExecutionHandler(HandlerName, GetOnlyRejectedExecutionHandler) + extension.SetTpsRejectedExecutionHandler(constant.DEFAULT_KEY, GetOnlyRejectedExecutionHandler) +} + +var onlyLogHandlerInstance *OnlyLogRejectedExecutionHandler +var onlyLogHandlerOnce sync.Once + +/** + * This implementation only logs the invocation info. + * it always return nil. + */ +type OnlyLogRejectedExecutionHandler struct { + +} + +func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result { + log.Warnf("The invocation was rejected. url: %s", url.String()) + return nil +} + +func GetOnlyRejectedExecutionHandler() filter.RejectedExecutionHandler { + onlyLogHandlerOnce.Do(func() { + onlyLogHandlerInstance = &OnlyLogRejectedExecutionHandler{} + }) + return onlyLogHandlerInstance +} + diff --git a/filter/impl/tps_limit_filter.go b/filter/impl/tps_limit_filter.go index 6ada1aa61a..ae900a33a3 100644 --- a/filter/impl/tps_limit_filter.go +++ b/filter/impl/tps_limit_filter.go @@ -18,6 +18,7 @@ package impl import ( + "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/filter" "github.com/apache/dubbo-go/protocol" @@ -28,19 +29,37 @@ const ( ) func init() { - extension.SetFilter(TpsLimitFilterKey, GetAccessLogFilter) + extension.SetFilter(TpsLimitFilterKey, GetTpsLimitFilter) } /** - * + * if you wish to use the TpsLimiter, please add the configuration into your service provider configuration: + * for example: + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service", # it should be the name of limiter. if the value is 'default', + * # the MethodServiceTpsLimiterImpl will be used. + * tps.limit.rejected.handler: "default", # optional, or the name of the implementation + * if the value of 'tps.limiter' is nil or empty string, the tps filter will do nothing */ type TpsLimitFilter struct { } func (t TpsLimitFilter) Invoke(invoker protocol.Invoker,invocation protocol.Invocation) protocol.Result { - invoker.GetUrl() - invoker.IsAvailable() + url := invoker.GetUrl() + tpsLimiter := url.GetParam(constant.TPS_LIMITER_KEY, "") + rejectedExeHandler := url.GetParam(constant.TPS_REJECTED_EXECUTION_HANDLER_KEY, constant.DEFAULT_KEY) + if len(tpsLimiter) > 0 { + allow := extension.GetTpsLimiter(tpsLimiter).IsAllowable(invoker.GetUrl(), invocation) + if allow { + return invoker.Invoke(invocation) + } + return extension.GetTpsRejectedExecutionHandler(rejectedExeHandler).RejectedExecution(url, invocation) + } return invoker.Invoke(invocation) } @@ -49,6 +68,5 @@ func (t TpsLimitFilter) OnResponse(result protocol.Result, invoker protocol.Invo } func GetTpsLimitFilter() filter.Filter { - var tpsLimitFilter = TpsLimitFilter{} - return tpsLimitFilter + return &TpsLimitFilter{} } diff --git a/filter/impl/tps_limit_filter_test.go b/filter/impl/tps_limit_filter_test.go index 2ac8beceba..236f42c95c 100644 --- a/filter/impl/tps_limit_filter_test.go +++ b/filter/impl/tps_limit_filter_test.go @@ -16,3 +16,82 @@ */ package impl + +import ( + "net/url" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/protocol" + "github.com/apache/dubbo-go/protocol/invocation" +) + +func TestTpsLimitFilter_Invoke_With_No_TpsLimiter(t *testing.T) { + tpsFilter := GetTpsLimitFilter() + invokeUrl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.TPS_LIMITER_KEY, "")) + attch := make(map[string]string, 0) + + result := tpsFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), + invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch)) + assert.Nil(t, result.Error()) + assert.Nil(t, result.Result()) + +} + +func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mockLimiter := filter.NewMockTpsLimiter(ctrl) + mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(true).Times(1) + extension.SetTpsLimiter(constant.DEFAULT_KEY, func() filter.TpsLimiter { + return mockLimiter + }) + + tpsFilter := GetTpsLimitFilter() + invokeUrl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.TPS_LIMITER_KEY, constant.DEFAULT_KEY)) + attch := make(map[string]string, 0) + + result := tpsFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), + invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch)) + assert.Nil(t, result.Error()) + assert.Nil(t, result.Result()) +} + +func TestGenericFilter_Invoke_With_Default_TpsLimiter_Not_Allow(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mockLimiter := filter.NewMockTpsLimiter(ctrl) + mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(false).Times(1) + extension.SetTpsLimiter(constant.DEFAULT_KEY, func() filter.TpsLimiter { + return mockLimiter + }) + + mockResult := &protocol.RPCResult{} + mockRejectedHandler := filter.NewMockRejectedExecutionHandler(ctrl) + mockRejectedHandler.EXPECT().RejectedExecution(gomock.Any(), gomock.Any()).Return(mockResult).Times(1) + + extension.SetTpsRejectedExecutionHandler(constant.DEFAULT_KEY, func() filter.RejectedExecutionHandler { + return mockRejectedHandler + }) + + tpsFilter := GetTpsLimitFilter() + invokeUrl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.TPS_LIMITER_KEY, constant.DEFAULT_KEY)) + attch := make(map[string]string, 0) + + result := tpsFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), + invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch)) + assert.Nil(t, result.Error()) + assert.Nil(t, result.Result()) +} diff --git a/filter/impl/tps_limiter_method_service_impl.go b/filter/impl/tps_limiter_method_service_impl.go new file mode 100644 index 0000000000..8ea32c2ae4 --- /dev/null +++ b/filter/impl/tps_limiter_method_service_impl.go @@ -0,0 +1,136 @@ +/* + * 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 impl + +import ( + "fmt" + "strconv" + "sync" + + "github.com/modern-go/concurrent" + + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/protocol" +) + +const name = "method-service" + +func init() { + extension.SetTpsLimiter(constant.DEFAULT_KEY, GetMethodServiceTpsLimiter) + extension.SetTpsLimiter(name, GetMethodServiceTpsLimiter) +} + +/** + * This implementation allows developer to config both method-level and service-level tps limiter. + * for example: + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too. + * tps.interval: 5000 # interval, the time unit is ms + * tps.rate: 300 # the max value in the interval. <0 means that the service will not be limited. + * methods: + * - name: "GetUser" + * tps.interval: 3000 + * tps.rate: 20, # in this case, this configuration in service-level will be ignored. + * - name: "UpdateUser" + * tps.rate: -1, # If the rate<0, the method will be ignored + */ +type MethodServiceTpsLimiterImpl struct { + tpsState *concurrent.Map +} + +func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocation protocol.Invocation) bool { + + serviceLimitRate, err:= strconv.ParseInt(url.GetParam(constant.TPS_LIMIT_RATE_KEY, + constant.DEFAULT_TPS_LIMIT_RATE), 0, 0) + + if err != nil { + panic(fmt.Sprintf("Can not parse the %s for url %s, please check your configuration!", + constant.TPS_LIMIT_RATE_KEY, url.String())) + } + methodLimitRateConfig := invocation.AttachmentsByKey(constant.TPS_LIMIT_RATE_KEY, "") + + // both method-level and service-level don't have the configuration of tps limit + if serviceLimitRate < 0 && len(methodLimitRateConfig) <= 0 { + return true + } + + limitRate := serviceLimitRate + // the method has tps limit configuration + if len(methodLimitRateConfig) >0 { + limitRate, err = strconv.ParseInt(methodLimitRateConfig, 0, 0) + if err != nil { + panic(fmt.Sprintf("Can not parse the %s for invocation %s # %s, please check your configuration!", + constant.TPS_LIMIT_RATE_KEY, url.ServiceKey(), invocation.MethodName())) + } + } + + // 1. the serviceLimitRate < 0 and methodRateConfig is empty string + // 2. the methodLimitRate < 0 + if limitRate < 0{ + return true + } + + serviceInterval, err := strconv.ParseInt(url.GetParam(constant.TPS_LIMIT_INTERVAL_KEY, + constant.DEFAULT_TPS_LIMIT_INTERVAL), 0, 0) + + if err != nil || serviceInterval <= 0{ + panic(fmt.Sprintf("The %s must be positive, please check your configuration!", + constant.TPS_LIMIT_INTERVAL_KEY)) + } + limitInterval := serviceInterval + methodIntervalConfig := invocation.AttachmentsByKey(constant.TPS_LIMIT_INTERVAL_KEY, "") + // there is the interval configuration of method-level + if len(methodIntervalConfig) > 0 { + limitInterval, err = strconv.ParseInt(methodIntervalConfig, 0, 0) + if err != nil || limitInterval <= 0{ + panic(fmt.Sprintf("The %s for invocation %s # %s must be positive, please check your configuration!", + constant.TPS_LIMIT_INTERVAL_KEY, url.ServiceKey(), invocation.MethodName())) + } + } + + limitTarget := url.ServiceKey() + + // method-level tps limit + if len(methodIntervalConfig) > 0 || len(methodLimitRateConfig) >0 { + limitTarget = limitTarget + "#" + invocation.MethodName() + } + + limitStrategyConfig := invocation.AttachmentsByKey(constant.TPS_LIMIT_STRATEGY_KEY, + url.GetParam(constant.TPS_LIMIT_STRATEGY_KEY, constant.DEFAULT_KEY)) + limitStateCreator := extension.GetTpsLimitStrategyCreator(limitStrategyConfig) + limitState, _ := limiter.tpsState.LoadOrStore(limitTarget, limitStateCreator(int(limitRate), int(limitInterval))) + return limitState.(filter.TpsLimitStrategy).IsAllowable() +} + +var methodServiceTpsLimiterInstance *MethodServiceTpsLimiterImpl +var methodServiceTpsLimiterOnce sync.Once + +func GetMethodServiceTpsLimiter() filter.TpsLimiter { + methodServiceTpsLimiterOnce.Do(func() { + methodServiceTpsLimiterInstance = &MethodServiceTpsLimiterImpl{ + tpsState: concurrent.NewMap(), + } + }) + return methodServiceTpsLimiterInstance +} diff --git a/filter/impl/tps_limiter.go b/filter/rejected_execution_handler.go similarity index 86% rename from filter/impl/tps_limiter.go rename to filter/rejected_execution_handler.go index ee24c8c1b2..1773edcbd6 100644 --- a/filter/impl/tps_limiter.go +++ b/filter/rejected_execution_handler.go @@ -14,14 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -package impl +package filter import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/protocol" ) -type TpsLimiter interface { - IsAllowable(common.URL, protocol.Invocation) -} \ No newline at end of file +type RejectedExecutionHandler interface { + RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result +} diff --git a/filter/rejected_execution_handler_mock.go b/filter/rejected_execution_handler_mock.go new file mode 100644 index 0000000000..20c3e575bb --- /dev/null +++ b/filter/rejected_execution_handler_mock.go @@ -0,0 +1,65 @@ +// 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. +// + +// Code generated by MockGen. DO NOT EDIT. +// Source: rejected_execution_handler.go + +// Package filter is a generated GoMock package. +package filter + +import ( + common "github.com/apache/dubbo-go/common" + protocol "github.com/apache/dubbo-go/protocol" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockRejectedExecutionHandler is a mock of RejectedExecutionHandler interface +type MockRejectedExecutionHandler struct { + ctrl *gomock.Controller + recorder *MockRejectedExecutionHandlerMockRecorder +} + +// MockRejectedExecutionHandlerMockRecorder is the mock recorder for MockRejectedExecutionHandler +type MockRejectedExecutionHandlerMockRecorder struct { + mock *MockRejectedExecutionHandler +} + +// NewMockRejectedExecutionHandler creates a new mock instance +func NewMockRejectedExecutionHandler(ctrl *gomock.Controller) *MockRejectedExecutionHandler { + mock := &MockRejectedExecutionHandler{ctrl: ctrl} + mock.recorder = &MockRejectedExecutionHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockRejectedExecutionHandler) EXPECT() *MockRejectedExecutionHandlerMockRecorder { + return m.recorder +} + +// RejectedExecution mocks base method +func (m *MockRejectedExecutionHandler) RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RejectedExecution", url, invocation) + ret0, _ := ret[0].(protocol.Result) + return ret0 +} + +// RejectedExecution indicates an expected call of RejectedExecution +func (mr *MockRejectedExecutionHandlerMockRecorder) RejectedExecution(url, invocation interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RejectedExecution", reflect.TypeOf((*MockRejectedExecutionHandler)(nil).RejectedExecution), url, invocation) +} diff --git a/filter/impl/tps_limiter_fixed_window_impl.go b/filter/tps_limit_strategy.go similarity index 71% rename from filter/impl/tps_limiter_fixed_window_impl.go rename to filter/tps_limit_strategy.go index 6f4a3360f9..da51440541 100644 --- a/filter/impl/tps_limiter_fixed_window_impl.go +++ b/filter/tps_limit_strategy.go @@ -15,21 +15,11 @@ * limitations under the License. */ -package impl - -import ( - "github.com/apache/dubbo-go/common" - "github.com/apache/dubbo-go/protocol" -) - -type FixedWindowTpsLimiterImpl struct { - -} - -func (limiter FixedWindowTpsLimiterImpl) IsAllowable(common.URL, protocol.Invocation) { - panic("implement me") +package filter +/* + * please register your implementation by invoking SetTpsLimitStrategy + */ +type TpsLimitStrategy interface { + IsAllowable() bool } -func NewInstance() TpsLimiter { - return FixedWindowTpsLimiterImpl{} -} diff --git a/filter/tps_limiter.go b/filter/tps_limiter.go new file mode 100644 index 0000000000..ca945cc700 --- /dev/null +++ b/filter/tps_limiter.go @@ -0,0 +1,39 @@ +/* + * 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 filter + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/protocol" +) +/* + * please register your implementation by invoking SetTpsLimiter + * The usage, for example: + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "the name of limiter", + */ +type TpsLimiter interface { + IsAllowable(common.URL, protocol.Invocation) bool +} + + + diff --git a/filter/tps_limiter_mock.go b/filter/tps_limiter_mock.go new file mode 100644 index 0000000000..5fbf717614 --- /dev/null +++ b/filter/tps_limiter_mock.go @@ -0,0 +1,65 @@ +// 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. +// + +// Code generated by MockGen. DO NOT EDIT. +// Source: tps_limiter.go + +// Package filter is a generated GoMock package. +package filter + +import ( + common "github.com/apache/dubbo-go/common" + protocol "github.com/apache/dubbo-go/protocol" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockTpsLimiter is a mock of TpsLimiter interface +type MockTpsLimiter struct { + ctrl *gomock.Controller + recorder *MockTpsLimiterMockRecorder +} + +// MockTpsLimiterMockRecorder is the mock recorder for MockTpsLimiter +type MockTpsLimiterMockRecorder struct { + mock *MockTpsLimiter +} + +// NewMockTpsLimiter creates a new mock instance +func NewMockTpsLimiter(ctrl *gomock.Controller) *MockTpsLimiter { + mock := &MockTpsLimiter{ctrl: ctrl} + mock.recorder = &MockTpsLimiterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockTpsLimiter) EXPECT() *MockTpsLimiterMockRecorder { + return m.recorder +} + +// IsAllowable mocks base method +func (m *MockTpsLimiter) IsAllowable(arg0 common.URL, arg1 protocol.Invocation) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsAllowable", arg0, arg1) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsAllowable indicates an expected call of IsAllowable +func (mr *MockTpsLimiterMockRecorder) IsAllowable(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAllowable", reflect.TypeOf((*MockTpsLimiter)(nil).IsAllowable), arg0, arg1) +} diff --git a/go.mod b/go.mod index be1c80bd17..8171e8e429 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/apache/dubbo-go require ( github.com/Workiva/go-datastructures v1.0.50 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 + github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect + github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e // indirect github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190923055845-e3dd5d131df5 github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 // indirect @@ -34,11 +36,12 @@ require ( github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v1.1.0 // indirect + github.com/prometheus/common v0.6.0 github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec github.com/satori/go.uuid v1.2.0 github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect github.com/soheilhy/cmux v0.1.4 // indirect - github.com/stretchr/testify v1.3.0 + github.com/stretchr/testify v1.4.0 github.com/tebeka/strftime v0.1.3 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // indirect diff --git a/go.sum b/go.sum index 19b148133b..3ae72390a6 100644 --- a/go.sum +++ b/go.sum @@ -31,7 +31,11 @@ github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJM github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e h1:MSuLXx/mveDbpDNhVrcWTMeV4lbYWKcyO4rH+jAxmX0= github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= @@ -446,6 +450,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto= github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ= github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9/go.mod h1:RHkNRtSLfOK7qBTHaeSX1D6BNpI3qw7NTxsmNr4RvN8= @@ -534,6 +540,7 @@ google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= From dec6c16d4e70f7f06b4dd5af6a1ac557bbc53a39 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Mon, 14 Oct 2019 22:24:25 +0800 Subject: [PATCH 03/12] Refactor MethodServiceTpsLimitImpl; Read config from yml --- config/method_config.go | 15 +-- config/service_config.go | 78 +++++++++------- .../impl/tps_limiter_method_service_impl.go | 92 +++++++++---------- 3 files changed, 102 insertions(+), 83 deletions(-) diff --git a/config/method_config.go b/config/method_config.go index ac9242a230..431a30c1dd 100644 --- a/config/method_config.go +++ b/config/method_config.go @@ -25,12 +25,15 @@ import ( ) type MethodConfig struct { - InterfaceId string - InterfaceName string - Name string `yaml:"name" json:"name,omitempty" property:"name"` - Retries string `yaml:"retries" json:"retries,omitempty" property:"retries"` - Loadbalance string `yaml:"loadbalance" json:"loadbalance,omitempty" property:"loadbalance"` - Weight int64 `yaml:"weight" json:"weight,omitempty" property:"weight"` + InterfaceId string + InterfaceName string + Name string `yaml:"name" json:"name,omitempty" property:"name"` + Retries string `yaml:"retries" json:"retries,omitempty" property:"retries"` + Loadbalance string `yaml:"loadbalance" json:"loadbalance,omitempty" property:"loadbalance"` + Weight int64 `yaml:"weight" json:"weight,omitempty" property:"weight"` + TpsLimitInterval string `yaml:"tps.limit.interval" json:"tps.limit.interval,omitempty" property:"tps.limit.interval"` + TpsLimitRate string `yaml:"tps.limit.rate" json:"tps.limit.rate,omitempty" property:"tps.limit.rate"` + TpsLimitStrategy string `yaml:"tps.limit.strategy" json:"tps.limit.strategy,omitempty" property:"tps.limit.strategy"` } func (c *MethodConfig) Prefix() string { diff --git a/config/service_config.go b/config/service_config.go index ee0457937e..784257b8c7 100644 --- a/config/service_config.go +++ b/config/service_config.go @@ -43,27 +43,32 @@ import ( ) type ServiceConfig struct { - context context.Context - id string - Filter string `yaml:"filter" json:"filter,omitempty" property:"filter"` - Protocol string `default:"dubbo" required:"true" yaml:"protocol" json:"protocol,omitempty" property:"protocol"` //multi protocol support, split by ',' - InterfaceName string `required:"true" yaml:"interface" json:"interface,omitempty" property:"interface"` - Registry string `yaml:"registry" json:"registry,omitempty" property:"registry"` - Cluster string `default:"failover" yaml:"cluster" json:"cluster,omitempty" property:"cluster"` - Loadbalance string `default:"random" yaml:"loadbalance" json:"loadbalance,omitempty" property:"loadbalance"` - Group string `yaml:"group" json:"group,omitempty" property:"group"` - Version string `yaml:"version" json:"version,omitempty" property:"version" ` - Methods []*MethodConfig `yaml:"methods" json:"methods,omitempty" property:"methods"` - Warmup string `yaml:"warmup" json:"warmup,omitempty" property:"warmup"` - Retries string `yaml:"retries" json:"retries,omitempty" property:"retries"` - Params map[string]string `yaml:"params" json:"params,omitempty" property:"params"` - Token string `yaml:"token" json:"token,omitempty" property:"token"` - AccessLog string `yaml:"accesslog" json:"accesslog,omitempty" property:"accesslog"` - unexported *atomic.Bool - exported *atomic.Bool - rpcService common.RPCService - cacheProtocol protocol.Protocol - cacheMutex sync.Mutex + context context.Context + id string + Filter string `yaml:"filter" json:"filter,omitempty" property:"filter"` + Protocol string `default:"dubbo" required:"true" yaml:"protocol" json:"protocol,omitempty" property:"protocol"` // multi protocol support, split by ',' + InterfaceName string `required:"true" yaml:"interface" json:"interface,omitempty" property:"interface"` + Registry string `yaml:"registry" json:"registry,omitempty" property:"registry"` + Cluster string `default:"failover" yaml:"cluster" json:"cluster,omitempty" property:"cluster"` + Loadbalance string `default:"random" yaml:"loadbalance" json:"loadbalance,omitempty" property:"loadbalance"` + Group string `yaml:"group" json:"group,omitempty" property:"group"` + Version string `yaml:"version" json:"version,omitempty" property:"version" ` + Methods []*MethodConfig `yaml:"methods" json:"methods,omitempty" property:"methods"` + Warmup string `yaml:"warmup" json:"warmup,omitempty" property:"warmup"` + Retries string `yaml:"retries" json:"retries,omitempty" property:"retries"` + Params map[string]string `yaml:"params" json:"params,omitempty" property:"params"` + Token string `yaml:"token" json:"token,omitempty" property:"token"` + AccessLog string `yaml:"accesslog" json:"accesslog,omitempty" property:"accesslog"` + TpsLimiter string `yaml:"tps.limiter" json:"tps.limiter,omitempty" property:"tps.limiter"` + TpsLimitInterval string `yaml:"tps.limit.interval" json:"tps.limit.interval,omitempty" property:"tps.limit.interval"` + TpsLimitRate string `yaml:"tps.limit.rate" json:"tps.limit.rate,omitempty" property:"tps.limit.rate"` + TpsLimitStrategy string `yaml:"tps.limit.strategy" json:"tps.limit.strategy,omitempty" property:"tps.limit.strategy"` + TpsLimitRejectedHandler string `yaml:"tps.limit.rejected.handler" json:"tps.limit.rejected.handler,omitempty" property:"tps.limit.rejected.handler"` + unexported *atomic.Bool + exported *atomic.Bool + rpcService common.RPCService + cacheProtocol protocol.Protocol + cacheMutex sync.Mutex } func (c *ServiceConfig) Prefix() string { @@ -94,9 +99,9 @@ func NewServiceConfig(id string, context context.Context) *ServiceConfig { } func (srvconfig *ServiceConfig) Export() error { - //TODO: config center start here + // TODO: config center start here - //TODO:delay export + // TODO:delay export if srvconfig.unexported != nil && srvconfig.unexported.Load() { err := perrors.Errorf("The service %v has already unexported! ", srvconfig.InterfaceName) logger.Errorf(err.Error()) @@ -111,7 +116,7 @@ func (srvconfig *ServiceConfig) Export() error { urlMap := srvconfig.getUrlMap() for _, proto := range loadProtocol(srvconfig.Protocol, providerConfig.Protocols) { - //registry the service reflect + // registry the service reflect methods, err := common.ServiceMap.Register(proto.Name, srvconfig.rpcService) if err != nil { err := perrors.Errorf("The service %v export the protocol %v error! Error message is %v .", srvconfig.InterfaceName, proto.Name, err.Error()) @@ -164,7 +169,7 @@ func (srvconfig *ServiceConfig) Implement(s common.RPCService) { func (srvconfig *ServiceConfig) getUrlMap() url.Values { urlMap := url.Values{} - //first set user params + // first set user params for k, v := range srvconfig.Params { urlMap.Set(k, v) } @@ -177,7 +182,7 @@ func (srvconfig *ServiceConfig) getUrlMap() url.Values { urlMap.Set(constant.GROUP_KEY, srvconfig.Group) urlMap.Set(constant.VERSION_KEY, srvconfig.Version) urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)) - //application info + // application info urlMap.Set(constant.APPLICATION_KEY, providerConfig.ApplicationConfig.Name) urlMap.Set(constant.ORGANIZATION_KEY, providerConfig.ApplicationConfig.Organization) urlMap.Set(constant.NAME_KEY, providerConfig.ApplicationConfig.Name) @@ -186,16 +191,27 @@ func (srvconfig *ServiceConfig) getUrlMap() url.Values { urlMap.Set(constant.OWNER_KEY, providerConfig.ApplicationConfig.Owner) urlMap.Set(constant.ENVIRONMENT_KEY, providerConfig.ApplicationConfig.Environment) - //filter + // filter urlMap.Set(constant.SERVICE_FILTER_KEY, mergeValue(providerConfig.Filter, srvconfig.Filter, constant.DEFAULT_SERVICE_FILTERS)) - //filter special config + // filter special config urlMap.Set(constant.ACCESS_LOG_KEY, srvconfig.AccessLog) + // tps limiter + urlMap.Set(constant.TPS_LIMIT_STRATEGY_KEY, srvconfig.TpsLimitStrategy) + urlMap.Set(constant.TPS_LIMIT_INTERVAL_KEY, srvconfig.TpsLimitInterval) + urlMap.Set(constant.TPS_LIMIT_RATE_KEY, srvconfig.TpsLimitRate) + urlMap.Set(constant.TPS_LIMITER_KEY, srvconfig.TpsLimiter) + urlMap.Set(constant.TPS_REJECTED_EXECUTION_HANDLER_KEY, srvconfig.TpsLimitRejectedHandler) for _, v := range srvconfig.Methods { - urlMap.Set("methods."+v.Name+"."+constant.LOADBALANCE_KEY, v.Loadbalance) - urlMap.Set("methods."+v.Name+"."+constant.RETRIES_KEY, v.Retries) - urlMap.Set("methods."+v.Name+"."+constant.WEIGHT_KEY, strconv.FormatInt(v.Weight, 10)) + prefix := "methods." + v.Name + "." + urlMap.Set(prefix+constant.LOADBALANCE_KEY, v.Loadbalance) + urlMap.Set(prefix+constant.RETRIES_KEY, v.Retries) + urlMap.Set(prefix+constant.WEIGHT_KEY, strconv.FormatInt(v.Weight, 10)) + + urlMap.Set(prefix+constant.TPS_LIMIT_STRATEGY_KEY, srvconfig.TpsLimitStrategy) + urlMap.Set(prefix+constant.TPS_LIMIT_INTERVAL_KEY, srvconfig.TpsLimitInterval) + urlMap.Set(prefix+constant.TPS_LIMIT_RATE_KEY, srvconfig.TpsLimitRate) } return urlMap diff --git a/filter/impl/tps_limiter_method_service_impl.go b/filter/impl/tps_limiter_method_service_impl.go index 8ea32c2ae4..2a30c30b14 100644 --- a/filter/impl/tps_limiter_method_service_impl.go +++ b/filter/impl/tps_limiter_method_service_impl.go @@ -46,8 +46,8 @@ func init() { * interface : "com.ikurento.user.UserProvider" * ... # other configuration * tps.limiter: "method-service" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too. - * tps.interval: 5000 # interval, the time unit is ms - * tps.rate: 300 # the max value in the interval. <0 means that the service will not be limited. + * tps.limit.interval: 5000 # interval, the time unit is ms + * tps.limit.rate: 300 # the max value in the interval. <0 means that the service will not be limited. * methods: * - name: "GetUser" * tps.interval: 3000 @@ -61,66 +61,66 @@ type MethodServiceTpsLimiterImpl struct { func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocation protocol.Invocation) bool { - serviceLimitRate, err:= strconv.ParseInt(url.GetParam(constant.TPS_LIMIT_RATE_KEY, - constant.DEFAULT_TPS_LIMIT_RATE), 0, 0) + methodConfigPrefix := "methods." + invocation.MethodName() + "." - if err != nil { - panic(fmt.Sprintf("Can not parse the %s for url %s, please check your configuration!", - constant.TPS_LIMIT_RATE_KEY, url.String())) - } - methodLimitRateConfig := invocation.AttachmentsByKey(constant.TPS_LIMIT_RATE_KEY, "") + methodLimitRateConfig := url.GetParam(methodConfigPrefix+constant.TPS_LIMIT_RATE_KEY, "") + methodIntervalConfig := url.GetParam(methodConfigPrefix+constant.TPS_LIMIT_INTERVAL_KEY, "") - // both method-level and service-level don't have the configuration of tps limit - if serviceLimitRate < 0 && len(methodLimitRateConfig) <= 0 { - return true + limitTarget := url.ServiceKey() + + // method-level tps limit + if len(methodIntervalConfig) > 0 || len(methodLimitRateConfig) > 0 { + limitTarget = limitTarget + "#" + invocation.MethodName() } - limitRate := serviceLimitRate - // the method has tps limit configuration - if len(methodLimitRateConfig) >0 { - limitRate, err = strconv.ParseInt(methodLimitRateConfig, 0, 0) - if err != nil { - panic(fmt.Sprintf("Can not parse the %s for invocation %s # %s, please check your configuration!", - constant.TPS_LIMIT_RATE_KEY, url.ServiceKey(), invocation.MethodName())) - } + limitState, found := limiter.tpsState.Load(limitTarget) + if found { + return limitState.(filter.TpsLimitStrategy).IsAllowable() } - // 1. the serviceLimitRate < 0 and methodRateConfig is empty string - // 2. the methodLimitRate < 0 - if limitRate < 0{ + limitRate := getLimitConfig(methodLimitRateConfig, url, invocation, + constant.TPS_LIMIT_RATE_KEY, + constant.DEFAULT_TPS_LIMIT_RATE) + + if limitRate < 0 { return true } - serviceInterval, err := strconv.ParseInt(url.GetParam(constant.TPS_LIMIT_INTERVAL_KEY, - constant.DEFAULT_TPS_LIMIT_INTERVAL), 0, 0) - - if err != nil || serviceInterval <= 0{ - panic(fmt.Sprintf("The %s must be positive, please check your configuration!", - constant.TPS_LIMIT_INTERVAL_KEY)) + limitInterval := getLimitConfig(methodIntervalConfig, url, invocation, + constant.TPS_LIMIT_INTERVAL_KEY, + constant.DEFAULT_TPS_LIMIT_INTERVAL) + if limitInterval <= 0{ + panic(fmt.Sprintf("The interval must be positive, please check your configuration! url: %s", url.String())) } - limitInterval := serviceInterval - methodIntervalConfig := invocation.AttachmentsByKey(constant.TPS_LIMIT_INTERVAL_KEY, "") - // there is the interval configuration of method-level - if len(methodIntervalConfig) > 0 { - limitInterval, err = strconv.ParseInt(methodIntervalConfig, 0, 0) - if err != nil || limitInterval <= 0{ + + limitStrategyConfig := url.GetParam(methodConfigPrefix+constant.TPS_LIMIT_STRATEGY_KEY, + url.GetParam(constant.TPS_LIMIT_STRATEGY_KEY, constant.DEFAULT_KEY)) + limitStateCreator := extension.GetTpsLimitStrategyCreator(limitStrategyConfig) + limitState, _ = limiter.tpsState.LoadOrStore(limitTarget, limitStateCreator(int(limitRate), int(limitInterval))) + return limitState.(filter.TpsLimitStrategy).IsAllowable() +} + +func getLimitConfig(methodLevelConfig string, + url common.URL, + invocation protocol.Invocation, + configKey string, + defaultVal string) int64 { + + if len(methodLevelConfig) > 0 { + result, err := strconv.ParseInt(methodLevelConfig, 0, 0) + if err != nil { panic(fmt.Sprintf("The %s for invocation %s # %s must be positive, please check your configuration!", - constant.TPS_LIMIT_INTERVAL_KEY, url.ServiceKey(), invocation.MethodName())) + configKey, url.ServiceKey(), invocation.MethodName())) } + return result } - limitTarget := url.ServiceKey() + result, err := strconv.ParseInt(url.GetParam(configKey, defaultVal), 0, 0) - // method-level tps limit - if len(methodIntervalConfig) > 0 || len(methodLimitRateConfig) >0 { - limitTarget = limitTarget + "#" + invocation.MethodName() + if err != nil { + panic(fmt.Sprintf("Cannot parse the configuration %s, please check your configuration!", configKey)) } - - limitStrategyConfig := invocation.AttachmentsByKey(constant.TPS_LIMIT_STRATEGY_KEY, - url.GetParam(constant.TPS_LIMIT_STRATEGY_KEY, constant.DEFAULT_KEY)) - limitStateCreator := extension.GetTpsLimitStrategyCreator(limitStrategyConfig) - limitState, _ := limiter.tpsState.LoadOrStore(limitTarget, limitStateCreator(int(limitRate), int(limitInterval))) - return limitState.(filter.TpsLimitStrategy).IsAllowable() + return result } var methodServiceTpsLimiterInstance *MethodServiceTpsLimiterImpl From 57b63db2aee014486d5cfc94a9ed8d372e053cea Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Tue, 15 Oct 2019 22:20:55 +0800 Subject: [PATCH 04/12] Finish Test --- common/extension/tps_limit.go | 8 +- config/service_config.go | 6 +- ...jected_execution_handler_only_log_impl.go} | 14 +- filter/impl/tps_limit_filter.go | 3 +- filter/impl/tps_limit_filter_test.go | 6 +- .../tps_limit_fix_window_strategy_impl.go | 85 ++++++++++++ ...tps_limit_fix_window_strategy_impl_test.go | 43 ++++++ .../tps_limit_sliding_window_strategy_impl.go | 90 +++++++++++++ ...limit_sliding_window_strategy_impl_test.go | 45 +++++++ ...it_thread_safe_fix_window_strategy_impl.go | 65 +++++++++ ...read_safe_fix_window_strategy_impl_test.go | 43 ++++++ .../impl/tps_limiter_method_service_impl.go | 60 ++++++++- .../tps_limiter_method_service_impl_test.go | 125 ++++++++++++++++++ filter/tps_limit_strategy.go | 2 +- filter/tps_limit_strategy_mock.go | 63 +++++++++ filter/tps_limiter.go | 4 +- go.mod | 1 + 17 files changed, 639 insertions(+), 24 deletions(-) rename filter/impl/{only_log_rejected_execution_handler.go => rejected_execution_handler_only_log_impl.go} (89%) create mode 100644 filter/impl/tps_limit_fix_window_strategy_impl.go create mode 100644 filter/impl/tps_limit_fix_window_strategy_impl_test.go create mode 100644 filter/impl/tps_limit_sliding_window_strategy_impl.go create mode 100644 filter/impl/tps_limit_sliding_window_strategy_impl_test.go create mode 100644 filter/impl/tps_limit_thread_safe_fix_window_strategy_impl.go create mode 100644 filter/impl/tps_limit_thread_safe_fix_window_strategy_impl_test.go create mode 100644 filter/impl/tps_limiter_method_service_impl_test.go create mode 100644 filter/tps_limit_strategy_mock.go diff --git a/common/extension/tps_limit.go b/common/extension/tps_limit.go index 3427201831..70c71cbc4b 100644 --- a/common/extension/tps_limit.go +++ b/common/extension/tps_limit.go @@ -20,8 +20,8 @@ package extension import "github.com/apache/dubbo-go/filter" var ( - tpsLimitStrategy = make(map[string]func(rate int, interval int) filter.TpsLimitStrategy) - tpsLimiter = make(map[string]func() filter.TpsLimiter) + tpsLimitStrategy = make(map[string]func(rate int, interval int) filter.TpsLimitStrategy) + tpsLimiter = make(map[string]func() filter.TpsLimiter) tpsRejectedExecutionHandler = make(map[string]func() filter.RejectedExecutionHandler) ) @@ -51,7 +51,7 @@ func GetTpsLimitStrategyCreator(name string) func(rate int, interval int) filter return creator } -func SetTpsRejectedExecutionHandler(name string, creator func() filter.RejectedExecutionHandler) { +func SetTpsRejectedExecutionHandler(name string, creator func() filter.RejectedExecutionHandler) { tpsRejectedExecutionHandler[name] = creator } @@ -62,4 +62,4 @@ func GetTpsRejectedExecutionHandler(name string) filter.RejectedExecutionHandler "and you have register it by invoking extension.SetTpsRejectedExecutionHandler.") } return creator() -} \ No newline at end of file +} diff --git a/config/service_config.go b/config/service_config.go index 784257b8c7..fb65567a4b 100644 --- a/config/service_config.go +++ b/config/service_config.go @@ -209,9 +209,9 @@ func (srvconfig *ServiceConfig) getUrlMap() url.Values { urlMap.Set(prefix+constant.RETRIES_KEY, v.Retries) urlMap.Set(prefix+constant.WEIGHT_KEY, strconv.FormatInt(v.Weight, 10)) - urlMap.Set(prefix+constant.TPS_LIMIT_STRATEGY_KEY, srvconfig.TpsLimitStrategy) - urlMap.Set(prefix+constant.TPS_LIMIT_INTERVAL_KEY, srvconfig.TpsLimitInterval) - urlMap.Set(prefix+constant.TPS_LIMIT_RATE_KEY, srvconfig.TpsLimitRate) + urlMap.Set(prefix+constant.TPS_LIMIT_STRATEGY_KEY, v.TpsLimitStrategy) + urlMap.Set(prefix+constant.TPS_LIMIT_INTERVAL_KEY, v.TpsLimitInterval) + urlMap.Set(prefix+constant.TPS_LIMIT_RATE_KEY, v.TpsLimitRate) } return urlMap diff --git a/filter/impl/only_log_rejected_execution_handler.go b/filter/impl/rejected_execution_handler_only_log_impl.go similarity index 89% rename from filter/impl/only_log_rejected_execution_handler.go rename to filter/impl/rejected_execution_handler_only_log_impl.go index 8ce4a44593..1ea44efb4c 100644 --- a/filter/impl/only_log_rejected_execution_handler.go +++ b/filter/impl/rejected_execution_handler_only_log_impl.go @@ -19,9 +19,13 @@ package impl import ( "sync" +) +import ( "github.com/prometheus/common/log" +) +import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" @@ -29,7 +33,7 @@ import ( "github.com/apache/dubbo-go/protocol" ) -const HandlerName = "log" +const HandlerName = "log" func init() { extension.SetTpsRejectedExecutionHandler(HandlerName, GetOnlyRejectedExecutionHandler) @@ -41,15 +45,14 @@ var onlyLogHandlerOnce sync.Once /** * This implementation only logs the invocation info. - * it always return nil. + * it always return en error inside the result. */ type OnlyLogRejectedExecutionHandler struct { - } func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result { - log.Warnf("The invocation was rejected. url: %s", url.String()) - return nil + log.Errorf("The invocation was rejected due to over rate limitation. url: %s", url.String()) + return &protocol.RPCResult{} } func GetOnlyRejectedExecutionHandler() filter.RejectedExecutionHandler { @@ -58,4 +61,3 @@ func GetOnlyRejectedExecutionHandler() filter.RejectedExecutionHandler { }) return onlyLogHandlerInstance } - diff --git a/filter/impl/tps_limit_filter.go b/filter/impl/tps_limit_filter.go index ae900a33a3..fc3a5a8a3e 100644 --- a/filter/impl/tps_limit_filter.go +++ b/filter/impl/tps_limit_filter.go @@ -46,10 +46,9 @@ func init() { * if the value of 'tps.limiter' is nil or empty string, the tps filter will do nothing */ type TpsLimitFilter struct { - } -func (t TpsLimitFilter) Invoke(invoker protocol.Invoker,invocation protocol.Invocation) protocol.Result { +func (t TpsLimitFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { url := invoker.GetUrl() tpsLimiter := url.GetParam(constant.TPS_LIMITER_KEY, "") rejectedExeHandler := url.GetParam(constant.TPS_REJECTED_EXECUTION_HANDLER_KEY, constant.DEFAULT_KEY) diff --git a/filter/impl/tps_limit_filter_test.go b/filter/impl/tps_limit_filter_test.go index 236f42c95c..45ce2a5e6d 100644 --- a/filter/impl/tps_limit_filter_test.go +++ b/filter/impl/tps_limit_filter_test.go @@ -20,10 +20,14 @@ package impl import ( "net/url" "testing" +) +import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" +) +import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" @@ -67,7 +71,7 @@ func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) { assert.Nil(t, result.Result()) } -func TestGenericFilter_Invoke_With_Default_TpsLimiter_Not_Allow(t *testing.T) { +func TestGenericFilter_Invoke_With_Default_TpsLimiter_Not_Allow(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockLimiter := filter.NewMockTpsLimiter(ctrl) diff --git a/filter/impl/tps_limit_fix_window_strategy_impl.go b/filter/impl/tps_limit_fix_window_strategy_impl.go new file mode 100644 index 0000000000..04e79b9b4d --- /dev/null +++ b/filter/impl/tps_limit_fix_window_strategy_impl.go @@ -0,0 +1,85 @@ +/* + * 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 impl + +import ( + "sync/atomic" + "time" +) +import ( + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/filter" +) + +const ( + FixedWindowKey = "fixedWindow" +) + +func init() { + extension.SetTpsLimitStrategy(FixedWindowKey, NewFixedWindowTpsLimitStrategyImpl) + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, NewFixedWindowTpsLimitStrategyImpl) +} + +/** + * It's the same as default implementation in Java + * It's not a thread-safe implementation. + * It you want to use the thread-safe implementation, please use ThreadSafeFixedWindowTpsLimitStrategyImpl + * This is the default implementation. + * + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" # the name of limiter + * tps.limit.strategy: "default" or "fixedWindow" # service-level + * methods: + * - name: "GetUser" + * tps.interval: 3000 + * tps.limit.strategy: "default" or "fixedWindow" # method-level + */ +type FixedWindowTpsLimitStrategyImpl struct { + rate int32 + interval int64 + count int32 + timestamp int64 +} + +func (impl *FixedWindowTpsLimitStrategyImpl) IsAllowable() bool { + + current := time.Now().UnixNano() + if impl.timestamp+impl.interval < current { + // it's a new window + // if a lot of threads come here, the count will be set to 0 several times. + // so the return statement will be wrong. + impl.timestamp = current + impl.count = 0 + } + // this operation is thread-safe, but count + 1 may be overflow + return atomic.AddInt32(&impl.count, 1) <= impl.rate +} + +func NewFixedWindowTpsLimitStrategyImpl(rate int, interval int) filter.TpsLimitStrategy { + return &FixedWindowTpsLimitStrategyImpl{ + rate: int32(rate), + interval: int64(interval * 1000), // convert to ns + count: 0, + timestamp: time.Now().UnixNano(), + } +} diff --git a/filter/impl/tps_limit_fix_window_strategy_impl_test.go b/filter/impl/tps_limit_fix_window_strategy_impl_test.go new file mode 100644 index 0000000000..a78d0ec070 --- /dev/null +++ b/filter/impl/tps_limit_fix_window_strategy_impl_test.go @@ -0,0 +1,43 @@ +/* + * 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 impl + +import ( + "testing" + "time" +) + +import ( + "github.com/coreos/etcd/pkg/testutil" +) + +func TestFixedWindowTpsLimitStrategyImpl_IsAllowable(t *testing.T) { + strategy := NewFixedWindowTpsLimitStrategyImpl(2, 60000) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertFalse(t, strategy.IsAllowable()) + + strategy = NewFixedWindowTpsLimitStrategyImpl(2, 2000) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertFalse(t, strategy.IsAllowable()) + time.Sleep(time.Duration(2100 * 1000)) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertFalse(t, strategy.IsAllowable()) +} diff --git a/filter/impl/tps_limit_sliding_window_strategy_impl.go b/filter/impl/tps_limit_sliding_window_strategy_impl.go new file mode 100644 index 0000000000..726ac197a8 --- /dev/null +++ b/filter/impl/tps_limit_sliding_window_strategy_impl.go @@ -0,0 +1,90 @@ +/* + * 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 impl + +import ( + "container/list" + "sync" + "time" +) + +import ( + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/filter" +) + +func init() { + extension.SetTpsLimitStrategy("slidingWindow", NewSlidingWindowTpsLimitStrategyImpl) +} + +/** + * it's thread-safe. + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" # the name of limiter + * tps.limit.strategy: "slidingWindow" # service-level + * methods: + * - name: "GetUser" + * tps.interval: 3000 + * tps.limit.strategy: "slidingWindow" # method-level + */ +type SlidingWindowTpsLimitStrategyImpl struct { + rate int + interval int64 + mutex *sync.Mutex + queue *list.List +} + +func (impl *SlidingWindowTpsLimitStrategyImpl) IsAllowable() bool { + impl.mutex.Lock() + defer impl.mutex.Unlock() + // quick path + size := impl.queue.Len() + current := time.Now().UnixNano() + if size < impl.rate { + impl.queue.PushBack(current) + return true + } + + // slow path + boundary := current - impl.interval + + timestamp := impl.queue.Front() + // remove the element that out of the window + for timestamp != nil && timestamp.Value.(int64) < boundary { + impl.queue.Remove(timestamp) + timestamp = impl.queue.Front() + } + if impl.queue.Len() < impl.rate { + impl.queue.PushBack(current) + return true + } + return false +} + +func NewSlidingWindowTpsLimitStrategyImpl(rate int, interval int) filter.TpsLimitStrategy { + return &SlidingWindowTpsLimitStrategyImpl{ + rate: rate, + interval: int64(interval * 1000), + mutex: &sync.Mutex{}, + queue: list.New(), + } +} diff --git a/filter/impl/tps_limit_sliding_window_strategy_impl_test.go b/filter/impl/tps_limit_sliding_window_strategy_impl_test.go new file mode 100644 index 0000000000..26a9400cdf --- /dev/null +++ b/filter/impl/tps_limit_sliding_window_strategy_impl_test.go @@ -0,0 +1,45 @@ +/* + * 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 impl + +import ( + "testing" + "time" +) + +import ( + "go.etcd.io/etcd/pkg/testutil" +) + +func TestSlidingWindowTpsLimitStrategyImpl_IsAllowable(t *testing.T) { + strategy := NewSlidingWindowTpsLimitStrategyImpl(2, 60000) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertFalse(t, strategy.IsAllowable()) + time.Sleep(time.Duration(2100 * 1000)) + testutil.AssertFalse(t, strategy.IsAllowable()) + + strategy = NewSlidingWindowTpsLimitStrategyImpl(2, 2000) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertFalse(t, strategy.IsAllowable()) + time.Sleep(time.Duration(2100 * 1000)) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertFalse(t, strategy.IsAllowable()) +} diff --git a/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl.go b/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl.go new file mode 100644 index 0000000000..e7d592c0bf --- /dev/null +++ b/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl.go @@ -0,0 +1,65 @@ +/* + * 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 impl + +import ( + "sync" +) + +import ( + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/filter" +) + +func init() { + extension.SetTpsLimitStrategy("threadSafeFixedWindow", NewThreadSafeFixedWindowTpsLimitStrategyImpl) +} + +/** + * it's the thread-safe implementation. + * Also, it's a thread-safe decorator of FixedWindowTpsLimitStrategyImpl + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" # the name of limiter + * tps.limit.strategy: "threadSafeFixedWindow" # service-level + * methods: + * - name: "GetUser" + * tps.interval: 3000 + * tps.limit.strategy: "threadSafeFixedWindow" # method-level + */ +type ThreadSafeFixedWindowTpsLimitStrategyImpl struct { + mutex *sync.Mutex + fixedWindow *FixedWindowTpsLimitStrategyImpl +} + +func (impl *ThreadSafeFixedWindowTpsLimitStrategyImpl) IsAllowable() bool { + impl.mutex.Lock() + defer impl.mutex.Unlock() + return impl.fixedWindow.IsAllowable() +} + +func NewThreadSafeFixedWindowTpsLimitStrategyImpl(rate int, interval int) filter.TpsLimitStrategy { + fixedWindowStrategy := NewFixedWindowTpsLimitStrategyImpl(rate, interval).(*FixedWindowTpsLimitStrategyImpl) + return &ThreadSafeFixedWindowTpsLimitStrategyImpl{ + fixedWindow: fixedWindowStrategy, + mutex: &sync.Mutex{}, + } +} diff --git a/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl_test.go b/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl_test.go new file mode 100644 index 0000000000..e41dd62f2c --- /dev/null +++ b/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl_test.go @@ -0,0 +1,43 @@ +/* + * 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 impl + +import ( + "testing" + "time" +) + +import ( + "github.com/coreos/etcd/pkg/testutil" +) + +func TestThreadSafeFixedWindowTpsLimitStrategyImpl_IsAllowable(t *testing.T) { + strategy := NewThreadSafeFixedWindowTpsLimitStrategyImpl(2, 60000) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertFalse(t, strategy.IsAllowable()) + + strategy = NewThreadSafeFixedWindowTpsLimitStrategyImpl(2, 2000) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertFalse(t, strategy.IsAllowable()) + time.Sleep(time.Duration(2100 * 1000)) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertTrue(t, strategy.IsAllowable()) + testutil.AssertFalse(t, strategy.IsAllowable()) +} diff --git a/filter/impl/tps_limiter_method_service_impl.go b/filter/impl/tps_limiter_method_service_impl.go index 2a30c30b14..23cd64f5c4 100644 --- a/filter/impl/tps_limiter_method_service_impl.go +++ b/filter/impl/tps_limiter_method_service_impl.go @@ -20,9 +20,13 @@ import ( "fmt" "strconv" "sync" +) +import ( "github.com/modern-go/concurrent" +) +import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" @@ -45,15 +49,63 @@ func init() { * protocol : "dubbo" * interface : "com.ikurento.user.UserProvider" * ... # other configuration - * tps.limiter: "method-service" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too. + * tps.limiter: "method-service" or "default" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too. * tps.limit.interval: 5000 # interval, the time unit is ms * tps.limit.rate: 300 # the max value in the interval. <0 means that the service will not be limited. * methods: * - name: "GetUser" * tps.interval: 3000 - * tps.rate: 20, # in this case, this configuration in service-level will be ignored. + * tps.limit.rate: 20, # in this case, this configuration in service-level will be ignored. + * - name: "UpdateUser" + * tps.limit.rate: -1, # If the rate<0, the method will be ignored + * + * + * More examples: + * case1: + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" or "default" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too. + * tps.limit.interval: 5000 # interval, the time unit is ms + * tps.limit.rate: 300 # the max value in the interval. <0 means that the service will not be limited. + * methods: + * - name: "GetUser" + * - name: "UpdateUser" + * tps.limit.rate: -1, + * in this case, the method UpdateUser will be ignored, + * which means that only GetUser will be limited by service-level configuration. + * + * case2: + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" or "default" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too. + * tps.limit.interval: 5000 # interval, the time unit is ms + * tps.limit.rate: 300 # the max value in the interval. <0 means that the service will not be limited. + * methods: + * - name: "GetUser" + * - name: "UpdateUser" + * tps.limit.rate: 30, + * In this case, the GetUser will be limited by service-level configuration(300 times in 5000ms), + * but UpdateUser will be limited by its configuration (30 times in 60000ms) + * + * case3: + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" or "default" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too. + * methods: + * - name: "GetUser" * - name: "UpdateUser" - * tps.rate: -1, # If the rate<0, the method will be ignored + * tps.limit.rate: 70, + * tps.limit.interval: 40000 + * In this case, only UpdateUser will be limited by its configuration (70 times in 40000ms) */ type MethodServiceTpsLimiterImpl struct { tpsState *concurrent.Map @@ -89,7 +141,7 @@ func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocatio limitInterval := getLimitConfig(methodIntervalConfig, url, invocation, constant.TPS_LIMIT_INTERVAL_KEY, constant.DEFAULT_TPS_LIMIT_INTERVAL) - if limitInterval <= 0{ + if limitInterval <= 0 { panic(fmt.Sprintf("The interval must be positive, please check your configuration! url: %s", url.String())) } diff --git a/filter/impl/tps_limiter_method_service_impl_test.go b/filter/impl/tps_limiter_method_service_impl_test.go new file mode 100644 index 0000000000..9194a7488c --- /dev/null +++ b/filter/impl/tps_limiter_method_service_impl_test.go @@ -0,0 +1,125 @@ +/* + * 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 impl + +import ( + "net/url" + "testing" +) +import ( + "github.com/coreos/etcd/pkg/testutil" + "github.com/golang/mock/gomock" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/protocol/invocation" +) + +const methodName = "hello" + +var methodConfigPrefix = "methods." + methodName + "." +var invoc = invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0)) + +func TestMethodServiceTpsLimiterImpl_IsAllowable_Only_Service_Level(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + invokeUrl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20")) + + mockStrategyImpl := filter.NewMockTpsLimitStrategy(ctrl) + mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) filter.TpsLimitStrategy { + testutil.AssertEqual(t, 20, rate) + testutil.AssertEqual(t, 60000, interval) + return mockStrategyImpl + }) + + limiter := GetMethodServiceTpsLimiter() + result := limiter.IsAllowable(*invokeUrl, invoc) + testutil.AssertTrue(t, result) +} + +func TestMethodServiceTpsLimiterImpl_IsAllowable_No_Config(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + invokeUrl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "")) + + limiter := GetMethodServiceTpsLimiter() + result := limiter.IsAllowable(*invokeUrl, invoc) + testutil.AssertTrue(t, result) +} + +func TestMethodServiceTpsLimiterImpl_IsAllowable_Method_Level_Override(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + invokeUrl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20"), + common.WithParamsValue(constant.TPS_LIMIT_INTERVAL_KEY, "3000"), + common.WithParamsValue(constant.TPS_LIMIT_STRATEGY_KEY, "invalid"), + common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_RATE_KEY, "40"), + common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_INTERVAL_KEY, "7000"), + common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_STRATEGY_KEY, "default"), + ) + + mockStrategyImpl := filter.NewMockTpsLimitStrategy(ctrl) + mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) filter.TpsLimitStrategy { + testutil.AssertEqual(t, 40, rate) + testutil.AssertEqual(t, 7000, interval) + return mockStrategyImpl + }) + + limiter := GetMethodServiceTpsLimiter() + result := limiter.IsAllowable(*invokeUrl, invoc) + testutil.AssertTrue(t, result) +} + +func TestMethodServiceTpsLimiterImpl_IsAllowable_Both_Method_And_Service(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + invokeUrl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20"), + common.WithParamsValue(constant.TPS_LIMIT_INTERVAL_KEY, "3000"), + common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_RATE_KEY, "40"), + ) + + mockStrategyImpl := filter.NewMockTpsLimitStrategy(ctrl) + mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) filter.TpsLimitStrategy { + testutil.AssertEqual(t, 40, rate) + testutil.AssertEqual(t, 3000, interval) + return mockStrategyImpl + }) + + limiter := GetMethodServiceTpsLimiter() + result := limiter.IsAllowable(*invokeUrl, invoc) + testutil.AssertTrue(t, result) +} diff --git a/filter/tps_limit_strategy.go b/filter/tps_limit_strategy.go index da51440541..602d20f79c 100644 --- a/filter/tps_limit_strategy.go +++ b/filter/tps_limit_strategy.go @@ -16,10 +16,10 @@ */ package filter + /* * please register your implementation by invoking SetTpsLimitStrategy */ type TpsLimitStrategy interface { IsAllowable() bool } - diff --git a/filter/tps_limit_strategy_mock.go b/filter/tps_limit_strategy_mock.go new file mode 100644 index 0000000000..4adf5848d1 --- /dev/null +++ b/filter/tps_limit_strategy_mock.go @@ -0,0 +1,63 @@ +// 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. +// + +// Code generated by MockGen. DO NOT EDIT. +// Source: tps_limit_strategy.go + +// Package filter is a generated GoMock package. +package filter + +import ( + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockTpsLimitStrategy is a mock of TpsLimitStrategy interface +type MockTpsLimitStrategy struct { + ctrl *gomock.Controller + recorder *MockTpsLimitStrategyMockRecorder +} + +// MockTpsLimitStrategyMockRecorder is the mock recorder for MockTpsLimitStrategy +type MockTpsLimitStrategyMockRecorder struct { + mock *MockTpsLimitStrategy +} + +// NewMockTpsLimitStrategy creates a new mock instance +func NewMockTpsLimitStrategy(ctrl *gomock.Controller) *MockTpsLimitStrategy { + mock := &MockTpsLimitStrategy{ctrl: ctrl} + mock.recorder = &MockTpsLimitStrategyMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockTpsLimitStrategy) EXPECT() *MockTpsLimitStrategyMockRecorder { + return m.recorder +} + +// IsAllowable mocks base method +func (m *MockTpsLimitStrategy) IsAllowable() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsAllowable") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsAllowable indicates an expected call of IsAllowable +func (mr *MockTpsLimitStrategyMockRecorder) IsAllowable() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAllowable", reflect.TypeOf((*MockTpsLimitStrategy)(nil).IsAllowable)) +} diff --git a/filter/tps_limiter.go b/filter/tps_limiter.go index ca945cc700..1d2b2341ac 100644 --- a/filter/tps_limiter.go +++ b/filter/tps_limiter.go @@ -21,6 +21,7 @@ import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/protocol" ) + /* * please register your implementation by invoking SetTpsLimiter * The usage, for example: @@ -34,6 +35,3 @@ import ( type TpsLimiter interface { IsAllowable(common.URL, protocol.Invocation) bool } - - - diff --git a/go.mod b/go.mod index 8171e8e429..0354a5056a 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect github.com/magiconair/properties v1.8.1 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v1.1.0 // indirect From e8a168c246c40316e2233cf705de8b74967e62d2 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Tue, 15 Oct 2019 23:30:02 +0800 Subject: [PATCH 05/12] Fix UT --- .../tps_limiter_method_service_impl_test.go | 46 +++++++++++-------- go.mod | 1 + 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/filter/impl/tps_limiter_method_service_impl_test.go b/filter/impl/tps_limiter_method_service_impl_test.go index 9194a7488c..c0beee9cf3 100644 --- a/filter/impl/tps_limiter_method_service_impl_test.go +++ b/filter/impl/tps_limiter_method_service_impl_test.go @@ -22,8 +22,8 @@ import ( "testing" ) import ( - "github.com/coreos/etcd/pkg/testutil" "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" ) import ( @@ -34,51 +34,57 @@ import ( "github.com/apache/dubbo-go/protocol/invocation" ) -const methodName = "hello" - -var methodConfigPrefix = "methods." + methodName + "." -var invoc = invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0)) - func TestMethodServiceTpsLimiterImpl_IsAllowable_Only_Service_Level(t *testing.T) { + methodName := "hello" + invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0)) + ctrl := gomock.NewController(t) defer ctrl.Finish() invokeUrl := common.NewURLWithOptions( common.WithParams(url.Values{}), + common.WithParamsValue(constant.INTERFACE_KEY, methodName), common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20")) mockStrategyImpl := filter.NewMockTpsLimitStrategy(ctrl) mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) filter.TpsLimitStrategy { - testutil.AssertEqual(t, 20, rate) - testutil.AssertEqual(t, 60000, interval) + assert.Equal(t, 20, rate) + assert.Equal(t, 60000, interval) return mockStrategyImpl }) limiter := GetMethodServiceTpsLimiter() result := limiter.IsAllowable(*invokeUrl, invoc) - testutil.AssertTrue(t, result) + assert.True(t, result) } func TestMethodServiceTpsLimiterImpl_IsAllowable_No_Config(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() + methodName := "hello1" + invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0)) + // ctrl := gomock.NewController(t) + // defer ctrl.Finish() invokeUrl := common.NewURLWithOptions( common.WithParams(url.Values{}), + common.WithParamsValue(constant.INTERFACE_KEY, methodName), common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "")) limiter := GetMethodServiceTpsLimiter() result := limiter.IsAllowable(*invokeUrl, invoc) - testutil.AssertTrue(t, result) + assert.True(t, result) } func TestMethodServiceTpsLimiterImpl_IsAllowable_Method_Level_Override(t *testing.T) { + methodName := "hello2" + methodConfigPrefix := "methods." + methodName + "." + invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0)) ctrl := gomock.NewController(t) defer ctrl.Finish() invokeUrl := common.NewURLWithOptions( common.WithParams(url.Values{}), + common.WithParamsValue(constant.INTERFACE_KEY, methodName), common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20"), common.WithParamsValue(constant.TPS_LIMIT_INTERVAL_KEY, "3000"), common.WithParamsValue(constant.TPS_LIMIT_STRATEGY_KEY, "invalid"), @@ -90,22 +96,26 @@ func TestMethodServiceTpsLimiterImpl_IsAllowable_Method_Level_Override(t *testin mockStrategyImpl := filter.NewMockTpsLimitStrategy(ctrl) mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) filter.TpsLimitStrategy { - testutil.AssertEqual(t, 40, rate) - testutil.AssertEqual(t, 7000, interval) + assert.Equal(t, 40, rate) + assert.Equal(t, 7000, interval) return mockStrategyImpl }) limiter := GetMethodServiceTpsLimiter() result := limiter.IsAllowable(*invokeUrl, invoc) - testutil.AssertTrue(t, result) + assert.True(t, result) } func TestMethodServiceTpsLimiterImpl_IsAllowable_Both_Method_And_Service(t *testing.T) { + methodName := "hello3" + methodConfigPrefix := "methods." + methodName + "." + invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0)) ctrl := gomock.NewController(t) defer ctrl.Finish() invokeUrl := common.NewURLWithOptions( common.WithParams(url.Values{}), + common.WithParamsValue(constant.INTERFACE_KEY, methodName), common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20"), common.WithParamsValue(constant.TPS_LIMIT_INTERVAL_KEY, "3000"), common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_RATE_KEY, "40"), @@ -114,12 +124,12 @@ func TestMethodServiceTpsLimiterImpl_IsAllowable_Both_Method_And_Service(t *test mockStrategyImpl := filter.NewMockTpsLimitStrategy(ctrl) mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) filter.TpsLimitStrategy { - testutil.AssertEqual(t, 40, rate) - testutil.AssertEqual(t, 3000, interval) + assert.Equal(t, 40, rate) + assert.Equal(t, 3000, interval) return mockStrategyImpl }) limiter := GetMethodServiceTpsLimiter() result := limiter.IsAllowable(*invokeUrl, invoc) - testutil.AssertTrue(t, result) + assert.True(t, result) } diff --git a/go.mod b/go.mod index 0354a5056a..2f7a2820ba 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e // indirect github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190923055845-e3dd5d131df5 + github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 // indirect github.com/coreos/bbolt v1.3.3 // indirect github.com/coreos/etcd v3.3.13+incompatible From 37e668da1df1bef15b658e29eb9c4c4b5b4b5337 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Wed, 16 Oct 2019 13:02:34 +0800 Subject: [PATCH 06/12] Add UT --- ...ejected_execution_handler_only_log_impl.go | 6 ++-- ...ed_execution_handler_only_log_impl_test.go | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 filter/impl/rejected_execution_handler_only_log_impl_test.go diff --git a/filter/impl/rejected_execution_handler_only_log_impl.go b/filter/impl/rejected_execution_handler_only_log_impl.go index 1ea44efb4c..bc67fa4ec4 100644 --- a/filter/impl/rejected_execution_handler_only_log_impl.go +++ b/filter/impl/rejected_execution_handler_only_log_impl.go @@ -36,8 +36,8 @@ import ( const HandlerName = "log" func init() { - extension.SetTpsRejectedExecutionHandler(HandlerName, GetOnlyRejectedExecutionHandler) - extension.SetTpsRejectedExecutionHandler(constant.DEFAULT_KEY, GetOnlyRejectedExecutionHandler) + extension.SetTpsRejectedExecutionHandler(HandlerName, GetOnlyLogRejectedExecutionHandler) + extension.SetTpsRejectedExecutionHandler(constant.DEFAULT_KEY, GetOnlyLogRejectedExecutionHandler) } var onlyLogHandlerInstance *OnlyLogRejectedExecutionHandler @@ -55,7 +55,7 @@ func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL return &protocol.RPCResult{} } -func GetOnlyRejectedExecutionHandler() filter.RejectedExecutionHandler { +func GetOnlyLogRejectedExecutionHandler() filter.RejectedExecutionHandler { onlyLogHandlerOnce.Do(func() { onlyLogHandlerInstance = &OnlyLogRejectedExecutionHandler{} }) diff --git a/filter/impl/rejected_execution_handler_only_log_impl_test.go b/filter/impl/rejected_execution_handler_only_log_impl_test.go new file mode 100644 index 0000000000..da54d8a106 --- /dev/null +++ b/filter/impl/rejected_execution_handler_only_log_impl_test.go @@ -0,0 +1,35 @@ +/* + * 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 impl + +import ( + "net/url" + "testing" +) +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" +) + +func TestOnlyLogRejectedExecutionHandler_RejectedExecution(t *testing.T) { + handler := GetOnlyLogRejectedExecutionHandler() + invokeUrl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.INTERFACE_KEY, "methodName")) + handler.RejectedExecution(*invokeUrl, nil) +} From 687966ab20f066fd7ed23196f8193a5c99adb23a Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Wed, 16 Oct 2019 17:59:37 +0800 Subject: [PATCH 07/12] Fix review --- common/extension/tps_limit.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/common/extension/tps_limit.go b/common/extension/tps_limit.go index 70c71cbc4b..626361e493 100644 --- a/common/extension/tps_limit.go +++ b/common/extension/tps_limit.go @@ -17,7 +17,9 @@ package extension -import "github.com/apache/dubbo-go/filter" +import ( + "github.com/apache/dubbo-go/filter" +) var ( tpsLimitStrategy = make(map[string]func(rate int, interval int) filter.TpsLimitStrategy) @@ -30,8 +32,8 @@ func SetTpsLimiter(name string, creator func() filter.TpsLimiter) { } func GetTpsLimiter(name string) filter.TpsLimiter { - var creator = tpsLimiter[name] - if creator == nil { + creator, ok := tpsLimiter[name] + if !ok { panic("TpsLimiter for " + name + " is not existing, make sure you have import the package " + "and you have register it by invoking extension.SetTpsLimiter.") } @@ -43,8 +45,8 @@ func SetTpsLimitStrategy(name string, creator func(rate int, interval int) filte } func GetTpsLimitStrategyCreator(name string) func(rate int, interval int) filter.TpsLimitStrategy { - var creator = tpsLimitStrategy[name] - if creator == nil { + creator, ok := tpsLimitStrategy[name] + if !ok { panic("TpsLimitStrategy for " + name + " is not existing, make sure you have import the package " + "and you have register it by invoking extension.SetTpsLimitStrategy.") } @@ -56,8 +58,8 @@ func SetTpsRejectedExecutionHandler(name string, creator func() filter.RejectedE } func GetTpsRejectedExecutionHandler(name string) filter.RejectedExecutionHandler { - var creator = tpsRejectedExecutionHandler[name] - if creator() == nil { + creator, ok := tpsRejectedExecutionHandler[name] + if !ok { panic("TpsRejectedExecutionHandler for " + name + " is not existing, make sure you have import the package " + "and you have register it by invoking extension.SetTpsRejectedExecutionHandler.") } From d3111f7911b72593ba4cd6271cc82207f70c7069 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Thu, 17 Oct 2019 12:28:21 +0800 Subject: [PATCH 08/12] Fix UT --- ...tps_limit_fix_window_strategy_impl_test.go | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/filter/impl/tps_limit_fix_window_strategy_impl_test.go b/filter/impl/tps_limit_fix_window_strategy_impl_test.go index a78d0ec070..55d0b14b75 100644 --- a/filter/impl/tps_limit_fix_window_strategy_impl_test.go +++ b/filter/impl/tps_limit_fix_window_strategy_impl_test.go @@ -23,21 +23,21 @@ import ( ) import ( - "github.com/coreos/etcd/pkg/testutil" + "github.com/stretchr/testify/assert" ) func TestFixedWindowTpsLimitStrategyImpl_IsAllowable(t *testing.T) { strategy := NewFixedWindowTpsLimitStrategyImpl(2, 60000) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) strategy = NewFixedWindowTpsLimitStrategyImpl(2, 2000) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) time.Sleep(time.Duration(2100 * 1000)) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) } From 542ead74ca34c1337f5808c77b7eb7e54e9e1fa9 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Thu, 17 Oct 2019 13:43:25 +0800 Subject: [PATCH 09/12] Fix review: move the tps_limit to filter/impl/tps/ --- common/extension/tps_limit.go | 20 ++++++++-------- config/testdata/provider_config.yml | 9 +++++++ .../tps/intf}/rejected_execution_handler.go | 15 +++++++++++- .../{ => impl/tps/intf}/tps_limit_strategy.go | 13 +++++++++- filter/{ => impl/tps/intf}/tps_limiter.go | 2 +- .../tps}/rejected_execution_handler_mock.go | 2 +- ...ejected_execution_handler_only_log_impl.go | 22 ++++++++++------- ...ed_execution_handler_only_log_impl_test.go | 2 +- .../tps_limit_fix_window_strategy_impl.go | 6 ++--- ...tps_limit_fix_window_strategy_impl_test.go | 2 +- .../tps_limit_sliding_window_strategy_impl.go | 6 ++--- ...limit_sliding_window_strategy_impl_test.go | 24 +++++++++---------- .../{ => impl/tps}/tps_limit_strategy_mock.go | 2 +- ...it_thread_safe_fix_window_strategy_impl.go | 6 ++--- ...read_safe_fix_window_strategy_impl_test.go | 22 ++++++++--------- .../tps_limiter_method_service_impl.go | 10 ++++---- .../tps_limiter_method_service_impl_test.go | 16 ++++++------- filter/{ => impl/tps}/tps_limiter_mock.go | 2 +- filter/impl/tps_limit_filter_test.go | 15 ++++++------ 19 files changed, 118 insertions(+), 78 deletions(-) rename filter/{ => impl/tps/intf}/rejected_execution_handler.go (70%) rename filter/{ => impl/tps/intf}/tps_limit_strategy.go (69%) rename filter/{ => impl/tps/intf}/tps_limiter.go (98%) rename filter/{ => impl/tps}/rejected_execution_handler_mock.go (99%) rename filter/impl/{ => tps}/rejected_execution_handler_only_log_impl.go (75%) rename filter/impl/{ => tps}/rejected_execution_handler_only_log_impl_test.go (98%) rename filter/impl/{ => tps}/tps_limit_fix_window_strategy_impl.go (96%) rename filter/impl/{ => tps}/tps_limit_fix_window_strategy_impl_test.go (99%) rename filter/impl/{ => tps}/tps_limit_sliding_window_strategy_impl.go (96%) rename filter/impl/{ => tps}/tps_limit_sliding_window_strategy_impl_test.go (67%) rename filter/{ => impl/tps}/tps_limit_strategy_mock.go (99%) rename filter/impl/{ => tps}/tps_limit_thread_safe_fix_window_strategy_impl.go (95%) rename filter/impl/{ => tps}/tps_limit_thread_safe_fix_window_strategy_impl_test.go (69%) rename filter/impl/{ => tps}/tps_limiter_method_service_impl.go (96%) rename filter/impl/{ => tps}/tps_limiter_method_service_impl_test.go (93%) rename filter/{ => impl/tps}/tps_limiter_mock.go (99%) diff --git a/common/extension/tps_limit.go b/common/extension/tps_limit.go index 626361e493..e789d5b106 100644 --- a/common/extension/tps_limit.go +++ b/common/extension/tps_limit.go @@ -18,20 +18,20 @@ package extension import ( - "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/filter/impl/tps/intf" ) var ( - tpsLimitStrategy = make(map[string]func(rate int, interval int) filter.TpsLimitStrategy) - tpsLimiter = make(map[string]func() filter.TpsLimiter) - tpsRejectedExecutionHandler = make(map[string]func() filter.RejectedExecutionHandler) + tpsLimitStrategy = make(map[string]func(rate int, interval int) intf.TpsLimitStrategy) + tpsLimiter = make(map[string]func() intf.TpsLimiter) + tpsRejectedExecutionHandler = make(map[string]func() intf.RejectedExecutionHandler) ) -func SetTpsLimiter(name string, creator func() filter.TpsLimiter) { +func SetTpsLimiter(name string, creator func() intf.TpsLimiter) { tpsLimiter[name] = creator } -func GetTpsLimiter(name string) filter.TpsLimiter { +func GetTpsLimiter(name string) intf.TpsLimiter { creator, ok := tpsLimiter[name] if !ok { panic("TpsLimiter for " + name + " is not existing, make sure you have import the package " + @@ -40,11 +40,11 @@ func GetTpsLimiter(name string) filter.TpsLimiter { return creator() } -func SetTpsLimitStrategy(name string, creator func(rate int, interval int) filter.TpsLimitStrategy) { +func SetTpsLimitStrategy(name string, creator func(rate int, interval int) intf.TpsLimitStrategy) { tpsLimitStrategy[name] = creator } -func GetTpsLimitStrategyCreator(name string) func(rate int, interval int) filter.TpsLimitStrategy { +func GetTpsLimitStrategyCreator(name string) func(rate int, interval int) intf.TpsLimitStrategy { creator, ok := tpsLimitStrategy[name] if !ok { panic("TpsLimitStrategy for " + name + " is not existing, make sure you have import the package " + @@ -53,11 +53,11 @@ func GetTpsLimitStrategyCreator(name string) func(rate int, interval int) filter return creator } -func SetTpsRejectedExecutionHandler(name string, creator func() filter.RejectedExecutionHandler) { +func SetTpsRejectedExecutionHandler(name string, creator func() intf.RejectedExecutionHandler) { tpsRejectedExecutionHandler[name] = creator } -func GetTpsRejectedExecutionHandler(name string) filter.RejectedExecutionHandler { +func GetTpsRejectedExecutionHandler(name string) intf.RejectedExecutionHandler { creator, ok := tpsRejectedExecutionHandler[name] if !ok { panic("TpsRejectedExecutionHandler for " + name + " is not existing, make sure you have import the package " + diff --git a/config/testdata/provider_config.yml b/config/testdata/provider_config.yml index 5cbefe0811..71e45b9c0e 100644 --- a/config/testdata/provider_config.yml +++ b/config/testdata/provider_config.yml @@ -29,6 +29,15 @@ services: "UserProvider": registry: "hangzhouzk,shanghaizk" filter: "" + # the name of limiter + tps.limiter: "default" + # the time unit of interval is ms + tps.limit.interval: 60000 + tps.limit.rate: 200 + # the name of strategy + tps.limit.strategy: "slidingWindow" + # the name of RejectedExecutionHandler + tps.limit.rejected.handler: "default" protocol : "dubbo" # equivalent to interface of dubbo.xml interface : "com.ikurento.user.UserProvider" diff --git a/filter/rejected_execution_handler.go b/filter/impl/tps/intf/rejected_execution_handler.go similarity index 70% rename from filter/rejected_execution_handler.go rename to filter/impl/tps/intf/rejected_execution_handler.go index 1773edcbd6..1e0c0938f8 100644 --- a/filter/rejected_execution_handler.go +++ b/filter/impl/tps/intf/rejected_execution_handler.go @@ -14,13 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package filter +package intf import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/protocol" ) +/** + * This implementation only logs the invocation info. + * it always return en error inside the result. + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" # the name of limiter + * tps.limit.rejected.handler: "name of handler" + * methods: + * - name: "GetUser" + */ type RejectedExecutionHandler interface { RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result } diff --git a/filter/tps_limit_strategy.go b/filter/impl/tps/intf/tps_limit_strategy.go similarity index 69% rename from filter/tps_limit_strategy.go rename to filter/impl/tps/intf/tps_limit_strategy.go index 602d20f79c..ed52daebf6 100644 --- a/filter/tps_limit_strategy.go +++ b/filter/impl/tps/intf/tps_limit_strategy.go @@ -15,10 +15,21 @@ * limitations under the License. */ -package filter +package intf /* * please register your implementation by invoking SetTpsLimitStrategy + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" # the name of limiter + * tps.limit.strategy: "name of implementation" # service-level + * methods: + * - name: "GetUser" + * tps.interval: 3000 + * tps.limit.strategy: "name of implementation" # method-level */ type TpsLimitStrategy interface { IsAllowable() bool diff --git a/filter/tps_limiter.go b/filter/impl/tps/intf/tps_limiter.go similarity index 98% rename from filter/tps_limiter.go rename to filter/impl/tps/intf/tps_limiter.go index 1d2b2341ac..d3935c11de 100644 --- a/filter/tps_limiter.go +++ b/filter/impl/tps/intf/tps_limiter.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package filter +package intf import ( "github.com/apache/dubbo-go/common" diff --git a/filter/rejected_execution_handler_mock.go b/filter/impl/tps/rejected_execution_handler_mock.go similarity index 99% rename from filter/rejected_execution_handler_mock.go rename to filter/impl/tps/rejected_execution_handler_mock.go index 20c3e575bb..55b01f022f 100644 --- a/filter/rejected_execution_handler_mock.go +++ b/filter/impl/tps/rejected_execution_handler_mock.go @@ -18,7 +18,7 @@ // Source: rejected_execution_handler.go // Package filter is a generated GoMock package. -package filter +package tps import ( common "github.com/apache/dubbo-go/common" diff --git a/filter/impl/rejected_execution_handler_only_log_impl.go b/filter/impl/tps/rejected_execution_handler_only_log_impl.go similarity index 75% rename from filter/impl/rejected_execution_handler_only_log_impl.go rename to filter/impl/tps/rejected_execution_handler_only_log_impl.go index bc67fa4ec4..596160f07c 100644 --- a/filter/impl/rejected_execution_handler_only_log_impl.go +++ b/filter/impl/tps/rejected_execution_handler_only_log_impl.go @@ -15,21 +15,18 @@ * limitations under the License. */ -package impl +package tps import ( "sync" ) -import ( - "github.com/prometheus/common/log" -) - import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/filter/impl/tps/intf" "github.com/apache/dubbo-go/protocol" ) @@ -46,16 +43,25 @@ var onlyLogHandlerOnce sync.Once /** * This implementation only logs the invocation info. * it always return en error inside the result. + * "UserProvider": + * registry: "hangzhouzk" + * protocol : "dubbo" + * interface : "com.ikurento.user.UserProvider" + * ... # other configuration + * tps.limiter: "method-service" # the name of limiter + * tps.limit.rejected.handler: "default" or "log" + * methods: + * - name: "GetUser" */ type OnlyLogRejectedExecutionHandler struct { } func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result { - log.Errorf("The invocation was rejected due to over rate limitation. url: %s", url.String()) + logger.Errorf("The invocation was rejected due to over rate limitation. url: %s", url.String()) return &protocol.RPCResult{} } -func GetOnlyLogRejectedExecutionHandler() filter.RejectedExecutionHandler { +func GetOnlyLogRejectedExecutionHandler() intf.RejectedExecutionHandler { onlyLogHandlerOnce.Do(func() { onlyLogHandlerInstance = &OnlyLogRejectedExecutionHandler{} }) diff --git a/filter/impl/rejected_execution_handler_only_log_impl_test.go b/filter/impl/tps/rejected_execution_handler_only_log_impl_test.go similarity index 98% rename from filter/impl/rejected_execution_handler_only_log_impl_test.go rename to filter/impl/tps/rejected_execution_handler_only_log_impl_test.go index da54d8a106..beff7e3f2c 100644 --- a/filter/impl/rejected_execution_handler_only_log_impl_test.go +++ b/filter/impl/tps/rejected_execution_handler_only_log_impl_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package impl +package tps import ( "net/url" diff --git a/filter/impl/tps_limit_fix_window_strategy_impl.go b/filter/impl/tps/tps_limit_fix_window_strategy_impl.go similarity index 96% rename from filter/impl/tps_limit_fix_window_strategy_impl.go rename to filter/impl/tps/tps_limit_fix_window_strategy_impl.go index 04e79b9b4d..7e4032c684 100644 --- a/filter/impl/tps_limit_fix_window_strategy_impl.go +++ b/filter/impl/tps/tps_limit_fix_window_strategy_impl.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package impl +package tps import ( "sync/atomic" @@ -24,7 +24,7 @@ import ( import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/filter/impl/tps/intf" ) const ( @@ -75,7 +75,7 @@ func (impl *FixedWindowTpsLimitStrategyImpl) IsAllowable() bool { return atomic.AddInt32(&impl.count, 1) <= impl.rate } -func NewFixedWindowTpsLimitStrategyImpl(rate int, interval int) filter.TpsLimitStrategy { +func NewFixedWindowTpsLimitStrategyImpl(rate int, interval int) intf.TpsLimitStrategy { return &FixedWindowTpsLimitStrategyImpl{ rate: int32(rate), interval: int64(interval * 1000), // convert to ns diff --git a/filter/impl/tps_limit_fix_window_strategy_impl_test.go b/filter/impl/tps/tps_limit_fix_window_strategy_impl_test.go similarity index 99% rename from filter/impl/tps_limit_fix_window_strategy_impl_test.go rename to filter/impl/tps/tps_limit_fix_window_strategy_impl_test.go index 55d0b14b75..8848a05dde 100644 --- a/filter/impl/tps_limit_fix_window_strategy_impl_test.go +++ b/filter/impl/tps/tps_limit_fix_window_strategy_impl_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package impl +package tps import ( "testing" diff --git a/filter/impl/tps_limit_sliding_window_strategy_impl.go b/filter/impl/tps/tps_limit_sliding_window_strategy_impl.go similarity index 96% rename from filter/impl/tps_limit_sliding_window_strategy_impl.go rename to filter/impl/tps/tps_limit_sliding_window_strategy_impl.go index 726ac197a8..3a8db5ab37 100644 --- a/filter/impl/tps_limit_sliding_window_strategy_impl.go +++ b/filter/impl/tps/tps_limit_sliding_window_strategy_impl.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package impl +package tps import ( "container/list" @@ -25,7 +25,7 @@ import ( import ( "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/filter/impl/tps/intf" ) func init() { @@ -80,7 +80,7 @@ func (impl *SlidingWindowTpsLimitStrategyImpl) IsAllowable() bool { return false } -func NewSlidingWindowTpsLimitStrategyImpl(rate int, interval int) filter.TpsLimitStrategy { +func NewSlidingWindowTpsLimitStrategyImpl(rate int, interval int) intf.TpsLimitStrategy { return &SlidingWindowTpsLimitStrategyImpl{ rate: rate, interval: int64(interval * 1000), diff --git a/filter/impl/tps_limit_sliding_window_strategy_impl_test.go b/filter/impl/tps/tps_limit_sliding_window_strategy_impl_test.go similarity index 67% rename from filter/impl/tps_limit_sliding_window_strategy_impl_test.go rename to filter/impl/tps/tps_limit_sliding_window_strategy_impl_test.go index 26a9400cdf..1bca13d401 100644 --- a/filter/impl/tps_limit_sliding_window_strategy_impl_test.go +++ b/filter/impl/tps/tps_limit_sliding_window_strategy_impl_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package impl +package tps import ( "testing" @@ -23,23 +23,23 @@ import ( ) import ( - "go.etcd.io/etcd/pkg/testutil" + "github.com/stretchr/testify/assert" ) func TestSlidingWindowTpsLimitStrategyImpl_IsAllowable(t *testing.T) { strategy := NewSlidingWindowTpsLimitStrategyImpl(2, 60000) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) time.Sleep(time.Duration(2100 * 1000)) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) strategy = NewSlidingWindowTpsLimitStrategyImpl(2, 2000) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) time.Sleep(time.Duration(2100 * 1000)) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) } diff --git a/filter/tps_limit_strategy_mock.go b/filter/impl/tps/tps_limit_strategy_mock.go similarity index 99% rename from filter/tps_limit_strategy_mock.go rename to filter/impl/tps/tps_limit_strategy_mock.go index 4adf5848d1..72c658fb9a 100644 --- a/filter/tps_limit_strategy_mock.go +++ b/filter/impl/tps/tps_limit_strategy_mock.go @@ -18,7 +18,7 @@ // Source: tps_limit_strategy.go // Package filter is a generated GoMock package. -package filter +package tps import ( gomock "github.com/golang/mock/gomock" diff --git a/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl.go b/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl.go similarity index 95% rename from filter/impl/tps_limit_thread_safe_fix_window_strategy_impl.go rename to filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl.go index e7d592c0bf..3541252dbe 100644 --- a/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl.go +++ b/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package impl +package tps import ( "sync" @@ -23,7 +23,7 @@ import ( import ( "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/filter/impl/tps/intf" ) func init() { @@ -56,7 +56,7 @@ func (impl *ThreadSafeFixedWindowTpsLimitStrategyImpl) IsAllowable() bool { return impl.fixedWindow.IsAllowable() } -func NewThreadSafeFixedWindowTpsLimitStrategyImpl(rate int, interval int) filter.TpsLimitStrategy { +func NewThreadSafeFixedWindowTpsLimitStrategyImpl(rate int, interval int) intf.TpsLimitStrategy { fixedWindowStrategy := NewFixedWindowTpsLimitStrategyImpl(rate, interval).(*FixedWindowTpsLimitStrategyImpl) return &ThreadSafeFixedWindowTpsLimitStrategyImpl{ fixedWindow: fixedWindowStrategy, diff --git a/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl_test.go b/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl_test.go similarity index 69% rename from filter/impl/tps_limit_thread_safe_fix_window_strategy_impl_test.go rename to filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl_test.go index e41dd62f2c..72cd4800de 100644 --- a/filter/impl/tps_limit_thread_safe_fix_window_strategy_impl_test.go +++ b/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package impl +package tps import ( "testing" @@ -23,21 +23,21 @@ import ( ) import ( - "github.com/coreos/etcd/pkg/testutil" + "github.com/stretchr/testify/assert" ) func TestThreadSafeFixedWindowTpsLimitStrategyImpl_IsAllowable(t *testing.T) { strategy := NewThreadSafeFixedWindowTpsLimitStrategyImpl(2, 60000) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) strategy = NewThreadSafeFixedWindowTpsLimitStrategyImpl(2, 2000) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) time.Sleep(time.Duration(2100 * 1000)) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertTrue(t, strategy.IsAllowable()) - testutil.AssertFalse(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.True(t, strategy.IsAllowable()) + assert.False(t, strategy.IsAllowable()) } diff --git a/filter/impl/tps_limiter_method_service_impl.go b/filter/impl/tps/tps_limiter_method_service_impl.go similarity index 96% rename from filter/impl/tps_limiter_method_service_impl.go rename to filter/impl/tps/tps_limiter_method_service_impl.go index 23cd64f5c4..01d9f6564a 100644 --- a/filter/impl/tps_limiter_method_service_impl.go +++ b/filter/impl/tps/tps_limiter_method_service_impl.go @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package impl +package tps import ( "fmt" @@ -30,7 +30,7 @@ import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/filter/impl/tps/intf" "github.com/apache/dubbo-go/protocol" ) @@ -127,7 +127,7 @@ func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocatio limitState, found := limiter.tpsState.Load(limitTarget) if found { - return limitState.(filter.TpsLimitStrategy).IsAllowable() + return limitState.(intf.TpsLimitStrategy).IsAllowable() } limitRate := getLimitConfig(methodLimitRateConfig, url, invocation, @@ -149,7 +149,7 @@ func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocatio url.GetParam(constant.TPS_LIMIT_STRATEGY_KEY, constant.DEFAULT_KEY)) limitStateCreator := extension.GetTpsLimitStrategyCreator(limitStrategyConfig) limitState, _ = limiter.tpsState.LoadOrStore(limitTarget, limitStateCreator(int(limitRate), int(limitInterval))) - return limitState.(filter.TpsLimitStrategy).IsAllowable() + return limitState.(intf.TpsLimitStrategy).IsAllowable() } func getLimitConfig(methodLevelConfig string, @@ -178,7 +178,7 @@ func getLimitConfig(methodLevelConfig string, var methodServiceTpsLimiterInstance *MethodServiceTpsLimiterImpl var methodServiceTpsLimiterOnce sync.Once -func GetMethodServiceTpsLimiter() filter.TpsLimiter { +func GetMethodServiceTpsLimiter() intf.TpsLimiter { methodServiceTpsLimiterOnce.Do(func() { methodServiceTpsLimiterInstance = &MethodServiceTpsLimiterImpl{ tpsState: concurrent.NewMap(), diff --git a/filter/impl/tps_limiter_method_service_impl_test.go b/filter/impl/tps/tps_limiter_method_service_impl_test.go similarity index 93% rename from filter/impl/tps_limiter_method_service_impl_test.go rename to filter/impl/tps/tps_limiter_method_service_impl_test.go index c0beee9cf3..8a6fa8398d 100644 --- a/filter/impl/tps_limiter_method_service_impl_test.go +++ b/filter/impl/tps/tps_limiter_method_service_impl_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package impl +package tps import ( "net/url" @@ -30,7 +30,7 @@ import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/filter/impl/tps/intf" "github.com/apache/dubbo-go/protocol/invocation" ) @@ -46,9 +46,9 @@ func TestMethodServiceTpsLimiterImpl_IsAllowable_Only_Service_Level(t *testing.T common.WithParamsValue(constant.INTERFACE_KEY, methodName), common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20")) - mockStrategyImpl := filter.NewMockTpsLimitStrategy(ctrl) + mockStrategyImpl := NewMockTpsLimitStrategy(ctrl) mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) - extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) filter.TpsLimitStrategy { + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) intf.TpsLimitStrategy { assert.Equal(t, 20, rate) assert.Equal(t, 60000, interval) return mockStrategyImpl @@ -93,9 +93,9 @@ func TestMethodServiceTpsLimiterImpl_IsAllowable_Method_Level_Override(t *testin common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_STRATEGY_KEY, "default"), ) - mockStrategyImpl := filter.NewMockTpsLimitStrategy(ctrl) + mockStrategyImpl := NewMockTpsLimitStrategy(ctrl) mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) - extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) filter.TpsLimitStrategy { + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) intf.TpsLimitStrategy { assert.Equal(t, 40, rate) assert.Equal(t, 7000, interval) return mockStrategyImpl @@ -121,9 +121,9 @@ func TestMethodServiceTpsLimiterImpl_IsAllowable_Both_Method_And_Service(t *test common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_RATE_KEY, "40"), ) - mockStrategyImpl := filter.NewMockTpsLimitStrategy(ctrl) + mockStrategyImpl := NewMockTpsLimitStrategy(ctrl) mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) - extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) filter.TpsLimitStrategy { + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) intf.TpsLimitStrategy { assert.Equal(t, 40, rate) assert.Equal(t, 3000, interval) return mockStrategyImpl diff --git a/filter/tps_limiter_mock.go b/filter/impl/tps/tps_limiter_mock.go similarity index 99% rename from filter/tps_limiter_mock.go rename to filter/impl/tps/tps_limiter_mock.go index 5fbf717614..a247bf14da 100644 --- a/filter/tps_limiter_mock.go +++ b/filter/impl/tps/tps_limiter_mock.go @@ -18,7 +18,7 @@ // Source: tps_limiter.go // Package filter is a generated GoMock package. -package filter +package tps import ( common "github.com/apache/dubbo-go/common" diff --git a/filter/impl/tps_limit_filter_test.go b/filter/impl/tps_limit_filter_test.go index 45ce2a5e6d..18a72ba9e9 100644 --- a/filter/impl/tps_limit_filter_test.go +++ b/filter/impl/tps_limit_filter_test.go @@ -31,7 +31,8 @@ import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/filter/impl/tps" + "github.com/apache/dubbo-go/filter/impl/tps/intf" "github.com/apache/dubbo-go/protocol" "github.com/apache/dubbo-go/protocol/invocation" ) @@ -53,9 +54,9 @@ func TestTpsLimitFilter_Invoke_With_No_TpsLimiter(t *testing.T) { func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - mockLimiter := filter.NewMockTpsLimiter(ctrl) + mockLimiter := tps.NewMockTpsLimiter(ctrl) mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(true).Times(1) - extension.SetTpsLimiter(constant.DEFAULT_KEY, func() filter.TpsLimiter { + extension.SetTpsLimiter(constant.DEFAULT_KEY, func() intf.TpsLimiter { return mockLimiter }) @@ -74,17 +75,17 @@ func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) { func TestGenericFilter_Invoke_With_Default_TpsLimiter_Not_Allow(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - mockLimiter := filter.NewMockTpsLimiter(ctrl) + mockLimiter := tps.NewMockTpsLimiter(ctrl) mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(false).Times(1) - extension.SetTpsLimiter(constant.DEFAULT_KEY, func() filter.TpsLimiter { + extension.SetTpsLimiter(constant.DEFAULT_KEY, func() intf.TpsLimiter { return mockLimiter }) mockResult := &protocol.RPCResult{} - mockRejectedHandler := filter.NewMockRejectedExecutionHandler(ctrl) + mockRejectedHandler := tps.NewMockRejectedExecutionHandler(ctrl) mockRejectedHandler.EXPECT().RejectedExecution(gomock.Any(), gomock.Any()).Return(mockResult).Times(1) - extension.SetTpsRejectedExecutionHandler(constant.DEFAULT_KEY, func() filter.RejectedExecutionHandler { + extension.SetTpsRejectedExecutionHandler(constant.DEFAULT_KEY, func() intf.RejectedExecutionHandler { return mockRejectedHandler }) From 122629c86184eddb9ad54c7fa3acad6dfaee1587 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Thu, 17 Oct 2019 20:24:58 +0800 Subject: [PATCH 10/12] fix reveiw: rename the file --- ...r_only_log_impl.go => rejected_execution_handler_only_log.go} | 0 ..._impl_test.go => rejected_execution_handler_only_log_test.go} | 0 ..._window_strategy_impl.go => tps_limit_fix_window_strategy.go} | 0 ...rategy_impl_test.go => tps_limit_fix_window_strategy_test.go} | 0 ...dow_strategy_impl.go => tps_limit_sliding_window_strategy.go} | 0 ...gy_impl_test.go => tps_limit_sliding_window_strategy_test.go} | 0 ...tegy_impl.go => tps_limit_thread_safe_fix_window_strategy.go} | 0 ...test.go => tps_limit_thread_safe_fix_window_strategy_test.go} | 0 ...iter_method_service_impl.go => tps_limiter_method_service.go} | 0 ...d_service_impl_test.go => tps_limiter_method_service_test.go} | 0 filter/impl/tps_limit_filter.go | 1 + 11 files changed, 1 insertion(+) rename filter/impl/tps/{rejected_execution_handler_only_log_impl.go => rejected_execution_handler_only_log.go} (100%) rename filter/impl/tps/{rejected_execution_handler_only_log_impl_test.go => rejected_execution_handler_only_log_test.go} (100%) rename filter/impl/tps/{tps_limit_fix_window_strategy_impl.go => tps_limit_fix_window_strategy.go} (100%) rename filter/impl/tps/{tps_limit_fix_window_strategy_impl_test.go => tps_limit_fix_window_strategy_test.go} (100%) rename filter/impl/tps/{tps_limit_sliding_window_strategy_impl.go => tps_limit_sliding_window_strategy.go} (100%) rename filter/impl/tps/{tps_limit_sliding_window_strategy_impl_test.go => tps_limit_sliding_window_strategy_test.go} (100%) rename filter/impl/tps/{tps_limit_thread_safe_fix_window_strategy_impl.go => tps_limit_thread_safe_fix_window_strategy.go} (100%) rename filter/impl/tps/{tps_limit_thread_safe_fix_window_strategy_impl_test.go => tps_limit_thread_safe_fix_window_strategy_test.go} (100%) rename filter/impl/tps/{tps_limiter_method_service_impl.go => tps_limiter_method_service.go} (100%) rename filter/impl/tps/{tps_limiter_method_service_impl_test.go => tps_limiter_method_service_test.go} (100%) diff --git a/filter/impl/tps/rejected_execution_handler_only_log_impl.go b/filter/impl/tps/rejected_execution_handler_only_log.go similarity index 100% rename from filter/impl/tps/rejected_execution_handler_only_log_impl.go rename to filter/impl/tps/rejected_execution_handler_only_log.go diff --git a/filter/impl/tps/rejected_execution_handler_only_log_impl_test.go b/filter/impl/tps/rejected_execution_handler_only_log_test.go similarity index 100% rename from filter/impl/tps/rejected_execution_handler_only_log_impl_test.go rename to filter/impl/tps/rejected_execution_handler_only_log_test.go diff --git a/filter/impl/tps/tps_limit_fix_window_strategy_impl.go b/filter/impl/tps/tps_limit_fix_window_strategy.go similarity index 100% rename from filter/impl/tps/tps_limit_fix_window_strategy_impl.go rename to filter/impl/tps/tps_limit_fix_window_strategy.go diff --git a/filter/impl/tps/tps_limit_fix_window_strategy_impl_test.go b/filter/impl/tps/tps_limit_fix_window_strategy_test.go similarity index 100% rename from filter/impl/tps/tps_limit_fix_window_strategy_impl_test.go rename to filter/impl/tps/tps_limit_fix_window_strategy_test.go diff --git a/filter/impl/tps/tps_limit_sliding_window_strategy_impl.go b/filter/impl/tps/tps_limit_sliding_window_strategy.go similarity index 100% rename from filter/impl/tps/tps_limit_sliding_window_strategy_impl.go rename to filter/impl/tps/tps_limit_sliding_window_strategy.go diff --git a/filter/impl/tps/tps_limit_sliding_window_strategy_impl_test.go b/filter/impl/tps/tps_limit_sliding_window_strategy_test.go similarity index 100% rename from filter/impl/tps/tps_limit_sliding_window_strategy_impl_test.go rename to filter/impl/tps/tps_limit_sliding_window_strategy_test.go diff --git a/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl.go b/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy.go similarity index 100% rename from filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl.go rename to filter/impl/tps/tps_limit_thread_safe_fix_window_strategy.go diff --git a/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl_test.go b/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_test.go similarity index 100% rename from filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_impl_test.go rename to filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_test.go diff --git a/filter/impl/tps/tps_limiter_method_service_impl.go b/filter/impl/tps/tps_limiter_method_service.go similarity index 100% rename from filter/impl/tps/tps_limiter_method_service_impl.go rename to filter/impl/tps/tps_limiter_method_service.go diff --git a/filter/impl/tps/tps_limiter_method_service_impl_test.go b/filter/impl/tps/tps_limiter_method_service_test.go similarity index 100% rename from filter/impl/tps/tps_limiter_method_service_impl_test.go rename to filter/impl/tps/tps_limiter_method_service_test.go diff --git a/filter/impl/tps_limit_filter.go b/filter/impl/tps_limit_filter.go index fc3a5a8a3e..11f969e865 100644 --- a/filter/impl/tps_limit_filter.go +++ b/filter/impl/tps_limit_filter.go @@ -21,6 +21,7 @@ import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/filter" + _ "github.com/apache/dubbo-go/filter/impl/tps" "github.com/apache/dubbo-go/protocol" ) From 6dd82ff5282e4e74c0ca37b9f706bd0e437b322a Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Thu, 17 Oct 2019 23:21:00 +0800 Subject: [PATCH 11/12] Fix review --- .DS_Store | Bin 0 -> 6148 bytes common/extension/tps_limit.go | 20 +++++++++--------- .../rejected_execution_handler_mock.go | 2 +- .../rejected_execution_handler_only_log.go | 6 +++--- ...ejected_execution_handler_only_log_test.go | 2 +- .../tps_limit_fix_window_strategy.go | 6 +++--- .../tps_limit_fix_window_strategy_test.go | 2 +- .../tps_limit_sliding_window_strategy.go | 6 +++--- .../tps_limit_sliding_window_strategy_test.go | 2 +- .../tps/{ => impl}/tps_limit_strategy_mock.go | 2 +- ...s_limit_thread_safe_fix_window_strategy.go | 6 +++--- ...it_thread_safe_fix_window_strategy_test.go | 2 +- .../{ => impl}/tps_limiter_method_service.go | 10 ++++----- .../tps_limiter_method_service_test.go | 10 ++++----- .../impl/tps/{ => impl}/tps_limiter_mock.go | 2 +- .../{intf => }/rejected_execution_handler.go | 2 +- .../impl/tps/{intf => }/tps_limit_strategy.go | 2 +- filter/impl/tps/{intf => }/tps_limiter.go | 2 +- filter/impl/tps_limit_filter.go | 2 +- filter/impl/tps_limit_filter_test.go | 14 ++++++------ 20 files changed, 50 insertions(+), 50 deletions(-) create mode 100644 .DS_Store rename filter/impl/tps/{ => impl}/rejected_execution_handler_mock.go (99%) rename filter/impl/tps/{ => impl}/rejected_execution_handler_only_log.go (94%) rename filter/impl/tps/{ => impl}/rejected_execution_handler_only_log_test.go (98%) rename filter/impl/tps/{ => impl}/tps_limit_fix_window_strategy.go (96%) rename filter/impl/tps/{ => impl}/tps_limit_fix_window_strategy_test.go (99%) rename filter/impl/tps/{ => impl}/tps_limit_sliding_window_strategy.go (96%) rename filter/impl/tps/{ => impl}/tps_limit_sliding_window_strategy_test.go (99%) rename filter/impl/tps/{ => impl}/tps_limit_strategy_mock.go (99%) rename filter/impl/tps/{ => impl}/tps_limit_thread_safe_fix_window_strategy.go (95%) rename filter/impl/tps/{ => impl}/tps_limit_thread_safe_fix_window_strategy_test.go (99%) rename filter/impl/tps/{ => impl}/tps_limiter_method_service.go (96%) rename filter/impl/tps/{ => impl}/tps_limiter_method_service_test.go (96%) rename filter/impl/tps/{ => impl}/tps_limiter_mock.go (99%) rename filter/impl/tps/{intf => }/rejected_execution_handler.go (99%) rename filter/impl/tps/{intf => }/tps_limit_strategy.go (99%) rename filter/impl/tps/{intf => }/tps_limiter.go (98%) diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d5ca99c072f19da18d683d2bab5ca96b42c1d7b8 GIT binary patch literal 6148 zcmeHKI|@QE5ZqM}!N$@uSMUZw^aNhO!ViKdh+4nOb9pppKaD=^w2@iZOtRTY$P{ni ziil1xtBJ@+L`kk+3y3!?aM}XvX}D<-}Y!! zfC^9nDnJFOz;_kM`Z^eX_gJ1r1*pIuC}7`*0ynIQO`v}|Fn9|9>>=!ix%U#lVgX=H zYyuI1X;6Vd)od{|=!lohtBFlu&_%QP(7ai*Ls7pS=NC^Gt$`e=02O#vpc~7P)&DvC zL;wFw;))7Tfxl8fd$YxCiYH}lZ9UFvZGkW0mUD-jVeS+RUXFoYjD>lb| WO>6?4j=0l-{24G^XjI_W3OoQ4N)@C4 literal 0 HcmV?d00001 diff --git a/common/extension/tps_limit.go b/common/extension/tps_limit.go index e789d5b106..7d5cb8e9f6 100644 --- a/common/extension/tps_limit.go +++ b/common/extension/tps_limit.go @@ -18,20 +18,20 @@ package extension import ( - "github.com/apache/dubbo-go/filter/impl/tps/intf" + "github.com/apache/dubbo-go/filter/impl/tps" ) var ( - tpsLimitStrategy = make(map[string]func(rate int, interval int) intf.TpsLimitStrategy) - tpsLimiter = make(map[string]func() intf.TpsLimiter) - tpsRejectedExecutionHandler = make(map[string]func() intf.RejectedExecutionHandler) + tpsLimitStrategy = make(map[string]func(rate int, interval int) tps.TpsLimitStrategy) + tpsLimiter = make(map[string]func() tps.TpsLimiter) + tpsRejectedExecutionHandler = make(map[string]func() tps.RejectedExecutionHandler) ) -func SetTpsLimiter(name string, creator func() intf.TpsLimiter) { +func SetTpsLimiter(name string, creator func() tps.TpsLimiter) { tpsLimiter[name] = creator } -func GetTpsLimiter(name string) intf.TpsLimiter { +func GetTpsLimiter(name string) tps.TpsLimiter { creator, ok := tpsLimiter[name] if !ok { panic("TpsLimiter for " + name + " is not existing, make sure you have import the package " + @@ -40,11 +40,11 @@ func GetTpsLimiter(name string) intf.TpsLimiter { return creator() } -func SetTpsLimitStrategy(name string, creator func(rate int, interval int) intf.TpsLimitStrategy) { +func SetTpsLimitStrategy(name string, creator func(rate int, interval int) tps.TpsLimitStrategy) { tpsLimitStrategy[name] = creator } -func GetTpsLimitStrategyCreator(name string) func(rate int, interval int) intf.TpsLimitStrategy { +func GetTpsLimitStrategyCreator(name string) func(rate int, interval int) tps.TpsLimitStrategy { creator, ok := tpsLimitStrategy[name] if !ok { panic("TpsLimitStrategy for " + name + " is not existing, make sure you have import the package " + @@ -53,11 +53,11 @@ func GetTpsLimitStrategyCreator(name string) func(rate int, interval int) intf.T return creator } -func SetTpsRejectedExecutionHandler(name string, creator func() intf.RejectedExecutionHandler) { +func SetTpsRejectedExecutionHandler(name string, creator func() tps.RejectedExecutionHandler) { tpsRejectedExecutionHandler[name] = creator } -func GetTpsRejectedExecutionHandler(name string) intf.RejectedExecutionHandler { +func GetTpsRejectedExecutionHandler(name string) tps.RejectedExecutionHandler { creator, ok := tpsRejectedExecutionHandler[name] if !ok { panic("TpsRejectedExecutionHandler for " + name + " is not existing, make sure you have import the package " + diff --git a/filter/impl/tps/rejected_execution_handler_mock.go b/filter/impl/tps/impl/rejected_execution_handler_mock.go similarity index 99% rename from filter/impl/tps/rejected_execution_handler_mock.go rename to filter/impl/tps/impl/rejected_execution_handler_mock.go index 55b01f022f..2f7869d61e 100644 --- a/filter/impl/tps/rejected_execution_handler_mock.go +++ b/filter/impl/tps/impl/rejected_execution_handler_mock.go @@ -18,7 +18,7 @@ // Source: rejected_execution_handler.go // Package filter is a generated GoMock package. -package tps +package impl import ( common "github.com/apache/dubbo-go/common" diff --git a/filter/impl/tps/rejected_execution_handler_only_log.go b/filter/impl/tps/impl/rejected_execution_handler_only_log.go similarity index 94% rename from filter/impl/tps/rejected_execution_handler_only_log.go rename to filter/impl/tps/impl/rejected_execution_handler_only_log.go index 596160f07c..62d2fc81cb 100644 --- a/filter/impl/tps/rejected_execution_handler_only_log.go +++ b/filter/impl/tps/impl/rejected_execution_handler_only_log.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package tps +package impl import ( "sync" @@ -26,7 +26,7 @@ import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/common/logger" - "github.com/apache/dubbo-go/filter/impl/tps/intf" + "github.com/apache/dubbo-go/filter/impl/tps" "github.com/apache/dubbo-go/protocol" ) @@ -61,7 +61,7 @@ func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL return &protocol.RPCResult{} } -func GetOnlyLogRejectedExecutionHandler() intf.RejectedExecutionHandler { +func GetOnlyLogRejectedExecutionHandler() tps.RejectedExecutionHandler { onlyLogHandlerOnce.Do(func() { onlyLogHandlerInstance = &OnlyLogRejectedExecutionHandler{} }) diff --git a/filter/impl/tps/rejected_execution_handler_only_log_test.go b/filter/impl/tps/impl/rejected_execution_handler_only_log_test.go similarity index 98% rename from filter/impl/tps/rejected_execution_handler_only_log_test.go rename to filter/impl/tps/impl/rejected_execution_handler_only_log_test.go index beff7e3f2c..da54d8a106 100644 --- a/filter/impl/tps/rejected_execution_handler_only_log_test.go +++ b/filter/impl/tps/impl/rejected_execution_handler_only_log_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package tps +package impl import ( "net/url" diff --git a/filter/impl/tps/tps_limit_fix_window_strategy.go b/filter/impl/tps/impl/tps_limit_fix_window_strategy.go similarity index 96% rename from filter/impl/tps/tps_limit_fix_window_strategy.go rename to filter/impl/tps/impl/tps_limit_fix_window_strategy.go index 7e4032c684..7290619d55 100644 --- a/filter/impl/tps/tps_limit_fix_window_strategy.go +++ b/filter/impl/tps/impl/tps_limit_fix_window_strategy.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package tps +package impl import ( "sync/atomic" @@ -24,7 +24,7 @@ import ( import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter/impl/tps/intf" + "github.com/apache/dubbo-go/filter/impl/tps" ) const ( @@ -75,7 +75,7 @@ func (impl *FixedWindowTpsLimitStrategyImpl) IsAllowable() bool { return atomic.AddInt32(&impl.count, 1) <= impl.rate } -func NewFixedWindowTpsLimitStrategyImpl(rate int, interval int) intf.TpsLimitStrategy { +func NewFixedWindowTpsLimitStrategyImpl(rate int, interval int) tps.TpsLimitStrategy { return &FixedWindowTpsLimitStrategyImpl{ rate: int32(rate), interval: int64(interval * 1000), // convert to ns diff --git a/filter/impl/tps/tps_limit_fix_window_strategy_test.go b/filter/impl/tps/impl/tps_limit_fix_window_strategy_test.go similarity index 99% rename from filter/impl/tps/tps_limit_fix_window_strategy_test.go rename to filter/impl/tps/impl/tps_limit_fix_window_strategy_test.go index 8848a05dde..55d0b14b75 100644 --- a/filter/impl/tps/tps_limit_fix_window_strategy_test.go +++ b/filter/impl/tps/impl/tps_limit_fix_window_strategy_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package tps +package impl import ( "testing" diff --git a/filter/impl/tps/tps_limit_sliding_window_strategy.go b/filter/impl/tps/impl/tps_limit_sliding_window_strategy.go similarity index 96% rename from filter/impl/tps/tps_limit_sliding_window_strategy.go rename to filter/impl/tps/impl/tps_limit_sliding_window_strategy.go index 3a8db5ab37..de98eb7528 100644 --- a/filter/impl/tps/tps_limit_sliding_window_strategy.go +++ b/filter/impl/tps/impl/tps_limit_sliding_window_strategy.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package tps +package impl import ( "container/list" @@ -25,7 +25,7 @@ import ( import ( "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter/impl/tps/intf" + "github.com/apache/dubbo-go/filter/impl/tps" ) func init() { @@ -80,7 +80,7 @@ func (impl *SlidingWindowTpsLimitStrategyImpl) IsAllowable() bool { return false } -func NewSlidingWindowTpsLimitStrategyImpl(rate int, interval int) intf.TpsLimitStrategy { +func NewSlidingWindowTpsLimitStrategyImpl(rate int, interval int) tps.TpsLimitStrategy { return &SlidingWindowTpsLimitStrategyImpl{ rate: rate, interval: int64(interval * 1000), diff --git a/filter/impl/tps/tps_limit_sliding_window_strategy_test.go b/filter/impl/tps/impl/tps_limit_sliding_window_strategy_test.go similarity index 99% rename from filter/impl/tps/tps_limit_sliding_window_strategy_test.go rename to filter/impl/tps/impl/tps_limit_sliding_window_strategy_test.go index 1bca13d401..1d0187fa20 100644 --- a/filter/impl/tps/tps_limit_sliding_window_strategy_test.go +++ b/filter/impl/tps/impl/tps_limit_sliding_window_strategy_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package tps +package impl import ( "testing" diff --git a/filter/impl/tps/tps_limit_strategy_mock.go b/filter/impl/tps/impl/tps_limit_strategy_mock.go similarity index 99% rename from filter/impl/tps/tps_limit_strategy_mock.go rename to filter/impl/tps/impl/tps_limit_strategy_mock.go index 72c658fb9a..a653fb287a 100644 --- a/filter/impl/tps/tps_limit_strategy_mock.go +++ b/filter/impl/tps/impl/tps_limit_strategy_mock.go @@ -18,7 +18,7 @@ // Source: tps_limit_strategy.go // Package filter is a generated GoMock package. -package tps +package impl import ( gomock "github.com/golang/mock/gomock" diff --git a/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy.go b/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy.go similarity index 95% rename from filter/impl/tps/tps_limit_thread_safe_fix_window_strategy.go rename to filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy.go index 3541252dbe..5f43e8c3bf 100644 --- a/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy.go +++ b/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package tps +package impl import ( "sync" @@ -23,7 +23,7 @@ import ( import ( "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter/impl/tps/intf" + "github.com/apache/dubbo-go/filter/impl/tps" ) func init() { @@ -56,7 +56,7 @@ func (impl *ThreadSafeFixedWindowTpsLimitStrategyImpl) IsAllowable() bool { return impl.fixedWindow.IsAllowable() } -func NewThreadSafeFixedWindowTpsLimitStrategyImpl(rate int, interval int) intf.TpsLimitStrategy { +func NewThreadSafeFixedWindowTpsLimitStrategyImpl(rate int, interval int) tps.TpsLimitStrategy { fixedWindowStrategy := NewFixedWindowTpsLimitStrategyImpl(rate, interval).(*FixedWindowTpsLimitStrategyImpl) return &ThreadSafeFixedWindowTpsLimitStrategyImpl{ fixedWindow: fixedWindowStrategy, diff --git a/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_test.go b/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy_test.go similarity index 99% rename from filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_test.go rename to filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy_test.go index 72cd4800de..fea93dfa3b 100644 --- a/filter/impl/tps/tps_limit_thread_safe_fix_window_strategy_test.go +++ b/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package tps +package impl import ( "testing" diff --git a/filter/impl/tps/tps_limiter_method_service.go b/filter/impl/tps/impl/tps_limiter_method_service.go similarity index 96% rename from filter/impl/tps/tps_limiter_method_service.go rename to filter/impl/tps/impl/tps_limiter_method_service.go index 01d9f6564a..3faf0d6e67 100644 --- a/filter/impl/tps/tps_limiter_method_service.go +++ b/filter/impl/tps/impl/tps_limiter_method_service.go @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package tps +package impl import ( "fmt" @@ -30,7 +30,7 @@ import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter/impl/tps/intf" + "github.com/apache/dubbo-go/filter/impl/tps" "github.com/apache/dubbo-go/protocol" ) @@ -127,7 +127,7 @@ func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocatio limitState, found := limiter.tpsState.Load(limitTarget) if found { - return limitState.(intf.TpsLimitStrategy).IsAllowable() + return limitState.(tps.TpsLimitStrategy).IsAllowable() } limitRate := getLimitConfig(methodLimitRateConfig, url, invocation, @@ -149,7 +149,7 @@ func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocatio url.GetParam(constant.TPS_LIMIT_STRATEGY_KEY, constant.DEFAULT_KEY)) limitStateCreator := extension.GetTpsLimitStrategyCreator(limitStrategyConfig) limitState, _ = limiter.tpsState.LoadOrStore(limitTarget, limitStateCreator(int(limitRate), int(limitInterval))) - return limitState.(intf.TpsLimitStrategy).IsAllowable() + return limitState.(tps.TpsLimitStrategy).IsAllowable() } func getLimitConfig(methodLevelConfig string, @@ -178,7 +178,7 @@ func getLimitConfig(methodLevelConfig string, var methodServiceTpsLimiterInstance *MethodServiceTpsLimiterImpl var methodServiceTpsLimiterOnce sync.Once -func GetMethodServiceTpsLimiter() intf.TpsLimiter { +func GetMethodServiceTpsLimiter() tps.TpsLimiter { methodServiceTpsLimiterOnce.Do(func() { methodServiceTpsLimiterInstance = &MethodServiceTpsLimiterImpl{ tpsState: concurrent.NewMap(), diff --git a/filter/impl/tps/tps_limiter_method_service_test.go b/filter/impl/tps/impl/tps_limiter_method_service_test.go similarity index 96% rename from filter/impl/tps/tps_limiter_method_service_test.go rename to filter/impl/tps/impl/tps_limiter_method_service_test.go index 8a6fa8398d..006e946387 100644 --- a/filter/impl/tps/tps_limiter_method_service_test.go +++ b/filter/impl/tps/impl/tps_limiter_method_service_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package tps +package impl import ( "net/url" @@ -30,7 +30,7 @@ import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" - "github.com/apache/dubbo-go/filter/impl/tps/intf" + "github.com/apache/dubbo-go/filter/impl/tps" "github.com/apache/dubbo-go/protocol/invocation" ) @@ -48,7 +48,7 @@ func TestMethodServiceTpsLimiterImpl_IsAllowable_Only_Service_Level(t *testing.T mockStrategyImpl := NewMockTpsLimitStrategy(ctrl) mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) - extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) intf.TpsLimitStrategy { + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) tps.TpsLimitStrategy { assert.Equal(t, 20, rate) assert.Equal(t, 60000, interval) return mockStrategyImpl @@ -95,7 +95,7 @@ func TestMethodServiceTpsLimiterImpl_IsAllowable_Method_Level_Override(t *testin mockStrategyImpl := NewMockTpsLimitStrategy(ctrl) mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) - extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) intf.TpsLimitStrategy { + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) tps.TpsLimitStrategy { assert.Equal(t, 40, rate) assert.Equal(t, 7000, interval) return mockStrategyImpl @@ -123,7 +123,7 @@ func TestMethodServiceTpsLimiterImpl_IsAllowable_Both_Method_And_Service(t *test mockStrategyImpl := NewMockTpsLimitStrategy(ctrl) mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1) - extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) intf.TpsLimitStrategy { + extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, func(rate int, interval int) tps.TpsLimitStrategy { assert.Equal(t, 40, rate) assert.Equal(t, 3000, interval) return mockStrategyImpl diff --git a/filter/impl/tps/tps_limiter_mock.go b/filter/impl/tps/impl/tps_limiter_mock.go similarity index 99% rename from filter/impl/tps/tps_limiter_mock.go rename to filter/impl/tps/impl/tps_limiter_mock.go index a247bf14da..ff2f984e13 100644 --- a/filter/impl/tps/tps_limiter_mock.go +++ b/filter/impl/tps/impl/tps_limiter_mock.go @@ -18,7 +18,7 @@ // Source: tps_limiter.go // Package filter is a generated GoMock package. -package tps +package impl import ( common "github.com/apache/dubbo-go/common" diff --git a/filter/impl/tps/intf/rejected_execution_handler.go b/filter/impl/tps/rejected_execution_handler.go similarity index 99% rename from filter/impl/tps/intf/rejected_execution_handler.go rename to filter/impl/tps/rejected_execution_handler.go index 1e0c0938f8..827908974e 100644 --- a/filter/impl/tps/intf/rejected_execution_handler.go +++ b/filter/impl/tps/rejected_execution_handler.go @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package intf +package tps import ( "github.com/apache/dubbo-go/common" diff --git a/filter/impl/tps/intf/tps_limit_strategy.go b/filter/impl/tps/tps_limit_strategy.go similarity index 99% rename from filter/impl/tps/intf/tps_limit_strategy.go rename to filter/impl/tps/tps_limit_strategy.go index ed52daebf6..d1af85b464 100644 --- a/filter/impl/tps/intf/tps_limit_strategy.go +++ b/filter/impl/tps/tps_limit_strategy.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package intf +package tps /* * please register your implementation by invoking SetTpsLimitStrategy diff --git a/filter/impl/tps/intf/tps_limiter.go b/filter/impl/tps/tps_limiter.go similarity index 98% rename from filter/impl/tps/intf/tps_limiter.go rename to filter/impl/tps/tps_limiter.go index d3935c11de..0622a957a8 100644 --- a/filter/impl/tps/intf/tps_limiter.go +++ b/filter/impl/tps/tps_limiter.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package intf +package tps import ( "github.com/apache/dubbo-go/common" diff --git a/filter/impl/tps_limit_filter.go b/filter/impl/tps_limit_filter.go index 11f969e865..1e3222c0e8 100644 --- a/filter/impl/tps_limit_filter.go +++ b/filter/impl/tps_limit_filter.go @@ -21,7 +21,7 @@ import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/filter" - _ "github.com/apache/dubbo-go/filter/impl/tps" + _ "github.com/apache/dubbo-go/filter/impl/tps/impl" "github.com/apache/dubbo-go/protocol" ) diff --git a/filter/impl/tps_limit_filter_test.go b/filter/impl/tps_limit_filter_test.go index 18a72ba9e9..5f5557b07e 100644 --- a/filter/impl/tps_limit_filter_test.go +++ b/filter/impl/tps_limit_filter_test.go @@ -32,7 +32,7 @@ import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/filter/impl/tps" - "github.com/apache/dubbo-go/filter/impl/tps/intf" + "github.com/apache/dubbo-go/filter/impl/tps/impl" "github.com/apache/dubbo-go/protocol" "github.com/apache/dubbo-go/protocol/invocation" ) @@ -54,9 +54,9 @@ func TestTpsLimitFilter_Invoke_With_No_TpsLimiter(t *testing.T) { func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - mockLimiter := tps.NewMockTpsLimiter(ctrl) + mockLimiter := impl.NewMockTpsLimiter(ctrl) mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(true).Times(1) - extension.SetTpsLimiter(constant.DEFAULT_KEY, func() intf.TpsLimiter { + extension.SetTpsLimiter(constant.DEFAULT_KEY, func() tps.TpsLimiter { return mockLimiter }) @@ -75,17 +75,17 @@ func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) { func TestGenericFilter_Invoke_With_Default_TpsLimiter_Not_Allow(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - mockLimiter := tps.NewMockTpsLimiter(ctrl) + mockLimiter := impl.NewMockTpsLimiter(ctrl) mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(false).Times(1) - extension.SetTpsLimiter(constant.DEFAULT_KEY, func() intf.TpsLimiter { + extension.SetTpsLimiter(constant.DEFAULT_KEY, func() tps.TpsLimiter { return mockLimiter }) mockResult := &protocol.RPCResult{} - mockRejectedHandler := tps.NewMockRejectedExecutionHandler(ctrl) + mockRejectedHandler := impl.NewMockRejectedExecutionHandler(ctrl) mockRejectedHandler.EXPECT().RejectedExecution(gomock.Any(), gomock.Any()).Return(mockResult).Times(1) - extension.SetTpsRejectedExecutionHandler(constant.DEFAULT_KEY, func() intf.RejectedExecutionHandler { + extension.SetTpsRejectedExecutionHandler(constant.DEFAULT_KEY, func() tps.RejectedExecutionHandler { return mockRejectedHandler }) From 7c9bcec8ac81490f83f16a89f67cef237fb563d6 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Thu, 17 Oct 2019 23:22:49 +0800 Subject: [PATCH 12/12] Fix Review --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index d5ca99c072f19da18d683d2bab5ca96b42c1d7b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKI|@QE5ZqM}!N$@uSMUZw^aNhO!ViKdh+4nOb9pppKaD=^w2@iZOtRTY$P{ni ziil1xtBJ@+L`kk+3y3!?aM}XvX}D<-}Y!! zfC^9nDnJFOz;_kM`Z^eX_gJ1r1*pIuC}7`*0ynIQO`v}|Fn9|9>>=!ix%U#lVgX=H zYyuI1X;6Vd)od{|=!lohtBFlu&_%QP(7ai*Ls7pS=NC^Gt$`e=02O#vpc~7P)&DvC zL;wFw;))7Tfxl8fd$YxCiYH}lZ9UFvZGkW0mUD-jVeS+RUXFoYjD>lb| WO>6?4j=0l-{24G^XjI_W3OoQ4N)@C4