предисловие
Только лысая голова может стать сильнее.
Текст был включен в мой репозиторий GitHub, добро пожаловать, звезда:GitHub.com/Zhongf UC очень…
Когда я раньше учился, я не мог соприкоснуться с такими вещами, как высокий параллелизм/большой трафик, поэтому, конечно, я никогда не соприкасался с ограничением тока. При просмотре проекта компании мне показалось полезным ограничение по току (RateLimiter), и я, кстати, об этом узнал.
1. Введение в базовые знания об ограничении тока
Зачем ограничивать ток, я думаю, мне не нужно говорить больше.
- Например, я хожу в ресторан поужинать по выходным, нослишком много людейТеперь я могу только пойти на стойку регистрации, чтобы получить номер, и когда номер придет, я могу войти в ресторан на ужин. Что делать, если ресторан не ограничивает движение? Как только подошло время ужина, люди хлынули внутрь, а ресторан не мог вместить такое количество людей, поэтому легко было попасть в аварию (в ресторане было людно, и пройти было некуда. ресторан рухнул и не выдержал)
- То же самое относится и к миру кода.Сервер может обрабатывать ограниченное количество запросов.Если объем запросов особенно велик, нам нужно ограничить поток (либо дать запросу подождать, либо отбросить запрос)
В мире кодов есть два распространенных алгоритма ограничения тока:
- Алгоритм ведра токенов
- алгоритм дырявого ведра
1.1 Что такое алгоритм дырявого ведра
Например, теперь у меня есть ведро, зеленая часть — это емкость, в которую я могу вместить воду, если она превышает вместимость, которую я могу вместить, а затем налить воду в ведро, оно переполнится (ограниченный поток):
Что мы знаем на данный момент:
- Вместимость ведра фиксирована (зеленый на картинке)
- Если емкость ведра превышена, оно переполнится (либо подождите, либо сбросьте напрямую)
Хорошо, теперь выкапываем дырку в ведре, чтобы вода могла вытекать из дырки:
Размер отверстия ствола фиксированный, поэтомуТакже фиксируется скорость, с которой вода вытекает из отверстия..
Итак, чтобы подвести итогПараметры, требуемые алгоритмомТолько два:
- вместимость ковша
- скорость утечки воды
Алгоритм дырявого ведра имеетдвавыполнить:
- Когда пакетный трафик не разрешен: Если скорость поступающей воды больше, чем скорость исходящей воды, излишки воды сразу сливаются. Например, мое ведро может вместить 100 литров, но скорость потока воды в моем ведре составляет 10 литров в секунду. В это время, если сейчас поступает 100 литров воды в секунду, я пропускаю в ведро только 10 литров воды, а остальные ограничены. (Ограничить скорость запроса)
- позволятьопределенныйСитуация с резким потоком: мое ведро может вместить 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 оригинальных статейТехнические статьи, обширные видеоресурсы, красивые карты мозга,Следуйте, чтобы получить его!
Я думаю, что моя статья хорошо написана, нажмитеотличный!