限流、熔断、降级

8 阅读1分钟

限流 Rhino

①、常见的方式: heapdump.cn/article/548…

  • 令牌桶方式:以固定的速率往桶中添加令牌,处理速度取决于桶中令牌数
  • 漏桶方式:按照固定的速率流出请求,流入速率不限制。可以积攒请求取决于桶容量
  • 计数器方式:采用Semaphore信号量。如果超过阈值信号量,则进入队列阻塞等待
  • 滑动窗口方式:

采用滑动窗口限流方法实现

public class DynamicWindowLimit {
    private long limit = 1;
    private final int windowNum = 5;
    private final int windowTime = 1000;
    private LinkedList<Entry> windowList = Lists.newLinkedList();

    public DynamicWindowLimit() {
        while (true) {
            new Thread(() -> {
                if (windowList.size() == windowNum) {
                    // 删除最左的一个格子
                    windowList.poll();
                }
                // 窗口向右移动新增
                windowList.offer(new Entry(System.currentTimeMillis() / 1000));
                try {
                    Thread.sleep(windowTime / windowNum);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }).start();
        }
    }

    public boolean tryAcquire() {
        // 先判断当前属于哪个小窗口
        Entry entry = getCurWindow();
        entry.setCount(entry.getCount() + 1);
        return getSumRequest() >= limit;
    }

    public long getSumRequest() {
        return windowList.stream().mapToLong(Entry::getCount).sum();
    }
    public Entry getCurWindow() {
        if (windowList.isEmpty()) {
            while (true) {
                if (windowList.isEmpty()) {
                    break;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return windowList.getLast();
    }

    class Entry {
        long count;
        long time;

        public Entry(long time) {
            this.time = time;
        }

        public long getCount() {
            return count;
        }

        public void setCount(long count) {
            this.count = count;
        }

        public long getTime() {
            return time;
        }

        public void setTime(long time) {
            this.time = time;
        }
    }

    public static void main(String[] args) {
        DynamicWindowLimit dynamicWindowLimit = new DynamicWindowLimit();
        for (int i = 0; i < 3; i++) {
            if (dynamicWindowLimit.tryAcquire()) {
                System.out.println("请求可以执行...");
            } else {
                System.out.println("请求被限流!!!");
            }
        }
    }
}

②、限流的指标一般有哪些?

  • QPS、响应时间、错误率。

③、怎么实现集群维度的限流?

  • 单机模式下:每个应用启动的时候都会启动一个token-server来实现单机的限流策略
  • 集群模式下:会有一个单独token-server服务端,其他的应用里引入的是token-client,应用判断是否限流时是需要向server请求判断的,server管控整个集群所有的client对资源的访问是否达到限流配置

采用的是令牌桶的方式

④、Sentinel
sentinelguard.io/zh-cn/docs/…