令牌桶算法笔记

前言

令牌桶。。。用到是用到过 不过不是限流 是业务功能中使用的 不过跟限流类似 只不过生成令牌含义变成了某种业务的前置条件了
也记录一下 方便后续查询

算法原理

参考文档: https://baike.baidu.com/item/令牌桶算法/6597000

搞个放令牌的桶 每次请求都获取一个令牌进行访问 通过控制令牌生成的速度来控制请求速率

照例 意思意思


--------
       ·生成令牌 
       ·
  ----------
  \        /
   \  桶  /
    \    /
     ----
       ·分发令牌
       ·
输入流量-------尝试获取令牌----> 有合法令牌继续访问、没有令牌或者不合法拒绝访问------>  输出流量       
标记器

如果只是做流量控制 令牌桶算法本身就够用了
但是如果要做流量标记分析处理 那么就需要对流量进行标记 通过不同的方案去计算流量的特性 我也不明白 看起来就是通过做标记 来对流量进行分析
这里只作为记录

  • IN/OUT 公平标记器(FM)
  • 单速率三色标记器(srTCM)
  • 双速率标记器(trTCM)

实例

java编写

package com.ming;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.junit.Test;

import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * 令牌桶算法测试用例
 * 令牌桶算算法
 *
 * @author ming
 * @date 2019-09-17 13:55:47
 */
@Slf4j
public class TokenBucketTest {

    /**
     * 测试令牌桶模式 限流
     * <p>
     * 按照下面参数
     * 当桶满的情况下  5s内最大请求数为100  并且后续每5s 能够允许10次访问
     *
     * @author ming
     * @date 2019-09-17 13:57:12
     */
    @Test
    public void test() throws InterruptedException {
        //桶深
        int maxSize = 100;
        //生成令牌 休眠时间
        int generateSleepTime = 5;
        //一次生成多少令牌
        int generateTokenNumber = 30;

        //输出流量休眠时间
        int outputSleepTime = 1;


        //用 blockQueue模拟桶
        Queue<String> tokenBucket = new ArrayBlockingQueue<>(maxSize);

        //新启动一个线程 作为 token 生成 每5s生成10个
        new Thread(() -> {
            while (true) {
                for (int i = 0; i < generateTokenNumber; i++) {
                    try {
                        tokenBucket.add("生成令牌:" + System.currentTimeMillis() + "::" + i + "当前令牌桶容量:" + tokenBucket.size());
                    } catch (Exception e) {
                        //e.printStackTrace();
                        log.error("生成令牌失败 令牌桶当前容量:" + tokenBucket.size());
                        //不再继续添加令牌
                        continue;
                    }
                }

                try {
                    Thread.sleep(generateSleepTime * 1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //新启动一个线程 作为请求流量并且处理
        new Thread(() -> {
            while (true) {
                //模拟获取令牌
                String token = System.currentTimeMillis() + "获取令牌" + tokenBucket.poll();
                if (StringUtils.isEmpty(token)) {
                    //令牌为null 拒绝访问
                    log.warn("无令牌 禁止访问~");
                } else {
                    //存在令牌 允许访问 此处直接打印令牌
                    log.info(tokenBucket.size()+"::允许访问:::" + token);
                }


                try {
                    Thread.sleep(outputSleepTime * 1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        Thread.sleep(1000000L);

    }


}

总结

令牌桶 通过控制令牌数量 来达到控制请求频率 之前没咋用过
不过 我看到更多的是在流量标记分析上用令牌桶的多 例如qos 在一些特定业务中 也有类似令牌桶算法的套路

© 2024 ming博客. All rights reserved.基于rust salvo性能猛的很!