java分布式应用限流实现

java分布式应用限流实现

题记

众所周知,现今分布式限流工具有许多,对于不同应用框架的支持也不尽相同,选择适合当前项目架构的限流技术才是最合适的。

分布式

什么是分布式

分布式系统(distributed system)是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。

分布式系统优点

提高系统并发量和吞吐率,通俗点讲,就是单台机器与多台机器同时工作的区别。

分布式核心问题

并发导致的系统问题,著名的CAP理论就是对分布式系统问题的诠释:一致性、可用性、分区容错性

数据一致性解决方案

最简单,最常见的方法就是实现分布式锁,如:采用数据库实现,采用Zookeeper实现,采用Redis实现等。

以上归纳的方法属于分布式并发问题的解决方案,本文主要对高并发场景的限流进行优化解决

限流

java并发限流

Java并发工具类(四)Semaphore
Java并发工具类(三)Exchanger
Java并发工具类(二)CyclicBarrier
Java并发工具类(一)CountDownLatch

java限流针对的是单机场景下对于接口执行的限制,可以满足指定的场景。但是用于分布式架构的系统中不合时宜。

分布式应用限流

实现分布式限流的思路有很多种

基于Redis的限流
Redissetnx的操作

固定时间窗口大小,不会有滑动窗口的效果,除非按照N:N,即为N个单位时间对应Nkey,动态实现计数。

Redis的数据结构zset
 public boolean limitZset(){
    
    

        int currentTime = Helper.getCurrentTime();

        int intervalTime = 10 * 1000;

        System.err.println("开始时间:" + currentTime);

        if(redisTemplate.hasKey("limit_key")) {
    
    

            Integer count = redisTemplate.opsForZSet().rangeByScore("limit_key", currentTime -  intervalTime, currentTime).size();        // intervalTime是限流的时间

            System.out.println(count);

            if (count != null && count > 5) {
    
    

                return false;

            }

        }

        redisTemplate.opsForZSet().add("limit_key",UUID.randomUUID().toString(),currentTime);

        System.err.println("结束时间:" + Helper.getCurrentTime());
        return true;

    }
Redis的令牌桶算法
public boolean limitLeakyBuckets (){
    
    

 Object result = redisTemplate.opsForList().leftPop("limit_leaky_buckets");
        if(result == null){
    
    
            return false;
        }
       return true;
    }


@Scheduled(fixedDelay = 10000,initialDelay = 0)
public void setToken(){
    
    

    redisTemplate.opsForList().rightPush("limit_leaky_buckets",UUID.randomUUID().toString());

    }
}
基于Hystrix的限流

Netflix公司在分布式微服务架构的践行下,将其保护服务的稳定性而设计的客户端熔断和断路器的解决方案,称之为Hystrix

Future限流实现

public class FutureDemo {
    
    

    private static final Random random = new Random();

    public static void main(String[] args) throws InterruptedException, ExecutionException {
    
    
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future<String> future = executorService.submit(()->{
    
    
            int nextInt = random.nextInt(200);
            System.out.printf("Thread : %s,睡眠时间: %s ms \n", Thread.currentThread().getName(),nextInt);
            try {
    
    
                Thread.sleep(nextInt);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }finally {
    
    
                executorService.shutdown();
            }
            return "hello world";
        });

        try {
    
    
            future.get(100, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
    
    
            System.out.println("服务熔断保护");
            e.printStackTrace();
        }
    }
}

Hystrix实现

@RestController
public class HelloWorldController {
    
    

    private final Random random = new Random();

    @GetMapping("/hello")
    @HystrixCommand(fallbackMethod = "errorOfHello",
            commandProperties = {
    
    
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100")
            }
    )
    public String hello() throws InterruptedException {
    
    
        int nextInt = random.nextInt(200);
        System.out.printf("Thread : %s,睡眠时间: %s ms \n", Thread.currentThread().getName(), nextInt);
        Thread.sleep(nextInt);
        return "hello world";
    }

    @GetMapping("/hello2")
    public String hello2() throws InterruptedException {
    
    
        return new HystrixCommendDemo().execute();
    }


    public String errorOfHello() {
    
    
        return "error of hello world";
    }
}
基于Sentinel的限流

Sentinel是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。

public static void main(String[] args) {
    
    
        initFlowRules(); //初始化规则
        while(true){
    
    
            Entry entry=null;
            try{
    
    
                entry= SphU.entry(resource); //准入判断
                System.out.println("Hello Word");
            }catch (BlockException e){
    
    //异常处理
                e.printStackTrace();
            }finally {
    
    
                if(entry!=null){
    
    
                    entry.exit();// 资源释放
                }
            }
        }
    }
Sentinel对比 Hystrix
对比内容 Sentinel Hystrix
隔离策略 信号量隔离 线程池隔离/信号量隔离
熔断降级策略 基于响应时间或失败比率 基于失败比率
实时指标实现 滑动窗口 滑动窗口(基于 RxJava)
规则配置 支持多种数据源 支持多种数据源
扩展性 多个扩展点 插件的形式
基于注解的支持 支持 支持
限流 基于 QPS,支持基于调用关系的限流 不支持
流量整形 支持慢启动、匀速器模式 不支持
系统负载保护 支持 不支持
控制台 开箱即用,可配置规则、查看秒级监控、机器发现等 不完善
常见框架的适配 Servlet、Spring Cloud、Dubbo、gRPC 等 Servlet、Spring Cloud Netflix

猜你喜欢

转载自blog.csdn.net/shang_xs/article/details/108449708