Позвольте вам понять, что такое ограничение тока

Java Java EE

предисловие

Только лысая голова может стать сильнее.

Текст был включен в мой репозиторий GitHub, добро пожаловать, звезда:GitHub.com/Zhongf UC очень…

Когда я раньше учился, я не мог соприкоснуться с такими вещами, как высокий параллелизм/большой трафик, поэтому, конечно, я никогда не соприкасался с ограничением тока. При просмотре проекта компании мне показалось полезным ограничение по току (RateLimiter), и я, кстати, об этом узнал.

1. Введение в базовые знания об ограничении тока

Зачем ограничивать ток, я думаю, мне не нужно говорить больше.

  • Например, я хожу в ресторан поужинать по выходным, нослишком много людейТеперь я могу только пойти на стойку регистрации, чтобы получить номер, и когда номер придет, я могу войти в ресторан на ужин. Что делать, если ресторан не ограничивает движение? Как только подошло время ужина, люди хлынули внутрь, а ресторан не мог вместить такое количество людей, поэтому легко было попасть в аварию (в ресторане было людно, и пройти было некуда. ресторан рухнул и не выдержал)
  • То же самое относится и к миру кода.Сервер может обрабатывать ограниченное количество запросов.Если объем запросов особенно велик, нам нужно ограничить поток (либо дать запросу подождать, либо отбросить запрос)

限流

В мире кодов есть два распространенных алгоритма ограничения тока:

  • Алгоритм ведра токенов
  • алгоритм дырявого ведра

1.1 Что такое алгоритм дырявого ведра

Например, теперь у меня есть ведро, зеленая часть — это емкость, в которую я могу вместить воду, если она превышает вместимость, которую я могу вместить, а затем налить воду в ведро, оно переполнится (ограниченный поток):

桶子

Что мы знаем на данный момент:

  • Вместимость ведра фиксирована (зеленый на картинке)
  • Если емкость ведра превышена, оно переполнится (либо подождите, либо сбросьте напрямую)

Хорошо, теперь выкапываем дырку в ведре, чтобы вода могла вытекать из дырки:

挖了个洞,水从洞口流出来

Размер отверстия ствола фиксированный, поэтомуТакже фиксируется скорость, с которой вода вытекает из отверстия..

Итак, чтобы подвести итогПараметры, требуемые алгоритмомТолько два:

  • вместимость ковша
  • скорость утечки воды

Алгоритм дырявого ведра имеетдвавыполнить:

  1. Когда пакетный трафик не разрешен: Если скорость поступающей воды больше, чем скорость исходящей воды, излишки воды сразу сливаются. Например, мое ведро может вместить 100 литров, но скорость потока воды в моем ведре составляет 10 литров в секунду. В это время, если сейчас поступает 100 литров воды в секунду, я пропускаю в ведро только 10 литров воды, а остальные ограничены. (Ограничить скорость запроса)
  2. позволятьопределенныйСитуация с резким потоком: мое ведро может вместить 100 л. Если мое ведро сейчас пусто, то эти 100 л воды могут попасть в мое ведро. Я выливаю воду со скоростью 10 л/с.Если еще поступает 100 л воды, я могу только ограничить поток.

После проведенного выше анализа мы знаем, что:

Алгоритм дырявого ведра можетСглаживание всплесков трафика в сети(Поскольку скорость утечки воды фиксирована)

1.2 Что такое алгоритм ведра токенов

Теперь у меня есть другое ведро, это ведро не для воды, оно для жетонов:

桶子装着令牌

Токены будут выбрасываться в ведро с определенной скоростью, например, если я закину в ведро 10 токенов за одну секунду:

以一定的速率扔令牌进桶子

Существует верхний предел количества токенов, которое может храниться в корзине, например, моя корзина может содержать не более 1000 токенов.

Каждый раз, когда приходит запрос, он отправляется в корзину для получения токена.

  • Например, у меня в эту секунду 1001 запрос, и я иду в ведро, чтобы получить токены 1001. В это время могут возникнуть две ситуации:
    • В корзине нет 1001 токена, только 1000. Запрос, который не получает токен, можно только заблокировать (ожидание)
    • В корзине 1001 токен, и все запросы могут быть выполнены.

Поддержка алгоритма Token BucketВзрыв трафика в сети

**Разница между дырявым ведром и ведром с токенами: **Как видно из приведенного выше примера, дырявое ведро может обрабатывать запросы только с фиксированной скоростью, в то время как ведро с токенами может использовать максимальное количество токенов в ведре. , чтобы обработать запрос

Во-вторых, использование RateLimiter

RateLimiter — это токоограничивающий компонент Гуавы, этот токоограничивающий компонент используется в моей системе, что очень удобно в использовании.

Введите pom-зависимости:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>20.0</version>
</dependency>

RateLimiter этоНа основе алгоритма ведра токеновДа, API очень простой, см. следующую демонстрацию:

public static void main(String[] args) {
        //线程池
        ExecutorService exec = Executors.newCachedThreadPool();
        //速率是每秒只有3个许可
        final RateLimiter rateLimiter = RateLimiter.create(3.0);

        for (int i = 0; i < 100; i++) {
            final int no = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        //获取许可
                        rateLimiter.acquire();
                        System.out.println("Accessing: " + no + ",time:"
                                + new SimpleDateFormat("yy-MM-dd HH:mm:ss").format(new Date()));

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            };
            //执行线程
            exec.execute(runnable);
        }
        //退出线程池
        exec.shutdown();
    }

Мы видим из результатов, что только три могут быть выполнены в секунду:

每秒执行三个

3. Распределенное ограничение тока

RateLimiter — это автономный компонент ограничения тока, что делать, если это распределенное приложение?

Это может быть реализовано с помощью Redis + Lua, Общий код сценария lua выглядит следующим образом:

local key = "rate.limit:" .. KEYS[1] --限流KEY
local limit = tonumber(ARGV[1])        --限流大小
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > limit then --如果超出限流大小
  return 0
else  --请求数+1,并设置1秒过期
  redis.call("INCRBY", key,"1")
   redis.call("expire", key,"1")
   return current + 1
end

Код Java выглядит следующим образом:

public static boolean accquire() throws IOException, URISyntaxException {
    Jedis jedis = new Jedis("127.0.0.1");
    File luaFile = new File(RedisLimitRateWithLUA.class.getResource("/").toURI().getPath() + "limit.lua");
    String luaScript = FileUtils.readFileToString(luaFile);

    String key = "ip:" + System.currentTimeMillis()/1000; // 当前秒
    String limit = "5"; // 最大限制
    List<String> keys = new ArrayList<String>();
    keys.add(key);
    List<String> args = new ArrayList<String>();
    args.add(limit);
    Long result = (Long)(jedis.eval(luaScript, keys, args)); // 执行lua脚本,传入参数
    return result == 1;
}

объяснять:

  • Код Java передает ключ и параметр максимального ограничения в сценарий lua.
  • Выполните lua-скрипт (lua-скрипт определяет, превышает ли текущий ключ максимальный лимит)
    • Если превышает, вернуть 0 (текущий лимит)
    • Если не превышает, вернуть 1 (программа продолжает выполняться)

Источник ссылки:

Для получения дополнительной информации:

Наконец

рад вывестигалантерейные товарыОбщедоступный номер технологии Java:Java3y. В публичном аккаунтеБолее 200 оригинальных статейТехнические статьи, обширные видеоресурсы, красивые карты мозга,Следуйте, чтобы получить его!

转发到朋友圈是对我最大的支持!

Я думаю, что моя статья хорошо написана, нажмитеотличный!