网站首页 > java教程 正文
在分布式系统和高并发场景中,限流是保证系统稳定性和高可用性的关键技术之一。本期咱们一起探讨Sentinel和Spring Cloud Gateway的限流实现差异,并通过代码示例帮助你更好地理解和应用这些技术。
三大经典限流算法Java实现
1. 滑动时间窗口算法实现
public class SlidingWindow {
    private final long windowSizeInMs;
    private final int maxRequests;
    private final LinkedList<Long> requests = new LinkedList<>();
    
    public SlidingWindow(long windowSizeInMs, int maxRequests) {
        this.windowSizeInMs = windowSizeInMs;
        this.maxRequests = maxRequests;
    }
    
    public synchronized boolean allowRequest() {
        long currentTime = System.currentTimeMillis();
        // 移除过期请求
        while (!requests.isEmpty() && 
               requests.getFirst() < currentTime - windowSizeInMs) {
            requests.removeFirst();
        }
        
        if (requests.size() < maxRequests) {
            requests.addLast(currentTime);
            return true;
        }
        return false;
    }
}
// 使用示例
public class SlidingWindowExample {
    public static void main(String[] args) {
        // 限制1秒内最多10个请求
        SlidingWindow window = new SlidingWindow(1000, 10);
        
        for (int i = 0; i < 15; i++) {
            if (window.allowRequest()) {
                System.out.println("请求 " + (i + 1) + ": 允许");
            } else {
                System.out.println("请求 " + (i + 1) + ": 被限流");
            }
            try { Thread.sleep(100); } catch (InterruptedException e) {}
        }
    }
}2. 令牌桶算法实现
public class TokenBucket {
    private final int capacity;
    private final double refillRate; // 令牌/毫秒
    private double tokens;
    private long lastRefillTime;
    
    public TokenBucket(int capacity, int refillTokensPerSecond) {
        this.capacity = capacity;
        this.refillRate = refillTokensPerSecond / 1000.0;
        this.tokens = capacity;
        this.lastRefillTime = System.currentTimeMillis();
    }
    
    public synchronized boolean allowRequest() {
        refillTokens();
        if (tokens >= 1) {
            tokens -= 1;
            return true;
        }
        return false;
    }
    
    private void refillTokens() {
        long currentTime = System.currentTimeMillis();
        double timePassed = currentTime - lastRefillTime;
        tokens = Math.min(capacity, tokens + timePassed * refillRate);
        lastRefillTime = currentTime;
    }
}
// 使用示例
public class TokenBucketExample {
    public static void main(String[] args) {
        // 容量10个令牌,每秒补充5个
        TokenBucket bucket = new TokenBucket(10, 5);
        
        for (int i = 0; i < 20; i++) {
            if (bucket.allowRequest()) {
                System.out.println("请求 " + (i + 1) + ": 允许");
            } else {
                System.out.println("请求 " + (i + 1) + ": 被限流");
            }
            try { Thread.sleep(100); } catch (InterruptedException e) {}
        }
    }
}Sentinel 限流实战
3. Sentinel 基础使用示例
// 添加Maven依赖
// <dependency>
//     <groupId>com.alibaba.csp</groupId>
//     <artifactId>sentinel-core</artifactId>
//     <version>1.8.6</version>
// </dependency>
public class SentinelExample {
    
    // 定义资源
    private static final String RESOURCE_NAME = "orderApi";
    
    static {
        // 配置流控规则:QPS不超过10
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource(RESOURCE_NAME);
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(10);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
    
    public void createOrder() {
        Entry entry = null;
        try {
            entry = SphU.entry(RESOURCE_NAME);
            // 执行业务逻辑
            System.out.println("创建订单成功");
        } catch (BlockException e) {
            // 被限流
            System.out.println("创建订单被限流");
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        SentinelExample example = new SentinelExample();
        // 模拟高并发请求
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                example.createOrder();
            }).start();
            Thread.sleep(10);
        }
    }
}4. Sentinel 热点参数限流
public class SentinelParamFlowExample {
    
    private static final String RESOURCE_NAME = "queryUserInfo";
    
    static {
        // 热点参数限流规则
        ParamFlowRule rule = new ParamFlowRule(RESOURCE_NAME)
            .setParamIdx(0) // 第一个参数为热点参数
            .setGrade(RuleConstant.FLOW_GRADE_QPS)
            .setCount(5);   // 每个参数值每秒最多5次
            
        ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
    }
    
    public String queryUserInfo(Long userId) {
        Entry entry = null;
        try {
            // 使用热点参数
            entry = SphU.entry(RESOURCE_NAME, EntryType.IN, 1, userId);
            return "用户信息: " + userId;
        } catch (BlockException e) {
            return "请求过于频繁,请稍后重试";
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
    }
}Spring Cloud Gateway 限流实战
5. Gateway + Redis 限流配置
# application.yml
spring:
  redis:
    host: localhost
    port: 6379
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: http://localhost:8080
          predicates:
            - Path=/user/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10   # 每秒令牌数
                redis-rate-limiter.burstCapacity: 20   # 令牌桶容量
                key-resolver: "#{@userKeyResolver}"6. Gateway 限流Java配置
@Configuration
public class RateLimitConfig {
    
    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> {
            // 根据用户ID限流
            String userId = exchange.getRequest()
                .getQueryParams()
                .getFirst("userId");
            return Mono.just(Objects.requireNonNullElse(userId, "anonymous"));
        };
    }
    
    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(10, 20);
    }
}
// 自定义限流处理器
@Component
public class CustomRateLimiter implements RateLimiter {
    
    @Override
    public Mono<Response> isAllowed(String routeId, String id) {
        // 自定义限流逻辑
        return Mono.just(new Response(true, -1));
    }
    
    public static class Response {
        private final boolean allowed;
        private final long tokensRemaining;
        
        public Response(boolean allowed, long tokensRemaining) {
            this.allowed = allowed;
            this.tokensRemaining = tokensRemaining;
        }
    }
}性能测试对比
7. 限流算法性能测试
public class RateLimiterBenchmark {
    
    public static void main(String[] args) {
        testSlidingWindow();
        testTokenBucket();
        testSentinel();
    }
    
    private static void testSlidingWindow() {
        SlidingWindow limiter = new SlidingWindow(1000, 1000);
        long start = System.currentTimeMillis();
        int count = 0;
        for (int i = 0; i < 1000000; i++) {
            if (limiter.allowRequest()) {
                count++;
            }
        }
        long time = System.currentTimeMillis() - start;
        System.out.println("滑动窗口: " + time + "ms, 通过请求: " + count);
    }
    
    private static void testTokenBucket() {
        TokenBucket limiter = new TokenBucket(1000, 1000);
        long start = System.currentTimeMillis();
        int count = 0;
        for (int i = 0; i < 1000000; i++) {
            if (limiter.allowRequest()) {
                count++;
            }
        }
        long time = System.currentTimeMillis() - start;
        System.out.println("令牌桶: " + time + "ms, 通过请求: " + count);
    }
    
    private static void testSentinel() {
        // 初始化Sentinel规则
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("test");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(1000);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
        
        long start = System.currentTimeMillis();
        int count = 0;
        for (int i = 0; i < 1000000; i++) {
            Entry entry = null;
            try {
                entry = SphU.entry("test");
                count++;
            } catch (BlockException e) {
                // 被限流
            } finally {
                if (entry != null) {
                    entry.exit();
                }
            }
        }
        long time = System.currentTimeMillis() - start;
        System.out.println("Sentinel: " + time + "ms, 通过请求: " + count);
    }
}实际应用建议
- 网关层限流:使用Gateway的令牌桶算法,适合处理突发流量
 - 服务层限流:使用Sentinel的滑动窗口,实现更精细的控制
 - 热点数据保护:使用Sentinel的热点参数限流,保护关键资源
 
通过以上代码示例,咱们可以看到不同限流算法的具体实现方式和应用场景。在实际项目中:

- 滑动时间窗口适合需要精确控制QPS的场景
 - 令牌桶算法适合允许突发流量的场景
 - 漏桶算法适合需要平滑输出流量的场景
 
Sentinel和Gateway分别针对不同的使用场景提供了优秀的限流解决方案。小编认为理解它们的底层原理和实现方式,能够帮助咱在实际项目中做出更合理的技术选型。
猜你喜欢
- 2025-09-19 常见的几种简单限流算法_常见的几种简单限流算法有哪些
 - 2025-09-19 常用限流算法与Guava RateLimiter源码解析
 - 2025-09-19 如何实现一个简单可行的限流方法,保障电商系统的稳定性
 - 2025-09-19 常见的4种限流算法与实现_限流方法原理
 - 2025-09-19 API能力开放平台设计思路剖析_开放api技术
 - 2025-09-19 Sentinel 是什么?它是如何实现限流的?
 - 2025-09-19 在Spring Boot集成Bucket4j实现接口限流操作
 - 2025-09-19 Spring Boot3 中实现单节点限流操作全解析
 - 2025-09-19 一文搞懂!7种常见的限流方式!_限流的几种方式
 - 2025-09-19 Java API Gateway动态限流,流量控制还能这么玩?一线实战全解析!
 
欢迎 你 发表评论:
- 最近发表
 
- 标签列表
 - 
- java反编译工具 (77)
 - java反射 (57)
 - java接口 (61)
 - java随机数 (63)
 - java7下载 (59)
 - java数据结构 (61)
 - java 三目运算符 (65)
 - java对象转map (63)
 - Java继承 (69)
 - java字符串替换 (60)
 - 快速排序java (59)
 - java并发编程 (58)
 - java api文档 (60)
 - centos安装java (57)
 - java调用webservice接口 (61)
 - java深拷贝 (61)
 - 工厂模式java (59)
 - java代理模式 (59)
 - java.lang (57)
 - java连接mysql数据库 (67)
 - java重载 (68)
 - java 循环语句 (66)
 - java反序列化 (58)
 - java时间函数 (60)
 - java是值传递还是引用传递 (62)
 
 

本文暂时没有评论,来添加一个吧(●'◡'●)