24 changed files with 312 additions and 123 deletions
@ -1,47 +1,23 @@ |
|||||
/** |
|
||||
* 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; |
package org.thingsboard.server.common.transport.quota; |
||||
|
|
||||
import lombok.extern.slf4j.Slf4j; |
|
||||
import org.springframework.beans.factory.annotation.Value; |
|
||||
import org.springframework.stereotype.Service; |
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.HostRequestIntervalRegistry; |
|
||||
import org.thingsboard.server.common.transport.quota.inmemory.IntervalRegistryCleaner; |
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.IntervalRegistryLogger; |
||||
|
import org.thingsboard.server.common.transport.quota.inmemory.KeyBasedIntervalRegistry; |
||||
|
|
||||
import javax.annotation.PostConstruct; |
import javax.annotation.PostConstruct; |
||||
import javax.annotation.PreDestroy; |
import javax.annotation.PreDestroy; |
||||
|
|
||||
/** |
public class AbstractQuotaService implements QuotaService { |
||||
* @author Vitaliy Paromskiy |
|
||||
* @version 1.0 |
|
||||
*/ |
|
||||
@Service |
|
||||
@Slf4j |
|
||||
public class HostRequestsQuotaService implements QuotaService { |
|
||||
|
|
||||
private final HostRequestIntervalRegistry requestRegistry; |
private final KeyBasedIntervalRegistry requestRegistry; |
||||
private final HostRequestLimitPolicy requestsPolicy; |
private final RequestLimitPolicy requestsPolicy; |
||||
private final IntervalRegistryCleaner registryCleaner; |
private final IntervalRegistryCleaner registryCleaner; |
||||
private final IntervalRegistryLogger registryLogger; |
private final IntervalRegistryLogger registryLogger; |
||||
private final boolean enabled; |
private final boolean enabled; |
||||
|
|
||||
public HostRequestsQuotaService(HostRequestIntervalRegistry requestRegistry, HostRequestLimitPolicy requestsPolicy, |
public AbstractQuotaService(KeyBasedIntervalRegistry requestRegistry, RequestLimitPolicy requestsPolicy, |
||||
IntervalRegistryCleaner registryCleaner, IntervalRegistryLogger registryLogger, |
IntervalRegistryCleaner registryCleaner, IntervalRegistryLogger registryLogger, |
||||
@Value("${quota.host.enabled}") boolean enabled) { |
boolean enabled) { |
||||
this.requestRegistry = requestRegistry; |
this.requestRegistry = requestRegistry; |
||||
this.requestsPolicy = requestsPolicy; |
this.requestsPolicy = requestsPolicy; |
||||
this.registryCleaner = registryCleaner; |
this.registryCleaner = registryCleaner; |
||||
@ -0,0 +1,15 @@ |
|||||
|
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; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
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()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* <p> |
||||
|
* 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 |
||||
|
* <p> |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* <p> |
||||
|
* 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,38 +1,33 @@ |
|||||
/** |
/** |
||||
* Copyright © 2016-2018 The Thingsboard Authors |
* Copyright © 2016-2018 The Thingsboard Authors |
||||
* |
* <p> |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
* You may obtain a copy of the License at |
||||
* |
* <p> |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
* <p> |
||||
* Unless required by applicable law or agreed to in writing, software |
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
* limitations under the License. |
||||
*/ |
*/ |
||||
package org.thingsboard.server.common.transport.quota; |
package org.thingsboard.server.common.transport.quota.host; |
||||
|
|
||||
import org.springframework.beans.factory.annotation.Value; |
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.stereotype.Component; |
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.transport.quota.RequestLimitPolicy; |
||||
|
|
||||
/** |
/** |
||||
* @author Vitaliy Paromskiy |
* @author Vitaliy Paromskiy |
||||
* @version 1.0 |
* @version 1.0 |
||||
*/ |
*/ |
||||
@Component |
@Component |
||||
public class HostRequestLimitPolicy { |
public class HostRequestLimitPolicy extends RequestLimitPolicy { |
||||
|
|
||||
private final long limit; |
|
||||
|
|
||||
public HostRequestLimitPolicy(@Value("${quota.host.limit}") long limit) { |
public HostRequestLimitPolicy(@Value("${quota.host.limit}") long limit) { |
||||
this.limit = limit; |
super(limit); |
||||
} |
|
||||
|
|
||||
public boolean isValid(long currentValue) { |
|
||||
return currentValue <= limit; |
|
||||
} |
} |
||||
|
|
||||
} |
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2018 The Thingsboard Authors |
||||
|
* <p> |
||||
|
* 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 |
||||
|
* <p> |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* <p> |
||||
|
* 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); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
package org.thingsboard.server.common.transport.quota.tenant; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.transport.quota.inmemory.IntervalRegistryCleaner; |
||||
|
|
||||
|
@Component |
||||
|
public class TenantIntervalRegistryCleaner extends IntervalRegistryCleaner { |
||||
|
|
||||
|
public TenantIntervalRegistryCleaner(TenantMsgsIntervalRegistry intervalRegistry, |
||||
|
@Value("${quota.rule.tenant.cleanPeriodMs}") long cleanPeriodMs) { |
||||
|
super(intervalRegistry, cleanPeriodMs); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
package org.thingsboard.server.common.transport.quota.tenant; |
||||
|
|
||||
|
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; |
||||
|
|
||||
|
@Slf4j |
||||
|
@Component |
||||
|
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()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
package org.thingsboard.server.common.transport.quota.tenant; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.transport.quota.inmemory.KeyBasedIntervalRegistry; |
||||
|
|
||||
|
@Component |
||||
|
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"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
package org.thingsboard.server.common.transport.quota.tenant; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.transport.quota.AbstractQuotaService; |
||||
|
|
||||
|
@Component |
||||
|
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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
package org.thingsboard.server.common.transport.quota.tenant; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.common.transport.quota.RequestLimitPolicy; |
||||
|
|
||||
|
@Component |
||||
|
public class TenantRequestLimitPolicy extends RequestLimitPolicy { |
||||
|
|
||||
|
public TenantRequestLimitPolicy(@Value("${quota.rule.tenant.limit}") long limit) { |
||||
|
super(limit); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue