Архитектура серверной части с высокой степенью параллелизма — ограничение тока

Java задняя часть алгоритм

В начале проектирования система будет иметь расчетную емкость, и если она превысит пороговое значение TPS/QPS, которое система может выдерживать в течение длительного времени, система может быть перегружена, и в конечном итоге всей службы будет недостаточно. Чтобы избежать этой ситуации, нам нужно ограничить поток интерфейсных запросов.

Целью текущего регулирования является защита системы путем ограничения скорости одновременных запросов на доступ или количества запросов в течение временного окна.После достижения ограничения скорости обслуживание может быть отклонено, поставлено в очередь или отложено.

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

Контролируйте количество параллелизма Он относится к относительно распространенному методу ограничения тока и может быть реализован с помощью механизма семафора (такого как семафор в Java) в практических приложениях. Например, мы предоставляем сервисный интерфейс для внешнего мира, максимально допустимое количество параллелизма равно 10, а код реализован следующим образом:

public class DubboService {    private final Semaphore permit = new Semaphore(10, true);    public void process(){        try{
            permit.acquire();            //业务逻辑处理

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            permit.release();
        }
    }
}

В коде, несмотря на то, что выполняется 30 потоков, разрешено только 10 одновременных исполнений. Конструктор семафора Semaphore(int Permits) принимает целое число, представляющее количество доступных разрешений. Semaphore(10) означает, что 10 потокам разрешено получать лицензии, то есть максимальное количество одновременных потоков равно 10. Использование Semaphore также очень простое.Сначала поток использует метод Acquire() Semaphore для получения лицензии, а затем вызывает метод release() для возврата лицензии после использования.Вы также можете использовать метод tryAcquire(), чтобы попытаться получить лицензию. лицензия.

контроль скорости доступа В нашей инженерной практике для реализации этого режима обычно используется алгоритм Token Bucket. Другие алгоритмы, такие как алгоритмы дырявого ведра, также могут управлять скоростью, но они мало используются в нашей инженерной практике и не будут здесь представлены. Пожалуйста, узнайте сами.

В Википедии алгоритм ведра токенов описывается следующим образом:

Токен добавляется в корзину каждую 1/r секунды.

В ведре хранится не более b токенов.Если ведро заполнено, новые размещенные жетоны будут удалены.

Когда приходит N-байтовый пакет, потребляйте N токенов, а затем отправляйте пакет.

Если доступных токенов в ведре меньше n, то пакет будет помещен в буфер или отброшен.

Сегмент токенов контролирует объем данных, проходящих через временное окно.На уровне API то, что мы часто называем QPS и TPS, — это точно количество запросов или транзакций во временном окне, но временное окно ограничено 1 с. Поместите токен в ведро с постоянной скоростью, и если запрос необходимо обработать, вам нужно сначала получить токен из ведра и отказать в обслуживании, когда в ведре нет токена. Еще одним преимуществом ведра для токенов является то, что скорость можно легко изменить.

В нашей инженерной практике мы обычно используем Ratelimiter в Guava для контроля скорости, например, мы не хотим отправлять более 2 задач в секунду:


//速率是每秒两个许可final RateLimiter rateLimiter = RateLimiter.create(2.0);

void submitTasks(List tasks, Executor executor) {    for (Runnable task : tasks) {
        rateLimiter.acquire(); // 也许需要等待
        executor.execute(task);
    }
}

Блок управления запрашивает временное окно При определенных сценариях мы хотим ограничить определенный интерфейс или для каждого сервиса // каждый день количество запросов в минуту или количество вызовов. Например, ограничьте количество вызовов службы в секунду до 50, чтобы добиться следующего:


import com.google.common.cache.CacheBuilder;import com.google.common.cache.CacheLoader;import com.google.common.cache.LoadingCache;import java.util.concurrent.ExecutionException;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicLong;

    private LoadingCache<Long, AtomicLong> counter =
            CacheBuilder.newBuilder()                    .expireAfterWrite(2, TimeUnit.SECONDS)                    .build(new CacheLoader<Long, AtomicLong>() {
                        @Override
                        public AtomicLong load(Long seconds) throws Exception {
                            return new AtomicLong(0);
                        }
                    });

    public static long permit = 50;

    public ResponseEntity getData() throws ExecutionException {

        //得到当前秒
        long currentSeconds = System.currentTimeMillis() / 1000;
        if(counter.get(currentSeconds).incrementAndGet() > permit) {
            return ResponseEntity.builder().code(404).msg("访问速率过快").build();
        }
        //业务处理

    }
    ```
关于限流部分到此就结束了,下一篇将介绍降级和熔断机制。