diff --git a/NOTICE b/NOTICE index 525e9cd04..cdd632250 100644 --- a/NOTICE +++ b/NOTICE @@ -87,6 +87,19 @@ joylive-flowcontrol-resilience4j io.github.resilience4j -> com.jd.live.agent.shaded.io.github.resilience4j io.vavr -> com.jd.live.agent.shaded.io.vavr org.slf4j -> com.jd.live.agent.shaded.org.slf4j depend on joylive-logger-slf4j +joylive-flowcontrol-redisson + org.redisson -> com.jd.live.agent.shaded.org.redisson + io.netty -> com.jd.live.agent.shaded.io.netty + javax.cache -> com.jd.live.agent.shaded.javax.cache + rx -> com.jd.live.agent.shaded.rx + reactor -> com.jd.live.agent.shaded.reactor + org.reactivestreams -> com.jd.live.agent.shaded.org.reactivestreams + org.objenesis -> com.jd.live.agent.shaded.org.objenesis + com.esotericsoftware -> com.jd.live.agent.shaded.com.esotericsoftware + com.fasterxml -> com.jd.live.agent.shaded.com.fasterxml depend on joylive-parser-jackson + org.yaml -> com.jd.live.agent.shaded.org.yaml depend on joylive-parser-jackson + net.bytebuddy -> com.jd.live.agent.shaded.net.bytebuddy depend on joylive-bytekit-bytebuddy + org.slf4j -> com.jd.live.agent.shaded.org.slf4j depend on joylive-logger-slf4j joylive-service-nacos com.alibaba.nacos -> com.jd.live.agent.shaded.com.alibaba.nacos org.codehaus -> com.jd.live.agent.shaded.org.codehaus depend on joylive-event-opentelemetry diff --git a/joylive-bom/pom.xml b/joylive-bom/pom.xml index 8a8db7cbe..b4f4e01bd 100644 --- a/joylive-bom/pom.xml +++ b/joylive-bom/pom.xml @@ -168,6 +168,11 @@ joylive-flowcontrol-resilience4j ${revision} + + com.jd.live + joylive-flowcontrol-redisson + ${revision} + com.jd.live joylive-classloader-springboot2 diff --git a/joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/AbstractRateLimiterFactory.java b/joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/AbstractRateLimiterFactory.java index ebb369007..ac71f3372 100644 --- a/joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/AbstractRateLimiterFactory.java +++ b/joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/AbstractRateLimiterFactory.java @@ -21,6 +21,7 @@ import com.jd.live.agent.governance.policy.service.limit.RateLimitPolicy; import com.jd.live.agent.governance.policy.service.limit.SlidingWindow; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -99,19 +100,20 @@ private void addRecycler() { */ private void recycle() { long expireTime = governanceConfig.getServiceConfig().getRateLimiter().getExpireTime(); - for (Map.Entry> entry : limiters.entrySet()) { - AtomicReference reference = entry.getValue(); - RateLimiter limiter = reference.get(); - if (limiter != null && (System.currentTimeMillis() - limiter.getLastAcquireTime()) > expireTime) { - reference = limiters.remove(entry.getKey()); - if (reference != null) { - limiter = reference.get(); - if (limiter != null && (System.currentTimeMillis() - limiter.getLastAcquireTime()) <= expireTime) { - limiters.putIfAbsent(entry.getKey(), reference); + List recycles = new ArrayList<>(); + limiters.forEach((key, reference) -> { + limiters.compute(key, (k, ref) -> { + if (ref != null) { + RateLimiter limiter = ref.get(); + if (limiter != null && limiter.isExpired(expireTime)) { + recycles.add(limiter); + return null; } } - } - } + return ref; + }); + }); + recycles.forEach(RateLimiter::recycle); } /** diff --git a/joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/RateLimiter.java b/joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/RateLimiter.java index 281628630..a87bb495b 100644 --- a/joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/RateLimiter.java +++ b/joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/RateLimiter.java @@ -77,4 +77,12 @@ default boolean acquire(long timeout, TimeUnit timeUnit) { * @return policy */ RateLimitPolicy getPolicy(); + + default boolean isExpired(long expireTime) { + return System.currentTimeMillis() - getLastAcquireTime() > expireTime; + } + + default void recycle() { + + } } diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/pom.xml b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/pom.xml new file mode 100644 index 000000000..a5c96bc9b --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/pom.xml @@ -0,0 +1,116 @@ + + + 4.0.0 + + com.jd.live + joylive-flowcontrol + ${revision} + + + joylive-flowcontrol-redisson + + + 3.41.0 + + + + + org.redisson + redisson + ${redisson.version} + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + + + org.redisson:* + io.netty:* + javax.cache:* + org.objenesis:* + com.esotericsoftware:* + io.projectreactor:reactor-core + org.reactivestreams:reactive-stream + io.reactivex.rxjava3:rxjava + org.jodd:jodd-util + + + + + + + + + false + + + + + org.redisson + com.jd.live.agent.shaded.org.redisson + + + io.netty + com.jd.live.agent.shaded.io.netty + + + javax.cache + com.jd.live.agent.shaded.javax.cache + + + rx + com.jd.live.agent.shaded.rx + + + reactor + com.jd.live.agent.shaded.reactor + + + org.reactivestreams + com.jd.live.agent.shaded.org.reactivestreams + + + org.objenesis + com.jd.live.agent.shaded.org.objenesis + + + com.esotericsoftware + com.jd.live.agent.shaded.com.esotericsoftware + + + com.fasterxml + com.jd.live.agent.shaded.com.fasterxml + + + org.yaml + com.jd.live.agent.shaded.org.yaml + + + net.bytebuddy + com.jd.live.agent.shaded.net.bytebuddy + + + org.slf4j + com.jd.live.agent.shaded.org.slf4j + + + + + + + + + \ No newline at end of file diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/RedissonRateLimiter.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/RedissonRateLimiter.java new file mode 100644 index 000000000..9176362c4 --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/RedissonRateLimiter.java @@ -0,0 +1,77 @@ +/* + * Copyright © ${year} ${owner} (${email}) + * + * 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 com.jd.live.agent.implement.flowcontrol.ratelimit.redisson; + +import com.jd.live.agent.bootstrap.logger.Logger; +import com.jd.live.agent.bootstrap.logger.LoggerFactory; +import com.jd.live.agent.governance.invoke.ratelimit.AbstractRateLimiter; +import com.jd.live.agent.governance.policy.service.limit.RateLimitPolicy; +import com.jd.live.agent.governance.policy.service.limit.SlidingWindow; +import com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client.RedisClient; +import com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client.RedisClientManager; +import com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client.RedisConfig; +import org.redisson.api.RRateLimiter; +import org.redisson.api.RateType; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; + +/** + * RedissonRateLimiter + * + * @since 1.6.0 + */ +public class RedissonRateLimiter extends AbstractRateLimiter { + + private static final Logger logger = LoggerFactory.getLogger(RedissonRateLimiter.class); + + private final RedisClient client; + + private final RRateLimiter limiter; + + public RedissonRateLimiter(RedisClientManager manager, RateLimitPolicy policy, SlidingWindow window) { + this(manager, policy, window, policy.getName()); + } + + public RedissonRateLimiter(RedisClientManager manager, RateLimitPolicy policy, SlidingWindow window, String name) { + super(policy, TimeUnit.MILLISECONDS); + this.client = manager.getOrCreateClient(new RedisConfig(policy.getId(), option)); + this.limiter = client == null ? null : client.getRateLimiter("LiveAgent-limiter-" + policy.getId()); + if (limiter != null) { + limiter.trySetRate(RateType.OVERALL, window.getThreshold(), Duration.ofMillis(window.getTimeWindowInMs())); + } + } + + @Override + protected boolean doAcquire(int permits, long timeout, TimeUnit timeUnit) { + if (client != null) { + client.setLastAccessTime(System.currentTimeMillis()); + } + try { + return limiter == null || limiter.tryAcquire(permits, Duration.ofNanos(timeUnit.toNanos(timeout))); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + return true; + } + } + + @Override + public void recycle() { + if (client != null) { + client.decReference(); + } + } +} diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/RedissonRateLimiterFactory.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/RedissonRateLimiterFactory.java new file mode 100644 index 000000000..0cac387fb --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/RedissonRateLimiterFactory.java @@ -0,0 +1,69 @@ +/* + * Copyright © ${year} ${owner} (${email}) + * + * 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 com.jd.live.agent.implement.flowcontrol.ratelimit.redisson; + +import com.jd.live.agent.core.extension.annotation.Extension; +import com.jd.live.agent.core.inject.annotation.Inject; +import com.jd.live.agent.core.inject.annotation.Injectable; +import com.jd.live.agent.core.util.time.Timer; +import com.jd.live.agent.governance.invoke.ratelimit.AbstractRateLimiterFactory; +import com.jd.live.agent.governance.invoke.ratelimit.RateLimiter; +import com.jd.live.agent.governance.policy.service.limit.RateLimitPolicy; +import com.jd.live.agent.governance.policy.service.limit.SlidingWindow; +import com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client.RedisClientManager; + +import java.util.List; + +/** + * RedissonRateLimiterFactory + * + * @since 1.6.0 + */ +@Injectable +@Extension(value = "RedissonCluster") +public class RedissonRateLimiterFactory extends AbstractRateLimiterFactory { + + @Inject(Timer.COMPONENT_TIMER) + private Timer timer; + + private transient volatile RedisClientManager manager; + + @Override + protected RateLimiter create(RateLimitPolicy policy) { + List windows = policy.getSlidingWindows(); + RedisClientManager manager = getManager(); + return windows.size() == 1 + ? new RedissonRateLimiter(manager, policy, windows.get(0)) + : new RedissonRateLimiterGroup(manager, policy); + } + + /** + * Retrieves the singleton instance of {@link RedisClientManager}. + * + * @return The singleton instance of {@link RedisClientManager}. + */ + private RedisClientManager getManager() { + if (manager == null) { + synchronized (this) { + if (manager == null) { + manager = new RedisClientManager(timer); + } + } + } + return manager; + } + +} diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/RedissonRateLimiterGroup.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/RedissonRateLimiterGroup.java new file mode 100644 index 000000000..d8aa46129 --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/RedissonRateLimiterGroup.java @@ -0,0 +1,42 @@ +/* + * Copyright © ${year} ${owner} (${email}) + * + * 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 com.jd.live.agent.implement.flowcontrol.ratelimit.redisson; + +import com.jd.live.agent.governance.invoke.ratelimit.AbstractRateLimiterGroup; +import com.jd.live.agent.governance.invoke.ratelimit.RateLimiter; +import com.jd.live.agent.governance.policy.service.limit.RateLimitPolicy; +import com.jd.live.agent.governance.policy.service.limit.SlidingWindow; +import com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client.RedisClientManager; + +/** + * RedissonRateLimiterGroup + * + * @since 1.6.0 + */ +public class RedissonRateLimiterGroup extends AbstractRateLimiterGroup { + + private final RedisClientManager manager; + + public RedissonRateLimiterGroup(RedisClientManager manager, RateLimitPolicy policy) { + super(policy); + this.manager = manager; + } + + @Override + protected RateLimiter create(SlidingWindow window, String name) { + return new RedissonRateLimiter(manager, policy, window, name); + } +} diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisClient.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisClient.java new file mode 100644 index 000000000..22bd38f55 --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisClient.java @@ -0,0 +1,144 @@ +/* + * Copyright © ${year} ${owner} (${email}) + * + * 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 com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client; + +import com.jd.live.agent.bootstrap.logger.Logger; +import com.jd.live.agent.bootstrap.logger.LoggerFactory; +import com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.RedissonRateLimiter; +import org.redisson.Redisson; +import org.redisson.api.RRateLimiter; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +/** + * Represents a Redis client managed by {@link RedisClientManager}. + */ +public class RedisClient { + + private static final Logger logger = LoggerFactory.getLogger(RedissonRateLimiter.class); + + private final RedisConfig config; + + private final Consumer consumer; + + private final RedissonClient delegate; + + private long lastAccessTime; + + private final AtomicLong counter = new AtomicLong(0); + + public RedisClient(RedisConfig config, Consumer consumer) { + this.config = config; + this.consumer = consumer; + this.delegate = createClient(); + } + + public long getId() { + return config.getId(); + } + + /** + * Retrieves a rate limiter for the specified key. + * + * @param key the key for the rate limiter + * @return the rate limiter for the specified key, or null if the delegate is not initialized + */ + public RRateLimiter getRateLimiter(String key) { + return delegate == null ? null : delegate.getRateLimiter(key); + } + + public long getLastAccessTime() { + return lastAccessTime; + } + + public void setLastAccessTime(long lastAccessTime) { + this.lastAccessTime = lastAccessTime; + } + + /** + * Checks if the Redis client has expired based on the specified timeout. + * + * @param timeout the timeout duration in milliseconds + * @return true if the client has expired, false otherwise + */ + public boolean isExpired(long timeout) { + return System.currentTimeMillis() - lastAccessTime >= timeout; + } + + /** + * Increments the reference count of the Redis client. + */ + public void incReference() { + counter.incrementAndGet(); + } + + /** + * Decrements the reference count of the Redis client. + * If the reference count reaches zero, the client is removed by the consumer. + */ + public void decReference() { + if (counter.decrementAndGet() == 0) { + consumer.accept(this); + } + } + + /** + * Returns the current reference count of the Redis client. + * + * @return the reference count + */ + public int getReference() { + return (int) counter.get(); + } + + protected RedisConfig getConfig() { + return config; + } + + /** + * Shuts down the Redis client. + * This method should be called when the client is no longer needed to release resources. + */ + protected void shutdown() { + if (delegate != null) { + delegate.shutdown(); + } + } + + /** + * Creates and returns a RedissonClient instance based on the provided configuration. + * + * @return A RedissonClient instance if the configuration is valid, otherwise null. + */ + private RedissonClient createClient() { + RedissonClient result = null; + if (config.validate()) { + try { + Config cfg = new Config(); + RedisType redisType = RedisType.parse(config.type); + redisType.configure(cfg, config); + result = Redisson.create(cfg); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + } + return result; + } + +} diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisClientManager.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisClientManager.java new file mode 100644 index 000000000..b1a1f1a64 --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisClientManager.java @@ -0,0 +1,84 @@ +/* + * Copyright © ${year} ${owner} (${email}) + * + * 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 com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client; + +import com.jd.live.agent.core.util.time.Timer; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Manager class for Redis clients. + * This class manages the creation, retrieval, and recycling of Redis clients based on their configurations. + */ +public class RedisClientManager { + + private final Timer timer; + + private final Map clients = new ConcurrentHashMap<>(); + + public RedisClientManager(Timer timer) { + this.timer = timer; + } + + /** + * Retrieves an existing Redis client for the given configuration or creates a new one if it does not exist. + * + * @param config the {@link RedisConfig} for the client + * @return the Redis client for the given configuration + */ + public RedisClient getOrCreateClient(RedisConfig config) { + RedisClient client = clients.computeIfAbsent(config, c -> new RedisClient(c, this::removeClient)); + client.incReference(); + client.setLastAccessTime(System.currentTimeMillis()); + return client; + } + + /** + * Removes a Redis client if its reference count is zero and it has expired. + * + * @param client the Redis client to be removed + */ + private void removeClient(RedisClient client) { + RedisClient newClient = clients.remove(client.getConfig()); + if (newClient != null) { + if (newClient == client && newClient.getReference() == 0) { + addTask(newClient); + } else { + client = clients.putIfAbsent(newClient.getConfig(), newClient); + if (client != null) { + addTask(newClient); + } + } + } + } + + /** + * Adds a task to the timer to recycle the Redis client if its reference count is zero and it has expired. + * + * @param client the Redis client to be recycled + */ + private void addTask(RedisClient client) { + timer.add("recycle-redis-client-" + client.getId(), 5000, () -> { + if (client.getReference() == 0 && client.isExpired(10000)) { + client.shutdown(); + } else { + addTask(client); + } + }); + } + +} diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisConfig.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisConfig.java new file mode 100644 index 000000000..03f797be5 --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisConfig.java @@ -0,0 +1,173 @@ +/* + * Copyright © ${year} ${owner} (${email}) + * + * 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 com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client; + +import com.jd.live.agent.bootstrap.logger.Logger; +import com.jd.live.agent.bootstrap.logger.LoggerFactory; +import com.jd.live.agent.core.util.option.Option; + +import java.util.Objects; + +/** + * Configuration class for Redis settings. + */ +public class RedisConfig { + + private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class); + + private static final String KEY_TYPE = "type"; + private static final String KEY_ADDRESS = "address"; + private static final String KEY_USER = "user"; + private static final String KEY_PASSWORD = "password"; + private static final String KEY_DATABASE = "database"; + private static final String KEY_TIMEOUT = "timeout"; + private static final String KEY_SENTINEL_USER = "sentinelUser"; + private static final String KEY_SENTINEL_PASSWORD = "sentinelPassword"; + private static final String KEY_RETRY_ATTEMPTS = "retryAttempts"; + private static final String KEY_RETRY_INTERVAL = "retryInterval"; + private static final String KEY_CONNECT_TIMEOUT = "connectTimeout"; + private static final String KEY_IDLE_CONNECTION_TIMEOUT = "idleConnectionTimeout"; + private static final String KEY_PING_CONNECTION_INTERVAL = "pingConnectionInterval"; + private static final String KEY_CONNECTION_POOL_SIZE = "connectionPoolSize"; + private static final String KEY_CONNECTION_MINIMUM_IDLE_SIZE = "connectionMinimumIdleSize"; + private static final String KEY_MASTER_CONNECTION_POOL_SIZE = "masterConnectionPoolSize"; + private static final String KEY_SLAVE_CONNECTION_POOL_SIZE = "slaveConnectionPoolSize"; + private static final String KEY_MASTER_CONNECTION_MINIMUM_IDLE_SIZE = "masterConnectionMinimumIdleSize"; + private static final String KEY_SLAVE_CONNECTION_MINIMUM_IDLE_SIZE = "slaveConnectionMinimumIdleSize"; + + protected final long id; + + protected final String type; + + protected final String address; + + protected final String user; + + protected final String password; + + protected final int database; + + protected final int timeout; + + protected final int connectionPoolSize; + + protected final int connectionMinimumIdleSize; + + protected final int masterConnectionPoolSize; + + protected final int masterConnectionMinimumIdleSize; + + protected final int slaveConnectionPoolSize; + + protected final int slaveConnectionMinimumIdleSize; + + protected final int connectTimeout; + + protected final int idleConnectionTimeout; + + protected final int pingConnectionInterval; + + protected final boolean keepAlive; + + protected final int retryAttempts; + + protected final int retryInterval; + + protected final String sentinelUser; + + protected final String sentinelPassword; + + public RedisConfig(long id, Option option) { + this.id = id; + type = option.getString(KEY_TYPE); + address = option.getString(KEY_ADDRESS); + user = option.getString(KEY_USER); + password = option.getString(KEY_PASSWORD); + database = option.getNatural(KEY_DATABASE, 0); + sentinelUser = option.getString(KEY_SENTINEL_USER); + sentinelPassword = option.getString(KEY_SENTINEL_PASSWORD); + timeout = option.getPositive(KEY_TIMEOUT, 5000); + keepAlive = option.getBoolean(KEY_RETRY_ATTEMPTS, false); + connectTimeout = option.getPositive(KEY_CONNECT_TIMEOUT, 10000); + idleConnectionTimeout = option.getPositive(KEY_IDLE_CONNECTION_TIMEOUT, 10000); + pingConnectionInterval = option.getPositive(KEY_PING_CONNECTION_INTERVAL, 30000); + retryAttempts = option.getPositive(KEY_RETRY_ATTEMPTS, 3); + retryInterval = option.getPositive(KEY_RETRY_INTERVAL, 1500); + connectionPoolSize = option.getPositive(KEY_CONNECTION_POOL_SIZE, 64); + connectionMinimumIdleSize = option.getPositive(KEY_CONNECTION_MINIMUM_IDLE_SIZE, 24); + masterConnectionPoolSize = option.getPositive(KEY_MASTER_CONNECTION_POOL_SIZE, 64); + masterConnectionMinimumIdleSize = option.getPositive(KEY_MASTER_CONNECTION_MINIMUM_IDLE_SIZE, 24); + slaveConnectionPoolSize = option.getPositive(KEY_SLAVE_CONNECTION_POOL_SIZE, 64); + slaveConnectionMinimumIdleSize = option.getPositive(KEY_SLAVE_CONNECTION_MINIMUM_IDLE_SIZE, 24); + } + + public long getId() { + return id; + } + + /** + * Validates the Redis configuration. + * This method checks if the address is not null or empty. + * + * @return true if the address is valid, false otherwise + */ + public boolean validate() { + if (address == null || address.isEmpty()) { + logger.error("redisson address is empty for rate limit policy " + id); + return false; + } + return true; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof RedisConfig)) return false; + RedisConfig that = (RedisConfig) o; + return id == that.id + && database == that.database + && timeout == that.timeout + && connectionPoolSize == that.connectionPoolSize + && connectionMinimumIdleSize == that.connectionMinimumIdleSize + && masterConnectionPoolSize == that.masterConnectionPoolSize + && masterConnectionMinimumIdleSize == that.masterConnectionMinimumIdleSize + && slaveConnectionPoolSize == that.slaveConnectionPoolSize + && slaveConnectionMinimumIdleSize == that.slaveConnectionMinimumIdleSize + && connectTimeout == that.connectTimeout + && idleConnectionTimeout == that.idleConnectionTimeout + && pingConnectionInterval == that.pingConnectionInterval + && keepAlive == that.keepAlive + && retryAttempts == that.retryAttempts + && retryInterval == that.retryInterval + && Objects.equals(type, that.type) + && Objects.equals(address, that.address) + && Objects.equals(user, that.user) + && Objects.equals(password, that.password) + && Objects.equals(sentinelUser, that.sentinelUser) + && Objects.equals(sentinelPassword, that.sentinelPassword); + } + + @Override + public int hashCode() { + return Objects.hash(id, type, address, user, password, database, timeout, + connectionPoolSize, connectionMinimumIdleSize, + masterConnectionPoolSize, masterConnectionMinimumIdleSize, + slaveConnectionPoolSize, slaveConnectionMinimumIdleSize, + connectTimeout, idleConnectionTimeout, pingConnectionInterval, keepAlive, + retryAttempts, retryInterval, sentinelUser, sentinelPassword); + } + + +} diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisConfigurator.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisConfigurator.java new file mode 100644 index 000000000..e32eb72b8 --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisConfigurator.java @@ -0,0 +1,199 @@ +/* + * Copyright © ${year} ${owner} (${email}) + * + * 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 com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client; + +import org.redisson.config.*; + +import java.util.List; + +import static com.jd.live.agent.core.util.StringUtils.split; +import static com.jd.live.agent.core.util.StringUtils.splitList; + +public interface RedisConfigurator { + + String SCHEMA_REDISS = "rediss://"; + + String SCHEMA_REDIS = "redis://"; + + /** + * Configures the given configuration object using settings from the provided {@link RedisConfig}. + * + * @param config the configuration object to be configured + * @param redisConfig the {@link RedisConfig} object containing the settings + */ + void configure(T config, RedisConfig redisConfig); + + /** + * Abstract base class for configuring Redis settings. + * + * @param the type of the configuration object, extending {@link BaseConfig} + */ + abstract class BaseConfigurator> implements RedisConfigurator { + + @Override + public void configure(T config, RedisConfig redisConfig) { + config.setUsername(redisConfig.user); + config.setPassword(redisConfig.password); + config.setRetryAttempts(redisConfig.retryAttempts); + config.setRetryInterval(redisConfig.retryInterval); + config.setKeepAlive(redisConfig.keepAlive); + config.setTimeout(redisConfig.timeout); + config.setConnectTimeout(redisConfig.connectTimeout); + config.setIdleConnectionTimeout(redisConfig.idleConnectionTimeout); + config.setPingConnectionInterval(redisConfig.pingConnectionInterval); + } + + /** + * Resolves a single address by ensuring it has the correct Redis schema. + * If the address is null or empty, it returns the address as is. + * If the address already starts with "rediss://" or "redis://", it returns the address unchanged. + * Otherwise, it prepends "redis://" to the address. + * + * @param address the address to resolve + * @return the resolved address with the correct schema + */ + protected String resolveAddress(String address) { + if (address == null || address.isEmpty()) { + return address; + } else if (address.startsWith(SCHEMA_REDISS)) { + return address; + } else if (address.startsWith(SCHEMA_REDIS)) { + return address; + } else { + return SCHEMA_REDIS + address; + } + } + + /** + * Resolves an array of addresses by ensuring each address has the correct Redis schema. + * It uses the {@link #resolveAddress(String)} method for each individual address. + * + * @param addresses the array of addresses to resolve + * @return an array of resolved addresses with the correct schema + */ + protected String[] resolveAddress(String[] addresses) { + String[] result = null; + if (addresses != null) { + result = new String[addresses.length]; + for (int i = 0; i < addresses.length; i++) { + result[i] = resolveAddress(addresses[i]); + } + } + + return result; + } + + } + + /** + * Abstract base class for configuring Redis master-slave settings. + * + * @param the type of the configuration object, extending {@link BaseMasterSlaveServersConfig} + */ + abstract class BaseMasterSlaveConfigurator> extends BaseConfigurator { + + @Override + public void configure(T config, RedisConfig redisConfig) { + super.configure(config, redisConfig); + config.setReadMode(ReadMode.MASTER) + .setMasterConnectionPoolSize(redisConfig.masterConnectionPoolSize) + .setMasterConnectionMinimumIdleSize(redisConfig.masterConnectionMinimumIdleSize) + .setSlaveConnectionPoolSize(redisConfig.slaveConnectionPoolSize) + .setSlaveConnectionMinimumIdleSize(redisConfig.slaveConnectionMinimumIdleSize); + } + } + + /** + * Configurator for Redis master-slave setups. + */ + class MasterSlaveConfigurator extends BaseMasterSlaveConfigurator { + + public static MasterSlaveConfigurator INSTANCE = new MasterSlaveConfigurator(); + + @Override + public void configure(MasterSlaveServersConfig config, RedisConfig redisConfig) { + super.configure(config, redisConfig); + List addresses = splitList(redisConfig.address); + String master = addresses.get(0); + String[] slaves = addresses.size() == 1 ? new String[0] : addresses.subList(1, addresses.size()).toArray(new String[0]); + config.setMasterAddress(master) + .addSlaveAddress(slaves) + .setDatabase(redisConfig.database); + } + } + + /** + * Configurator for Redis sentinel setups. + */ + class SentinelConfigurator extends BaseMasterSlaveConfigurator { + + public static final SentinelConfigurator INSTANCE = new SentinelConfigurator(); + + @Override + public void configure(SentinelServersConfig config, RedisConfig redisConfig) { + super.configure(config, redisConfig); + config.addSentinelAddress(resolveAddress(split(redisConfig.address))) + .setDatabase(config.getDatabase()) + .setSentinelUsername(redisConfig.sentinelUser) + .setSentinelPassword(redisConfig.sentinelPassword); + } + } + + /** + * Configurator for Redis cluster setups. + */ + class ClusterConfigurator extends BaseMasterSlaveConfigurator { + + public static final ClusterConfigurator INSTANCE = new ClusterConfigurator(); + + @Override + public void configure(ClusterServersConfig config, RedisConfig redisConfig) { + super.configure(config, redisConfig); + config.addNodeAddress(resolveAddress(split(redisConfig.address))); + } + } + + /** + * Configurator for Redis replicated setups. + */ + class ReplicatedConfigurator extends BaseMasterSlaveConfigurator { + + public static ReplicatedConfigurator INSTANCE = new ReplicatedConfigurator(); + + @Override + public void configure(ReplicatedServersConfig config, RedisConfig redisConfig) { + super.configure(config, redisConfig); + config.addNodeAddress(resolveAddress(split(redisConfig.address))).setDatabase(config.getDatabase()); + } + } + + /** + * Configurator for single Redis server setups. + */ + class SingleConfigurator extends BaseConfigurator { + + public static final SingleConfigurator INSTANCE = new SingleConfigurator(); + + @Override + public void configure(SingleServerConfig config, RedisConfig redisConfig) { + super.configure(config, redisConfig); + config.setAddress(resolveAddress(redisConfig.address)) + .setDatabase(redisConfig.database) + .setConnectionPoolSize(redisConfig.connectionPoolSize) + .setConnectionMinimumIdleSize(redisConfig.connectionMinimumIdleSize); + } + } +} diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisType.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisType.java new file mode 100644 index 000000000..deb66215a --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/client/RedisType.java @@ -0,0 +1,104 @@ +/* + * Copyright © ${year} ${owner} (${email}) + * + * 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 com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client; + +import com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.client.RedisConfigurator.*; +import org.redisson.config.Config; + +/** + * Enum representing different types of Redis configurations. + * Each enum constant provides a method to configure a Redisson {@link Config} object based on the specific Redis type. + */ +public enum RedisType { + + /** + * Represents a single Redis server configuration. + */ + SINGLE { + @Override + public void configure(Config config, RedisConfig redisConfig) { + SingleConfigurator.INSTANCE.configure(config.useSingleServer(), redisConfig); + } + }, + + /** + * Represents a replicated Redis servers configuration. + */ + REPLICATED { + @Override + public void configure(Config config, RedisConfig redisConfig) { + ReplicatedConfigurator.INSTANCE.configure(config.useReplicatedServers(), redisConfig); + } + }, + + /** + * Represents a Redis sentinel configuration. + */ + SENTINEL { + @Override + public void configure(Config config, RedisConfig redisConfig) { + SentinelConfigurator.INSTANCE.configure(config.useSentinelServers(), redisConfig); + } + }, + + /** + * Represents a Redis cluster configuration. + */ + CLUSTER { + @Override + public void configure(Config config, RedisConfig redisConfig) { + ClusterConfigurator.INSTANCE.configure(config.useClusterServers(), redisConfig); + } + }, + + /** + * Represents a master-slave Redis configuration. + */ + MASTER_SLAVE { + @Override + public void configure(Config config, RedisConfig redisConfig) { + MasterSlaveConfigurator.INSTANCE.configure(config.useMasterSlaveServers(), redisConfig); + } + }; + + /** + * Configures the Redisson {@link Config} object based on the specific Redis type. + * + * @param config the Redisson {@link Config} object to be configured + * @param redisConfig the {@link RedisConfig} containing the configuration settings + */ + public abstract void configure(Config config, RedisConfig redisConfig); + + /** + * Parses a string to a {@link RedisType} enum constant. + * If the input string is null or empty, or if it does not match any valid enum constant, + * the method returns {@link RedisType#CLUSTER} as the default value. + * + * @param type the string representation of the Redis type + * @return the corresponding {@link RedisType} enum constant, or {@link RedisType#CLUSTER} if the input is invalid + */ + public static RedisType parse(String type) { + if (type == null || type.isEmpty()) { + return CLUSTER; + } + try { + return RedisType.valueOf(type.toUpperCase()); + } catch (IllegalArgumentException e) { + return CLUSTER; + } + } + +} diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/package-info.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/package-info.java new file mode 100644 index 000000000..a82c1bb95 --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/redisson/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright © ${year} ${owner} (${email}) + * + * 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-info + */ +package com.jd.live.agent.implement.flowcontrol.ratelimit.redisson; \ No newline at end of file diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.ratelimit.RateLimiterFactory b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.ratelimit.RateLimiterFactory new file mode 100644 index 000000000..094008b39 --- /dev/null +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-redisson/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.ratelimit.RateLimiterFactory @@ -0,0 +1 @@ +com.jd.live.agent.implement.flowcontrol.ratelimit.redisson.RedissonRateLimiterFactory \ No newline at end of file diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/InstanceCircuitBreakerStateListener.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/InstanceCircuitBreakerStateListener.java similarity index 96% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/InstanceCircuitBreakerStateListener.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/InstanceCircuitBreakerStateListener.java index 08806d465..3f47ba152 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/InstanceCircuitBreakerStateListener.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/InstanceCircuitBreakerStateListener.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.circuitbreak; +package com.jd.live.agent.implement.flowcontrol.circuitbreak.resilience4j; import com.jd.live.agent.bootstrap.logger.Logger; import com.jd.live.agent.bootstrap.logger.LoggerFactory; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/Resilience4jCircuitBreaker.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/Resilience4jCircuitBreaker.java similarity index 97% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/Resilience4jCircuitBreaker.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/Resilience4jCircuitBreaker.java index 015566b36..0cd440a68 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/Resilience4jCircuitBreaker.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/Resilience4jCircuitBreaker.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.circuitbreak; +package com.jd.live.agent.implement.flowcontrol.circuitbreak.resilience4j; import com.jd.live.agent.core.util.URI; import com.jd.live.agent.governance.invoke.circuitbreak.AbstractCircuitBreaker; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/Resilience4jCircuitBreakerEventConsumer.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/Resilience4jCircuitBreakerEventConsumer.java similarity index 97% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/Resilience4jCircuitBreakerEventConsumer.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/Resilience4jCircuitBreakerEventConsumer.java index 5a7f9fa44..4a036a20a 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/Resilience4jCircuitBreakerEventConsumer.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/Resilience4jCircuitBreakerEventConsumer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.circuitbreak; +package com.jd.live.agent.implement.flowcontrol.circuitbreak.resilience4j; import com.jd.live.agent.governance.invoke.circuitbreak.CircuitBreakerState; import com.jd.live.agent.governance.invoke.circuitbreak.CircuitBreakerStateEvent; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/Resilience4jCircuitBreakerFactory.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/Resilience4jCircuitBreakerFactory.java similarity index 98% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/Resilience4jCircuitBreakerFactory.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/Resilience4jCircuitBreakerFactory.java index d827d59d6..ffb096b9b 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/circuitbreak/Resilience4jCircuitBreakerFactory.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/circuitbreak/resilience4j/Resilience4jCircuitBreakerFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.circuitbreak; +package com.jd.live.agent.implement.flowcontrol.circuitbreak.resilience4j; import com.jd.live.agent.core.extension.annotation.Extension; import com.jd.live.agent.core.inject.annotation.Injectable; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/concurrencylimit/Resilience4jConcurrencyLimiter.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/concurrencylimit/resilience4j/Resilience4jConcurrencyLimiter.java similarity index 95% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/concurrencylimit/Resilience4jConcurrencyLimiter.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/concurrencylimit/resilience4j/Resilience4jConcurrencyLimiter.java index 5a7aa19d5..da584ecee 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/concurrencylimit/Resilience4jConcurrencyLimiter.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/concurrencylimit/resilience4j/Resilience4jConcurrencyLimiter.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.concurrencylimit; +package com.jd.live.agent.implement.flowcontrol.concurrencylimit.resilience4j; import com.jd.live.agent.governance.invoke.concurrencylimit.AbstractConcurrencyLimiter; import com.jd.live.agent.governance.policy.service.limit.ConcurrencyLimitPolicy; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/concurrencylimit/Resilience4jConcurrencyLimiterFactory.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/concurrencylimit/resilience4j/Resilience4jConcurrencyLimiterFactory.java similarity index 94% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/concurrencylimit/Resilience4jConcurrencyLimiterFactory.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/concurrencylimit/resilience4j/Resilience4jConcurrencyLimiterFactory.java index 23549e0ca..369f6a733 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/concurrencylimit/Resilience4jConcurrencyLimiterFactory.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/concurrencylimit/resilience4j/Resilience4jConcurrencyLimiterFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.concurrencylimit; +package com.jd.live.agent.implement.flowcontrol.concurrencylimit.resilience4j; import com.jd.live.agent.core.extension.annotation.Extension; import com.jd.live.agent.core.inject.annotation.Injectable; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/AtomicRateLimiter.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/AtomicRateLimiter.java similarity index 99% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/AtomicRateLimiter.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/AtomicRateLimiter.java index ada27e163..1721174da 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/AtomicRateLimiter.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/AtomicRateLimiter.java @@ -16,7 +16,7 @@ * * */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.ratelimit; +package com.jd.live.agent.implement.flowcontrol.ratelimit.resilience4j; import io.github.resilience4j.ratelimiter.RateLimiter; import io.github.resilience4j.ratelimiter.RateLimiterConfig; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/Resilience4jRateLimiter.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/Resilience4jRateLimiter.java similarity index 96% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/Resilience4jRateLimiter.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/Resilience4jRateLimiter.java index 20e9230d0..cbd029b33 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/Resilience4jRateLimiter.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/Resilience4jRateLimiter.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.ratelimit; +package com.jd.live.agent.implement.flowcontrol.ratelimit.resilience4j; import com.jd.live.agent.governance.invoke.ratelimit.AbstractRateLimiter; import com.jd.live.agent.governance.policy.service.limit.RateLimitPolicy; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/Resilience4jRateLimiterFactory.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/Resilience4jRateLimiterFactory.java similarity index 95% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/Resilience4jRateLimiterFactory.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/Resilience4jRateLimiterFactory.java index 6aeb4b0ce..2a5144332 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/Resilience4jRateLimiterFactory.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/Resilience4jRateLimiterFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.ratelimit; +package com.jd.live.agent.implement.flowcontrol.ratelimit.resilience4j; import com.jd.live.agent.core.extension.annotation.Extension; import com.jd.live.agent.core.inject.annotation.Injectable; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/Resilience4jRateLimiterGroup.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/Resilience4jRateLimiterGroup.java similarity index 94% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/Resilience4jRateLimiterGroup.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/Resilience4jRateLimiterGroup.java index fd05a3365..5e643d101 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/Resilience4jRateLimiterGroup.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/Resilience4jRateLimiterGroup.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.ratelimit; +package com.jd.live.agent.implement.flowcontrol.ratelimit.resilience4j; import com.jd.live.agent.governance.invoke.ratelimit.AbstractRateLimiterGroup; import com.jd.live.agent.governance.invoke.ratelimit.RateLimiter; diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/package-info.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/package-info.java similarity index 90% rename from joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/package-info.java rename to joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/package-info.java index 8786130ca..1dd43d9c9 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/resilience4j/ratelimit/package-info.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/java/com/jd/live/agent/implement/flowcontrol/ratelimit/resilience4j/package-info.java @@ -19,4 +19,4 @@ * @author Zhiguo.Chen * @since 1.0.0 */ -package com.jd.live.agent.implement.flowcontrol.resilience4j.ratelimit; \ No newline at end of file +package com.jd.live.agent.implement.flowcontrol.ratelimit.resilience4j; \ No newline at end of file diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.circuitbreak.CircuitBreakerFactory b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.circuitbreak.CircuitBreakerFactory index e3b673838..a679aa02f 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.circuitbreak.CircuitBreakerFactory +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.circuitbreak.CircuitBreakerFactory @@ -1 +1 @@ -com.jd.live.agent.implement.flowcontrol.resilience4j.circuitbreak.Resilience4jCircuitBreakerFactory \ No newline at end of file +com.jd.live.agent.implement.flowcontrol.circuitbreak.resilience4j.Resilience4jCircuitBreakerFactory \ No newline at end of file diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.concurrencylimit.ConcurrencyLimiterFactory b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.concurrencylimit.ConcurrencyLimiterFactory index e56b54a3a..69ca4b94a 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.concurrencylimit.ConcurrencyLimiterFactory +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.concurrencylimit.ConcurrencyLimiterFactory @@ -1 +1 @@ -com.jd.live.agent.implement.flowcontrol.resilience4j.concurrencylimit.Resilience4jConcurrencyLimiterFactory \ No newline at end of file +com.jd.live.agent.implement.flowcontrol.concurrencylimit.resilience4j.Resilience4jConcurrencyLimiterFactory \ No newline at end of file diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.ratelimit.RateLimiterFactory b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.ratelimit.RateLimiterFactory index 4aacdc6a4..f267ad7ae 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.ratelimit.RateLimiterFactory +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/main/resources/META-INF/services/com.jd.live.agent.governance.invoke.ratelimit.RateLimiterFactory @@ -1 +1 @@ -com.jd.live.agent.implement.flowcontrol.resilience4j.ratelimit.Resilience4jRateLimiterFactory \ No newline at end of file +com.jd.live.agent.implement.flowcontrol.ratelimit.resilience4j.Resilience4jRateLimiterFactory \ No newline at end of file diff --git a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/test/java/com/jd/live/agent/implement/ratelimit/resilience4j/test/Resilience4jRateLimiterTest.java b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/test/java/com/jd/live/agent/implement/ratelimit/resilience4j/test/Resilience4jRateLimiterTest.java index c8400b285..8add66236 100644 --- a/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/test/java/com/jd/live/agent/implement/ratelimit/resilience4j/test/Resilience4jRateLimiterTest.java +++ b/joylive-implement/joylive-flowcontrol/joylive-flowcontrol-resilience4j/src/test/java/com/jd/live/agent/implement/ratelimit/resilience4j/test/Resilience4jRateLimiterTest.java @@ -17,7 +17,7 @@ import com.jd.live.agent.governance.policy.service.limit.RateLimitPolicy; import com.jd.live.agent.governance.policy.service.limit.SlidingWindow; -import com.jd.live.agent.implement.flowcontrol.resilience4j.ratelimit.Resilience4jRateLimiter; +import com.jd.live.agent.implement.flowcontrol.ratelimit.resilience4j.Resilience4jRateLimiter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; diff --git a/joylive-implement/joylive-flowcontrol/pom.xml b/joylive-implement/joylive-flowcontrol/pom.xml index c3b632256..e406c9c62 100644 --- a/joylive-implement/joylive-flowcontrol/pom.xml +++ b/joylive-implement/joylive-flowcontrol/pom.xml @@ -13,6 +13,7 @@ pom joylive-flowcontrol-resilience4j + joylive-flowcontrol-redisson diff --git a/joylive-package/pom.xml b/joylive-package/pom.xml index abf0b6dad..1a0279574 100644 --- a/joylive-package/pom.xml +++ b/joylive-package/pom.xml @@ -111,6 +111,10 @@ com.jd.live joylive-flowcontrol-resilience4j + + com.jd.live + joylive-flowcontrol-redisson + com.jd.live joylive-classloader-springboot2 diff --git a/joylive-package/src/main/assembly/assembly.xml b/joylive-package/src/main/assembly/assembly.xml index f30f2eff9..4aae8f256 100644 --- a/joylive-package/src/main/assembly/assembly.xml +++ b/joylive-package/src/main/assembly/assembly.xml @@ -68,6 +68,7 @@ com.jd.live:joylive-event-opentelemetry com.jd.live:joylive-expression-jexl com.jd.live:joylive-flowcontrol-resilience4j + com.jd.live:joylive-flowcontrol-redisson diff --git a/joylive-package/src/main/assembly/config/microservice.json b/joylive-package/src/main/assembly/config/microservice.json index 40d12f4e8..00bdafab3 100644 --- a/joylive-package/src/main/assembly/config/microservice.json +++ b/joylive-package/src/main/assembly/config/microservice.json @@ -407,6 +407,73 @@ } ] }, + { + "name": "service-provider-reactive", + "serviceType": "HTTP", + "version": 0, + "groups": [ + { + "name": "default", + "defaultGroup": true, + "servicePolicy": { + "livePolicy": { + "unitPolicy": "PREFER_LOCAL_UNIT" + }, + "loadBalancePolicy": { + "policyType": "ROUND_ROBIN" + }, + "clusterPolicy": { + "type": "failover", + "retryPolicy": { + "retry": 10, + "interval": 1000, + "timeout": 5000, + "errorCodes": [ + 500, + 502 + ], + "methods": [ + "GET" + ], + "exceptions": [ + "java.lang.NullPointException" + ], + "version": 1704038400000 + } + }, + "rateLimitPolicies": [ + { + "name": "limit-rule-1", + "version": 1704038400000, + "realizeType": "RedissonCluster", + "slidingWindows": [ + { + "threshold": 100, + "timeWindowInMs": 1000 + } + ], + "maxWaitMs": 100, + "actionParameters": { + "type": "Single", + "address": "127.0.0.1:6379" + }, + "relationType": "AND", + "conditions": [ + { + "type": "query", + "opType": "EQUAL", + "key": "limiter", + "values": [ + "true" + ] + } + ] + } + ] + } + } + ] + }, { "name": "dubbo3-provider", "serviceType": "RPC_APP",