Remove Quota service.
This commit is contained in:
parent
a5e86c2e5e
commit
4a74c50150
@ -82,46 +82,6 @@ dashboard:
|
||||
# Maximum allowed datapoints fetched by widgets
|
||||
max_datapoints_limit: "${DASHBOARD_MAX_DATAPOINTS_LIMIT:50000}"
|
||||
|
||||
#Quota parameters
|
||||
quota:
|
||||
host:
|
||||
# Max allowed number of API requests in interval for single host
|
||||
limit: "${QUOTA_HOST_LIMIT:10000}"
|
||||
# Interval duration
|
||||
intervalMs: "${QUOTA_HOST_INTERVAL_MS:60000}"
|
||||
# Maximum silence duration for host after which Host removed from QuotaService. Must be bigger than intervalMs
|
||||
ttlMs: "${QUOTA_HOST_TTL_MS:60000}"
|
||||
# Interval for scheduled task that cleans expired records. TTL is used for expiring
|
||||
cleanPeriodMs: "${QUOTA_HOST_CLEAN_PERIOD_MS:300000}"
|
||||
# Enable Host API Limits
|
||||
enabled: "${QUOTA_HOST_ENABLED:false}"
|
||||
# Array of whitelist hosts
|
||||
whitelist: "${QUOTA_HOST_WHITELIST:localhost,127.0.0.1}"
|
||||
# Array of blacklist hosts
|
||||
blacklist: "${QUOTA_HOST_BLACKLIST:}"
|
||||
log:
|
||||
topSize: "${QUOTA_HOST_LOG_TOP_SIZE:10}"
|
||||
intervalMin: "${QUOTA_HOST_LOG_INTERVAL_MIN:2}"
|
||||
rule:
|
||||
tenant:
|
||||
# Max allowed number of API requests in interval for single tenant
|
||||
limit: "${QUOTA_TENANT_LIMIT:100000}"
|
||||
# Interval duration
|
||||
intervalMs: "${QUOTA_TENANT_INTERVAL_MS:60000}"
|
||||
# Maximum silence duration for tenant after which Tenant removed from QuotaService. Must be bigger than intervalMs
|
||||
ttlMs: "${QUOTA_TENANT_TTL_MS:60000}"
|
||||
# Interval for scheduled task that cleans expired records. TTL is used for expiring
|
||||
cleanPeriodMs: "${QUOTA_TENANT_CLEAN_PERIOD_MS:300000}"
|
||||
# Enable Host API Limits
|
||||
enabled: "${QUOTA_TENANT_ENABLED:true}"
|
||||
# Array of whitelist tenants
|
||||
whitelist: "${QUOTA_TENANT_WHITELIST:}"
|
||||
# Array of blacklist tenants
|
||||
blacklist: "${QUOTA_HOST_TENANT_BLACKLIST:}"
|
||||
log:
|
||||
topSize: "${QUOTA_TENANT_LOG_TOP_SIZE:10}"
|
||||
intervalMin: "${QUOTA_TENANT_LOG_INTERVAL_MIN:2}"
|
||||
|
||||
database:
|
||||
entities:
|
||||
type: "${DATABASE_ENTITIES_TYPE:sql}" # cassandra OR sql
|
||||
|
||||
@ -72,12 +72,6 @@ public class CoapTransportResource extends CoapResource {
|
||||
|
||||
@Override
|
||||
public void handleGET(CoapExchange exchange) {
|
||||
if (transportContext.getQuotaService().isQuotaExceeded(exchange.getSourceAddress().getHostAddress())) {
|
||||
log.warn("CoAP Quota exceeded for [{}:{}] . Disconnect", exchange.getSourceAddress().getHostAddress(), exchange.getSourcePort());
|
||||
exchange.respond(ResponseCode.BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest());
|
||||
if (!featureType.isPresent()) {
|
||||
log.trace("Missing feature type parameter");
|
||||
@ -108,12 +102,6 @@ public class CoapTransportResource extends CoapResource {
|
||||
|
||||
@Override
|
||||
public void handlePOST(CoapExchange exchange) {
|
||||
if (transportContext.getQuotaService().isQuotaExceeded(exchange.getSourceAddress().getHostAddress())) {
|
||||
log.warn("CoAP Quota exceeded for [{}:{}] . Disconnect", exchange.getSourceAddress().getHostAddress(), exchange.getSourcePort());
|
||||
exchange.respond(ResponseCode.BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<FeatureType> featureType = getFeatureType(exchange.advanced().getRequest());
|
||||
if (!featureType.isPresent()) {
|
||||
log.trace("Missing feature type parameter");
|
||||
|
||||
@ -27,8 +27,6 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.transport.SessionMsgProcessor;
|
||||
import org.thingsboard.server.common.transport.auth.DeviceAuthService;
|
||||
import org.thingsboard.server.common.transport.quota.QuotaService;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostRequestsQuotaService;
|
||||
import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@ -75,9 +75,6 @@ public class DeviceApiController {
|
||||
@RequestParam(value = "sharedKeys", required = false, defaultValue = "") String sharedKeys,
|
||||
HttpServletRequest httpRequest) {
|
||||
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
|
||||
if (quotaExceeded(httpRequest, responseWriter)) {
|
||||
return responseWriter;
|
||||
}
|
||||
transportContext.getTransportService().process(ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
|
||||
new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
|
||||
GetAttributeRequestMsg.Builder request = GetAttributeRequestMsg.newBuilder().setRequestId(0);
|
||||
@ -100,9 +97,6 @@ public class DeviceApiController {
|
||||
public DeferredResult<ResponseEntity> postDeviceAttributes(@PathVariable("deviceToken") String deviceToken,
|
||||
@RequestBody String json, HttpServletRequest request) {
|
||||
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
|
||||
if (quotaExceeded(request, responseWriter)) {
|
||||
return responseWriter;
|
||||
}
|
||||
transportContext.getTransportService().process(ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
|
||||
new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
|
||||
TransportService transportService = transportContext.getTransportService();
|
||||
@ -116,9 +110,6 @@ public class DeviceApiController {
|
||||
public DeferredResult<ResponseEntity> postTelemetry(@PathVariable("deviceToken") String deviceToken,
|
||||
@RequestBody String json, HttpServletRequest request) {
|
||||
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>();
|
||||
if (quotaExceeded(request, responseWriter)) {
|
||||
return responseWriter;
|
||||
}
|
||||
transportContext.getTransportService().process(ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
|
||||
new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
|
||||
TransportService transportService = transportContext.getTransportService();
|
||||
@ -133,9 +124,6 @@ public class DeviceApiController {
|
||||
@RequestParam(value = "timeout", required = false, defaultValue = "0") long timeout,
|
||||
HttpServletRequest httpRequest) {
|
||||
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
|
||||
if (quotaExceeded(httpRequest, responseWriter)) {
|
||||
return responseWriter;
|
||||
}
|
||||
transportContext.getTransportService().process(ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
|
||||
new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
|
||||
TransportService transportService = transportContext.getTransportService();
|
||||
@ -153,9 +141,6 @@ public class DeviceApiController {
|
||||
@PathVariable("requestId") Integer requestId,
|
||||
@RequestBody String json, HttpServletRequest request) {
|
||||
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>();
|
||||
if (quotaExceeded(request, responseWriter)) {
|
||||
return responseWriter;
|
||||
}
|
||||
transportContext.getTransportService().process(ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
|
||||
new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
|
||||
TransportService transportService = transportContext.getTransportService();
|
||||
@ -168,9 +153,6 @@ public class DeviceApiController {
|
||||
public DeferredResult<ResponseEntity> postRpcRequest(@PathVariable("deviceToken") String deviceToken,
|
||||
@RequestBody String json, HttpServletRequest httpRequest) {
|
||||
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>();
|
||||
if (quotaExceeded(httpRequest, responseWriter)) {
|
||||
return responseWriter;
|
||||
}
|
||||
transportContext.getTransportService().process(ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
|
||||
new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
|
||||
JsonObject request = new JsonParser().parse(json).getAsJsonObject();
|
||||
@ -189,9 +171,6 @@ public class DeviceApiController {
|
||||
@RequestParam(value = "timeout", required = false, defaultValue = "0") long timeout,
|
||||
HttpServletRequest httpRequest) {
|
||||
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
|
||||
if (quotaExceeded(httpRequest, responseWriter)) {
|
||||
return responseWriter;
|
||||
}
|
||||
transportContext.getTransportService().process(ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
|
||||
new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
|
||||
TransportService transportService = transportContext.getTransportService();
|
||||
@ -204,16 +183,6 @@ public class DeviceApiController {
|
||||
return responseWriter;
|
||||
}
|
||||
|
||||
private boolean quotaExceeded(HttpServletRequest request, DeferredResult<ResponseEntity> responseWriter) {
|
||||
if (transportContext.getQuotaService().isQuotaExceeded(request.getRemoteAddr())) {
|
||||
log.warn("REST Quota exceeded for [{}] . Disconnect", request.getRemoteAddr());
|
||||
responseWriter.setResult(new ResponseEntity<>(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponseMsg> {
|
||||
private final TransportContext transportContext;
|
||||
private final DeferredResult<ResponseEntity> responseWriter;
|
||||
|
||||
@ -28,7 +28,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.TransportContext;
|
||||
import org.thingsboard.server.common.transport.TransportService;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostRequestsQuotaService;
|
||||
import org.thingsboard.server.kafka.TbNodeIdProvider;
|
||||
import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor;
|
||||
|
||||
|
||||
@ -42,7 +42,6 @@ import org.thingsboard.server.common.transport.SessionMsgListener;
|
||||
import org.thingsboard.server.common.transport.TransportService;
|
||||
import org.thingsboard.server.common.transport.TransportServiceCallback;
|
||||
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
|
||||
import org.thingsboard.server.common.transport.quota.QuotaService;
|
||||
import org.thingsboard.server.common.msg.EncryptionUtil;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
|
||||
@ -92,7 +91,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
|
||||
private final MqttTransportContext context;
|
||||
private final MqttTransportAdaptor adaptor;
|
||||
private final TransportService transportService;
|
||||
private final QuotaService quotaService;
|
||||
private final SslHandler sslHandler;
|
||||
private final ConcurrentMap<MqttTopicMatcher, Integer> mqttQoSMap;
|
||||
|
||||
@ -106,7 +104,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
|
||||
this.context = context;
|
||||
this.transportService = context.getTransportService();
|
||||
this.adaptor = context.getAdaptor();
|
||||
this.quotaService = context.getQuotaService();
|
||||
this.sslHandler = context.getSslHandler();
|
||||
this.mqttQoSMap = new ConcurrentHashMap<>();
|
||||
this.deviceSessionCtx = new DeviceSessionCtx(sessionId, mqttQoSMap);
|
||||
@ -129,13 +126,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
|
||||
processDisconnect(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (quotaService.isQuotaExceeded(address.getHostName())) {
|
||||
log.warn("MQTT Quota exceeded for [{}:{}] . Disconnect", address.getHostName(), address.getPort());
|
||||
processDisconnect(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
deviceSessionCtx.setChannel(ctx);
|
||||
switch (msg.fixedHeader().messageType()) {
|
||||
case CONNECT:
|
||||
|
||||
@ -20,7 +20,6 @@ import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostRequestsQuotaService;
|
||||
import org.thingsboard.server.kafka.TbNodeIdProvider;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@ -43,9 +42,6 @@ public class TransportContext {
|
||||
@Autowired
|
||||
private TbNodeIdProvider nodeIdProvider;
|
||||
|
||||
@Autowired(required = false)
|
||||
private HostRequestsQuotaService quotaService;
|
||||
|
||||
@Getter
|
||||
private ExecutorService executor;
|
||||
|
||||
|
||||
@ -1,67 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota;
|
||||
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.IntervalRegistryCleaner;
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.IntervalRegistryLogger;
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.KeyBasedIntervalRegistry;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
public class AbstractQuotaService implements QuotaService {
|
||||
|
||||
private final KeyBasedIntervalRegistry requestRegistry;
|
||||
private final RequestLimitPolicy requestsPolicy;
|
||||
private final IntervalRegistryCleaner registryCleaner;
|
||||
private final IntervalRegistryLogger registryLogger;
|
||||
private final boolean enabled;
|
||||
|
||||
public AbstractQuotaService(KeyBasedIntervalRegistry requestRegistry, RequestLimitPolicy requestsPolicy,
|
||||
IntervalRegistryCleaner registryCleaner, IntervalRegistryLogger registryLogger,
|
||||
boolean enabled) {
|
||||
this.requestRegistry = requestRegistry;
|
||||
this.requestsPolicy = requestsPolicy;
|
||||
this.registryCleaner = registryCleaner;
|
||||
this.registryLogger = registryLogger;
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (enabled) {
|
||||
registryCleaner.schedule();
|
||||
registryLogger.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void close() {
|
||||
if (enabled) {
|
||||
registryCleaner.stop();
|
||||
registryLogger.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQuotaExceeded(String key) {
|
||||
if (enabled) {
|
||||
long count = requestRegistry.tick(key);
|
||||
return !requestsPolicy.isValid(count);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
public final class Clock {
|
||||
|
||||
private static long time = 0L;
|
||||
|
||||
private Clock() {
|
||||
}
|
||||
|
||||
|
||||
public static long millis() {
|
||||
return time == 0 ? System.currentTimeMillis() : time;
|
||||
}
|
||||
|
||||
public static void setMillis(long millis) {
|
||||
time = millis;
|
||||
}
|
||||
|
||||
public static void shift(long delta) {
|
||||
time += delta;
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
time = 0;
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface QuotaService {
|
||||
|
||||
boolean isQuotaExceeded(String key);
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota;
|
||||
|
||||
|
||||
public abstract class RequestLimitPolicy {
|
||||
|
||||
private final long limit;
|
||||
|
||||
public RequestLimitPolicy(long limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public boolean isValid(long currentValue) {
|
||||
return currentValue <= limit;
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.host;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.IntervalRegistryCleaner;
|
||||
|
||||
@Component
|
||||
public class HostIntervalRegistryCleaner extends IntervalRegistryCleaner {
|
||||
|
||||
public HostIntervalRegistryCleaner(HostRequestIntervalRegistry intervalRegistry,
|
||||
@Value("${quota.host.cleanPeriodMs}") long cleanPeriodMs) {
|
||||
super(intervalRegistry, cleanPeriodMs);
|
||||
}
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.host;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.IntervalRegistryLogger;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class HostIntervalRegistryLogger extends IntervalRegistryLogger {
|
||||
|
||||
private final long logIntervalMin;
|
||||
|
||||
public HostIntervalRegistryLogger(@Value("${quota.host.log.topSize}") int topSize,
|
||||
@Value("${quota.host.log.intervalMin}") long logIntervalMin,
|
||||
HostRequestIntervalRegistry intervalRegistry) {
|
||||
super(topSize, logIntervalMin, intervalRegistry);
|
||||
this.logIntervalMin = logIntervalMin;
|
||||
}
|
||||
|
||||
protected void log(Map<String, Long> top, int uniqHosts, long requestsCount) {
|
||||
long rps = requestsCount / TimeUnit.MINUTES.toSeconds(logIntervalMin);
|
||||
StringBuilder builder = new StringBuilder("Quota Statistic : ");
|
||||
builder.append("uniqHosts : ").append(uniqHosts).append("; ");
|
||||
builder.append("requestsCount : ").append(requestsCount).append("; ");
|
||||
builder.append("RPS : ").append(rps).append(" ");
|
||||
builder.append("top -> ");
|
||||
for (Map.Entry<String, Long> host : top.entrySet()) {
|
||||
builder.append(host.getKey()).append(" : ").append(host.getValue()).append("; ");
|
||||
}
|
||||
|
||||
log.info(builder.toString());
|
||||
}
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.host;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.KeyBasedIntervalRegistry;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class HostRequestIntervalRegistry extends KeyBasedIntervalRegistry {
|
||||
|
||||
public HostRequestIntervalRegistry(@Value("${quota.host.intervalMs}") long intervalDurationMs,
|
||||
@Value("${quota.host.ttlMs}") long ttlMs,
|
||||
@Value("${quota.host.whitelist}") String whiteList,
|
||||
@Value("${quota.host.blacklist}") String blackList) {
|
||||
super(intervalDurationMs, ttlMs, whiteList, blackList, "host");
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.host;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.quota.RequestLimitPolicy;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
@Component
|
||||
public class HostRequestLimitPolicy extends RequestLimitPolicy {
|
||||
|
||||
public HostRequestLimitPolicy(@Value("${quota.host.limit}") long limit) {
|
||||
super(limit);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.host;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.transport.quota.AbstractQuotaService;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class HostRequestsQuotaService extends AbstractQuotaService {
|
||||
|
||||
public HostRequestsQuotaService(HostRequestIntervalRegistry requestRegistry, HostRequestLimitPolicy requestsPolicy,
|
||||
HostIntervalRegistryCleaner registryCleaner, HostIntervalRegistryLogger registryLogger,
|
||||
@Value("${quota.host.enabled}") boolean enabled) {
|
||||
super(requestRegistry, requestsPolicy, registryCleaner, registryLogger, enabled);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.inmemory;
|
||||
|
||||
|
||||
import org.thingsboard.server.common.transport.quota.Clock;
|
||||
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
public class IntervalCount {
|
||||
|
||||
private final LongAdder adder = new LongAdder();
|
||||
private final long intervalDurationMs;
|
||||
private volatile long startTime;
|
||||
private volatile long lastTickTime;
|
||||
|
||||
public IntervalCount(long intervalDurationMs) {
|
||||
this.intervalDurationMs = intervalDurationMs;
|
||||
startTime = Clock.millis();
|
||||
}
|
||||
|
||||
public long resetIfExpiredAndTick() {
|
||||
if (isExpired()) {
|
||||
reset();
|
||||
}
|
||||
tick();
|
||||
return adder.sum();
|
||||
}
|
||||
|
||||
public long silenceDuration() {
|
||||
return Clock.millis() - lastTickTime;
|
||||
}
|
||||
|
||||
public long getCount() {
|
||||
return adder.sum();
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
adder.add(1);
|
||||
lastTickTime = Clock.millis();
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
adder.reset();
|
||||
startTime = Clock.millis();
|
||||
}
|
||||
|
||||
private boolean isExpired() {
|
||||
return (Clock.millis() - startTime) > intervalDurationMs;
|
||||
}
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.inmemory;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class IntervalRegistryCleaner {
|
||||
|
||||
private final KeyBasedIntervalRegistry intervalRegistry;
|
||||
private final long cleanPeriodMs;
|
||||
private ScheduledExecutorService executor;
|
||||
|
||||
public IntervalRegistryCleaner(KeyBasedIntervalRegistry intervalRegistry, long cleanPeriodMs) {
|
||||
this.intervalRegistry = intervalRegistry;
|
||||
this.cleanPeriodMs = cleanPeriodMs;
|
||||
}
|
||||
|
||||
public void schedule() {
|
||||
if (executor != null) {
|
||||
throw new IllegalStateException("Registry Cleaner already scheduled");
|
||||
}
|
||||
executor = Executors.newSingleThreadScheduledExecutor();
|
||||
executor.scheduleAtFixedRate(this::clean, cleanPeriodMs, cleanPeriodMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (executor != null) {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
try {
|
||||
intervalRegistry.clean();
|
||||
} catch (RuntimeException ex) {
|
||||
log.error("Could not clear Interval Registry", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.inmemory;
|
||||
|
||||
import com.google.common.collect.MinMaxPriorityQueue;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class IntervalRegistryLogger {
|
||||
|
||||
private final int topSize;
|
||||
private final KeyBasedIntervalRegistry intervalRegistry;
|
||||
private final long logIntervalMin;
|
||||
private ScheduledExecutorService executor;
|
||||
|
||||
public IntervalRegistryLogger(int topSize, long logIntervalMin, KeyBasedIntervalRegistry intervalRegistry) {
|
||||
this.topSize = topSize;
|
||||
this.logIntervalMin = logIntervalMin;
|
||||
this.intervalRegistry = intervalRegistry;
|
||||
}
|
||||
|
||||
public void schedule() {
|
||||
if (executor != null) {
|
||||
throw new IllegalStateException("Registry Cleaner already scheduled");
|
||||
}
|
||||
executor = Executors.newSingleThreadScheduledExecutor();
|
||||
executor.scheduleAtFixedRate(this::logStatistic, logIntervalMin, logIntervalMin, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (executor != null) {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void logStatistic() {
|
||||
Map<String, Long> registryContent = intervalRegistry.getContent();
|
||||
int uniqHosts = registryContent.size();
|
||||
long requestsCount = registryContent.values().stream().mapToLong(i -> i).sum();
|
||||
Map<String, Long> top = getTopElements(registryContent);
|
||||
log(top, uniqHosts, requestsCount);
|
||||
}
|
||||
|
||||
protected Map<String, Long> getTopElements(Map<String, Long> countMap) {
|
||||
MinMaxPriorityQueue<Map.Entry<String, Long>> topQueue = MinMaxPriorityQueue
|
||||
.orderedBy(Comparator.comparing((Function<Map.Entry<String, Long>, Long>) Map.Entry::getValue).reversed())
|
||||
.maximumSize(topSize)
|
||||
.create(countMap.entrySet());
|
||||
|
||||
return topQueue.stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
protected abstract void log(Map<String, Long> top, int uniqHosts, long requestsCount);
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.inmemory;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public abstract class KeyBasedIntervalRegistry {
|
||||
|
||||
private final Map<String, IntervalCount> hostCounts = new ConcurrentHashMap<>();
|
||||
private final long intervalDurationMs;
|
||||
private final long ttlMs;
|
||||
private final Set<String> whiteList;
|
||||
private final Set<String> blackList;
|
||||
|
||||
public KeyBasedIntervalRegistry(long intervalDurationMs, long ttlMs, String whiteList, String blackList, String name) {
|
||||
this.intervalDurationMs = intervalDurationMs;
|
||||
this.ttlMs = ttlMs;
|
||||
this.whiteList = Sets.newHashSet(StringUtils.split(whiteList, ','));
|
||||
this.blackList = Sets.newHashSet(StringUtils.split(blackList, ','));
|
||||
validate(name);
|
||||
}
|
||||
|
||||
private void validate(String name) {
|
||||
if (ttlMs < intervalDurationMs) {
|
||||
log.warn("TTL for {} IntervalRegistry [{}] smaller than interval duration [{}]", name, ttlMs, intervalDurationMs);
|
||||
}
|
||||
log.info("Start {} KeyBasedIntervalRegistry with whitelist {}", name, whiteList);
|
||||
log.info("Start {} KeyBasedIntervalRegistry with blacklist {}", name, blackList);
|
||||
}
|
||||
|
||||
public long tick(String clientHostId) {
|
||||
IntervalCount intervalCount = hostCounts.computeIfAbsent(clientHostId, s -> new IntervalCount(intervalDurationMs));
|
||||
long currentCount = intervalCount.resetIfExpiredAndTick();
|
||||
if (whiteList.contains(clientHostId)) {
|
||||
return 0;
|
||||
} else if (blackList.contains(clientHostId)) {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
return currentCount;
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
hostCounts.entrySet().removeIf(entry -> entry.getValue().silenceDuration() > ttlMs);
|
||||
}
|
||||
|
||||
public Map<String, Long> getContent() {
|
||||
return hostCounts.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
interval -> interval.getValue().getCount()));
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.tenant;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.IntervalRegistryCleaner;
|
||||
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "quota.rule.tenant", value = "enabled", havingValue = "true", matchIfMissing = false)
|
||||
public class TenantIntervalRegistryCleaner extends IntervalRegistryCleaner {
|
||||
|
||||
public TenantIntervalRegistryCleaner(TenantMsgsIntervalRegistry intervalRegistry,
|
||||
@Value("${quota.rule.tenant.cleanPeriodMs}") long cleanPeriodMs) {
|
||||
super(intervalRegistry, cleanPeriodMs);
|
||||
}
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.tenant;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.IntervalRegistryLogger;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "quota.rule.tenant", value = "enabled", havingValue = "true", matchIfMissing = false)
|
||||
public class TenantIntervalRegistryLogger extends IntervalRegistryLogger {
|
||||
|
||||
private final long logIntervalMin;
|
||||
|
||||
public TenantIntervalRegistryLogger(@Value("${quota.rule.tenant.log.topSize}") int topSize,
|
||||
@Value("${quota.rule.tenant.log.intervalMin}") long logIntervalMin,
|
||||
TenantMsgsIntervalRegistry intervalRegistry) {
|
||||
super(topSize, logIntervalMin, intervalRegistry);
|
||||
this.logIntervalMin = logIntervalMin;
|
||||
}
|
||||
|
||||
protected void log(Map<String, Long> top, int uniqHosts, long requestsCount) {
|
||||
long rps = requestsCount / TimeUnit.MINUTES.toSeconds(logIntervalMin);
|
||||
StringBuilder builder = new StringBuilder("Tenant Quota Statistic : ");
|
||||
builder.append("uniqTenants : ").append(uniqHosts).append("; ");
|
||||
builder.append("requestsCount : ").append(requestsCount).append("; ");
|
||||
builder.append("RPS : ").append(rps).append(" ");
|
||||
builder.append("top -> ");
|
||||
for (Map.Entry<String, Long> host : top.entrySet()) {
|
||||
builder.append(host.getKey()).append(" : ").append(host.getValue()).append("; ");
|
||||
}
|
||||
|
||||
log.info(builder.toString());
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.tenant;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.KeyBasedIntervalRegistry;
|
||||
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "quota.rule.tenant", value = "enabled", havingValue = "true", matchIfMissing = false)
|
||||
public class TenantMsgsIntervalRegistry extends KeyBasedIntervalRegistry {
|
||||
|
||||
public TenantMsgsIntervalRegistry(@Value("${quota.rule.tenant.intervalMs}") long intervalDurationMs,
|
||||
@Value("${quota.rule.tenant.ttlMs}") long ttlMs,
|
||||
@Value("${quota.rule.tenant.whitelist}") String whiteList,
|
||||
@Value("${quota.rule.tenant.blacklist}") String blackList) {
|
||||
super(intervalDurationMs, ttlMs, whiteList, blackList, "Rule Tenant");
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.tenant;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.quota.AbstractQuotaService;
|
||||
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "quota.rule.tenant", value = "enabled", havingValue = "true", matchIfMissing = false)
|
||||
public class TenantQuotaService extends AbstractQuotaService {
|
||||
|
||||
public TenantQuotaService(TenantMsgsIntervalRegistry requestRegistry, TenantRequestLimitPolicy requestsPolicy,
|
||||
TenantIntervalRegistryCleaner registryCleaner, TenantIntervalRegistryLogger registryLogger,
|
||||
@Value("${quota.rule.tenant.enabled}") boolean enabled) {
|
||||
super(requestRegistry, requestsPolicy, registryCleaner, registryLogger, enabled);
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.tenant;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.transport.quota.RequestLimitPolicy;
|
||||
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "quota.rule.tenant", value = "enabled", havingValue = "true", matchIfMissing = false)
|
||||
public class TenantRequestLimitPolicy extends RequestLimitPolicy {
|
||||
|
||||
public TenantRequestLimitPolicy(@Value("${quota.rule.tenant.limit}") long limit) {
|
||||
super(limit);
|
||||
}
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
public class ClockTest {
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
Clock.reset();
|
||||
}
|
||||
|
||||
@After
|
||||
public void clear() {
|
||||
Clock.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultClockUseSystemTime() {
|
||||
assertFalse(Clock.millis() > System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeCanBeSet() {
|
||||
Clock.setMillis(100L);
|
||||
assertEquals(100L, Clock.millis());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clockCanBeReseted() {
|
||||
Clock.setMillis(100L);
|
||||
assertEquals(100L, Clock.millis());
|
||||
Clock.reset();
|
||||
assertFalse(Clock.millis() > System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeIsShifted() {
|
||||
Clock.setMillis(100L);
|
||||
Clock.shift(50L);
|
||||
assertEquals(150L, Clock.millis());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostRequestLimitPolicy;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
public class HostRequestLimitPolicyTest {
|
||||
|
||||
private HostRequestLimitPolicy limitPolicy = new HostRequestLimitPolicy(10L);
|
||||
|
||||
@Test
|
||||
public void ifCurrentValueLessThenLimitItIsValid() {
|
||||
assertTrue(limitPolicy.isValid(9));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ifCurrentValueEqualsToLimitItIsValid() {
|
||||
assertTrue(limitPolicy.isValid(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ifCurrentValueGreaterThenLimitItIsValid() {
|
||||
assertFalse(limitPolicy.isValid(11));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostIntervalRegistryCleaner;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostIntervalRegistryLogger;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostRequestIntervalRegistry;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostRequestLimitPolicy;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostRequestsQuotaService;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
public class HostRequestsQuotaServiceTest {
|
||||
|
||||
private HostRequestsQuotaService quotaService;
|
||||
|
||||
private HostRequestIntervalRegistry requestRegistry = mock(HostRequestIntervalRegistry.class);
|
||||
private HostRequestLimitPolicy requestsPolicy = mock(HostRequestLimitPolicy.class);
|
||||
private HostIntervalRegistryCleaner registryCleaner = mock(HostIntervalRegistryCleaner.class);
|
||||
private HostIntervalRegistryLogger registryLogger = mock(HostIntervalRegistryLogger.class);
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
quotaService = new HostRequestsQuotaService(requestRegistry, requestsPolicy, registryCleaner, registryLogger, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quotaExceededIfRequestCountBiggerThanAllowed() {
|
||||
when(requestRegistry.tick("key")).thenReturn(10L);
|
||||
when(requestsPolicy.isValid(10L)).thenReturn(false);
|
||||
|
||||
assertTrue(quotaService.isQuotaExceeded("key"));
|
||||
|
||||
verify(requestRegistry).tick("key");
|
||||
verify(requestsPolicy).isValid(10L);
|
||||
verifyNoMoreInteractions(requestRegistry, requestsPolicy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quotaNotExceededIfRequestCountLessThanAllowed() {
|
||||
when(requestRegistry.tick("key")).thenReturn(10L);
|
||||
when(requestsPolicy.isValid(10L)).thenReturn(true);
|
||||
|
||||
assertFalse(quotaService.isQuotaExceeded("key"));
|
||||
|
||||
verify(requestRegistry).tick("key");
|
||||
verify(requestsPolicy).isValid(10L);
|
||||
verifyNoMoreInteractions(requestRegistry, requestsPolicy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceCanBeDisabled() {
|
||||
quotaService = new HostRequestsQuotaService(requestRegistry, requestsPolicy, registryCleaner, registryLogger, false);
|
||||
assertFalse(quotaService.isQuotaExceeded("key"));
|
||||
verifyNoMoreInteractions(requestRegistry, requestsPolicy);
|
||||
}
|
||||
}
|
||||
@ -1,83 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.inmemory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostRequestIntervalRegistry;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
public class HostRequestIntervalRegistryTest {
|
||||
|
||||
private HostRequestIntervalRegistry registry;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
registry = new HostRequestIntervalRegistry(10000L, 100L,"g1,g2", "b1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newHostCreateNewInterval() {
|
||||
assertEquals(1L, registry.tick("host1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void existingHostUpdated() {
|
||||
registry.tick("aaa");
|
||||
assertEquals(1L, registry.tick("bbb"));
|
||||
assertEquals(2L, registry.tick("aaa"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expiredIntervalsCleaned() throws InterruptedException {
|
||||
registry.tick("aaa");
|
||||
Thread.sleep(150L);
|
||||
registry.tick("bbb");
|
||||
registry.clean();
|
||||
assertEquals(1L, registry.tick("aaa"));
|
||||
assertEquals(2L, registry.tick("bbb"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void domainFromWhitelistNotCounted(){
|
||||
assertEquals(0L, registry.tick("g1"));
|
||||
assertEquals(0L, registry.tick("g1"));
|
||||
assertEquals(0L, registry.tick("g2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void domainFromBlackListReturnMaxValue(){
|
||||
assertEquals(Long.MAX_VALUE, registry.tick("b1"));
|
||||
assertEquals(Long.MAX_VALUE, registry.tick("b1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyWhitelistParsedOk(){
|
||||
registry = new HostRequestIntervalRegistry(10000L, 100L,"", "b1");
|
||||
assertEquals(1L, registry.tick("aaa"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyBlacklistParsedOk(){
|
||||
registry = new HostRequestIntervalRegistry(10000L, 100L,"", "");
|
||||
assertEquals(1L, registry.tick("aaa"));
|
||||
}
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.inmemory;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.transport.quota.Clock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
public class IntervalCountTest {
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
Clock.setMillis(1000L);
|
||||
}
|
||||
|
||||
@After
|
||||
public void clear() {
|
||||
Clock.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ticksInSameIntervalAreSummed() {
|
||||
IntervalCount intervalCount = new IntervalCount(100L);
|
||||
assertEquals(1L, intervalCount.resetIfExpiredAndTick());
|
||||
Clock.shift(100);
|
||||
assertEquals(2L, intervalCount.resetIfExpiredAndTick());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oldDataCleanedWhenIntervalExpired() {
|
||||
IntervalCount intervalCount = new IntervalCount(100L);
|
||||
assertEquals(1L, intervalCount.resetIfExpiredAndTick());
|
||||
Clock.shift(101);
|
||||
assertEquals(1L, intervalCount.resetIfExpiredAndTick());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void silenceDurationCalculatedFromLastTick() {
|
||||
IntervalCount intervalCount = new IntervalCount(100L);
|
||||
assertEquals(1L, intervalCount.resetIfExpiredAndTick());
|
||||
Clock.shift(10L);
|
||||
assertEquals(10L, intervalCount.silenceDuration());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2018 The Thingsboard Authors
|
||||
*
|
||||
* Licensed 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 org.thingsboard.server.common.transport.quota.inmemory;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostIntervalRegistryLogger;
|
||||
import org.thingsboard.server.common.transport.quota.host.HostRequestIntervalRegistry;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Vitaliy Paromskiy
|
||||
* @version 1.0
|
||||
*/
|
||||
public class IntervalRegistryLoggerTest {
|
||||
|
||||
private IntervalRegistryLogger logger;
|
||||
|
||||
private HostRequestIntervalRegistry requestRegistry = mock(HostRequestIntervalRegistry.class);
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
logger = new HostIntervalRegistryLogger(3, 10, requestRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onlyMaxHostsCollected() {
|
||||
Map<String, Long> map = ImmutableMap.of("a", 8L, "b", 3L, "c", 1L, "d", 3L);
|
||||
Map<String, Long> actual = logger.getTopElements(map);
|
||||
Map<String, Long> expected = ImmutableMap.of("a", 8L, "b", 3L, "d", 3L);
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyMapProcessedCorrectly() {
|
||||
Map<String, Long> map = Collections.emptyMap();
|
||||
Map<String, Long> actual = logger.getTopElements(map);
|
||||
Map<String, Long> expected = Collections.emptyMap();
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
}
|
||||
@ -28,27 +28,6 @@ transport:
|
||||
tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}"
|
||||
device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}"
|
||||
|
||||
#Quota parameters
|
||||
quota:
|
||||
host:
|
||||
# Max allowed number of API requests in interval for single host
|
||||
limit: "${QUOTA_HOST_LIMIT:10000}"
|
||||
# Interval duration
|
||||
intervalMs: "${QUOTA_HOST_INTERVAL_MS:60000}"
|
||||
# Maximum silence duration for host after which Host removed from QuotaService. Must be bigger than intervalMs
|
||||
ttlMs: "${QUOTA_HOST_TTL_MS:60000}"
|
||||
# Interval for scheduled task that cleans expired records. TTL is used for expiring
|
||||
cleanPeriodMs: "${QUOTA_HOST_CLEAN_PERIOD_MS:300000}"
|
||||
# Enable Host API Limits
|
||||
enabled: "${QUOTA_HOST_ENABLED:true}"
|
||||
# Array of whitelist hosts
|
||||
whitelist: "${QUOTA_HOST_WHITELIST:localhost,127.0.0.1}"
|
||||
# Array of blacklist hosts
|
||||
blacklist: "${QUOTA_HOST_BLACKLIST:}"
|
||||
log:
|
||||
topSize: 10
|
||||
intervalMin: 2
|
||||
|
||||
kafka:
|
||||
enabled: true
|
||||
bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}"
|
||||
|
||||
@ -29,27 +29,6 @@ transport:
|
||||
tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}"
|
||||
device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}"
|
||||
|
||||
#Quota parameters
|
||||
quota:
|
||||
host:
|
||||
# Max allowed number of API requests in interval for single host
|
||||
limit: "${QUOTA_HOST_LIMIT:10000}"
|
||||
# Interval duration
|
||||
intervalMs: "${QUOTA_HOST_INTERVAL_MS:60000}"
|
||||
# Maximum silence duration for host after which Host removed from QuotaService. Must be bigger than intervalMs
|
||||
ttlMs: "${QUOTA_HOST_TTL_MS:60000}"
|
||||
# Interval for scheduled task that cleans expired records. TTL is used for expiring
|
||||
cleanPeriodMs: "${QUOTA_HOST_CLEAN_PERIOD_MS:300000}"
|
||||
# Enable Host API Limits
|
||||
enabled: "${QUOTA_HOST_ENABLED:true}"
|
||||
# Array of whitelist hosts
|
||||
whitelist: "${QUOTA_HOST_WHITELIST:localhost,127.0.0.1}"
|
||||
# Array of blacklist hosts
|
||||
blacklist: "${QUOTA_HOST_BLACKLIST:}"
|
||||
log:
|
||||
topSize: 10
|
||||
intervalMin: 2
|
||||
|
||||
kafka:
|
||||
enabled: true
|
||||
bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}"
|
||||
|
||||
@ -51,27 +51,6 @@ transport:
|
||||
tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}"
|
||||
device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}"
|
||||
|
||||
#Quota parameters
|
||||
quota:
|
||||
host:
|
||||
# Max allowed number of API requests in interval for single host
|
||||
limit: "${QUOTA_HOST_LIMIT:10000}"
|
||||
# Interval duration
|
||||
intervalMs: "${QUOTA_HOST_INTERVAL_MS:60000}"
|
||||
# Maximum silence duration for host after which Host removed from QuotaService. Must be bigger than intervalMs
|
||||
ttlMs: "${QUOTA_HOST_TTL_MS:60000}"
|
||||
# Interval for scheduled task that cleans expired records. TTL is used for expiring
|
||||
cleanPeriodMs: "${QUOTA_HOST_CLEAN_PERIOD_MS:300000}"
|
||||
# Enable Host API Limits
|
||||
enabled: "${QUOTA_HOST_ENABLED:true}"
|
||||
# Array of whitelist hosts
|
||||
whitelist: "${QUOTA_HOST_WHITELIST:localhost,127.0.0.1}"
|
||||
# Array of blacklist hosts
|
||||
blacklist: "${QUOTA_HOST_BLACKLIST:}"
|
||||
log:
|
||||
topSize: 10
|
||||
intervalMin: 2
|
||||
|
||||
kafka:
|
||||
enabled: true
|
||||
bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user