1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/sogou-workflow

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
about-timeout.md 15 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 01.03.2025 10:20 552780a

Оповещение о времени ожидания

Чтобы все задачи связи работали точно в соответствии с ожиданиями пользователя, мы предоставляем множество возможностей для конфигурирования времени ожидания и гарантируем его точность.
Некоторые значения времени ожидания являются глобальными, например время ожидания соединения, но вы можете использовать функцию upstream для установки своего времени ожидания соединения для конкретного домена.
Есть также задачно-зависимые значения времени ожидания, такие как время ожидания полной отправки сообщения. Поскольку пользователи должны динамически настраивать это значение в зависимости от размера сообщения.
Конечно, сервер имеет свои общие настройки времени ожидания. В целом, настройка времени ожидания является сложной задачей, которую мы стараемся выполнять максимально точно.
Все значения времени ожидания используют стиль опроса, то есть они представлены целыми числами в миллисекундах, где -1 указывает на бесконечное время ожидания.

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

Базовая конфигурация времени ожидания для связи

В файле EndpointParams.h можно найти следующее:

struct EndpointParams
{
    size_t max_connections;
    int connect_timeout;
    int response_timeout;
    int ssl_connect_timeout;
};

static constexpr struct EndpointParams ENDPOINT_PARAMS_DEFAULT =
{
    .max_connections        = 200,
    .connect_timeout        = 10 * 1000,
    .response_timeout       = 10 * 1000,
    .ssl_connect_timeout    = 10 * 1000,
};

Среди этих значений, связанных с временем ожидания, приведены три:

  • connect_timeout: время ожидания для установления соединения с целью. По умолчанию равно 10 секундам.
  • response_timeout: время ожидания ответа от цели. По умолчанию равно 10 секундам. Это представляет собой время ожидания успешной отправки сообщения цели или чтения данных от цели.
  • ssl_connect_timeout: время ожидания завершения SSL рукопожатия. По умолчанию равно 10 секундам.

Эта структура представляет базовую конфигурацию для соединения связи, которая будет использоваться практически во всех последующих конфигурациях связи.

Глобальная конфигурация времени ожидания

В файле WFGlobal.h можно найти информацию о глобальной конфигурации:

struct WFGlobalSettings
{
    EndpointParams endpoint_params;
    unsigned int dns_ttl_default;
    unsigned int dns_ttl_min;
    int dns_threads;
    int poller_threads;
    int handler_threads;
    int compute_threads;
};

static constexpr struct WFGlobalSettings GLOBAL_SETTINGS_DEFAULT =
{
    .endpoint_params    =    ENDPOINT_PARAMS_DEFAULT,
    .dns_ttl_default    =    12 * 3600,    /* in seconds */
    .dns_ttl_min        =    180,          /* reacquire when communication error */
    .dns_threads        =    8,
    .poller_threads     =    2,
    .handler_threads    =    20,
    .compute_threads    =    -1
};
//compute_threads <= 0 means auto-set by system CPU count

Среди этих значений, связанных с временем ожидания, приведено одно — EndpointParams endpoint_params.

Метод изменения глобальной конфигурации заключается в выполнении операций перед вызовом любого из наших заводских функций:

int main()
{
    struct WFGlobalSettings settings = GLOBAL_SETTINGS_DEFAULT;
    settings.endpoint_params.connect_timeout = 2 * 1000;
    settings.endpoint_params.response_timeout = -1;
    WORKFLOW_library_init(&settings);
}

Пример выше изменяет время ожидания соединения на 2 секунды и время ожидания ответа на бесконечное. При такой конфигурации каждая задача должна иметь настроенный параметр времени ожидания для получения полного сообщения, чтобы избежать попадания в бесконечное ожидание.
Глобальные значения времени ожидания могут быть переопределены для отдельных адресов с помощью функции upstream, например, можно указать свое время ожидания соединения для определенного домена.
У каждого AddressParams в upstream также имеется параметр EndpointParams endpoint_params, который используется аналогично глобальному.
Для более подробной информации см. документацию upstream.

Конфигурация времени ожидания для сервера

В примере http_proxy были рассмотрены начальные конфигурации сервера. Среди значений времени ожидания приведены следующие:

  • peer_response_timeout: этот параметр совпадает с глобальным response_timeout и указывает на время ожидания ответа от удаленной машины. По умолчанию равен 10 секундам.
  • receive_timeout: время ожидания получения полного запроса. По умолчанию равно -1.
  • keep_alive_timeout: время жизни соединения. По умолчанию равно одной минуте. Для redis сервера — пяти минутам.
  • ssl_accept_timeout: время ожидания завершения SSL рукопожатия. По умолчанию равно 10 секундам.

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

Конфигурация времени ожидания уровня задачи

Конфигурация времени ожидания уровня задачи осуществляется через несколько методов сетевой задачи:

template <class REQ, class RESP>
class WFNetworkTask : public CommRequest
{
...
public:
    /* Все значения в миллисекундах. timeout == -1 для бесконечного времени ожидания. */
    void set_send_timeout(int timeout) { this->send_timeo = timeout; }
    void set_receive_timeout(int timeout) { this->receive_timeo = timeout; }
    void set_keep_alive(int timeout) { this->keep_alive_timeo = timeout; }
    void set_watch_timeout(int timeout) { this->watch_timeo = timeout; }
...
}

Из этого следует:

  • set_send_timeout(): устанавливает время ожидания для полной отправки сообщения. По умолчанию равно -1.
  • set_receive_timeout(): действует только для задач клиента и указывает на время ожидания получения полного ответа от сервера. По умолчанию равно -1.
  • server задачи имеют receive_timeout в конфигурации запуска сервера. Установка receive_timeout для server задачи не имеет смысла, так как сообщение уже получено.set_keep_alive() позволяет установить время ожидания для поддержания соединения. Обычно фреймворк хорошо управляет этим процессом, поэтому пользователю не требуется его использование.
    Если используется протокол HTTP, клиент или сервер могут использовать короткие соединения путем добавления HTTP заголовков. Избегайте использования этого метода для изменения этого поведения.
    Если клиент Redis хочет закрыть соединение после запроса, он должен использовать этот метод. Очевидно, что установка set_keep_alive() в callback недействительна (соединение уже повторно использовано).

set_watch_timeout() предназначен для задач клиента и представляет собой максимальное время ожидания первого ответного пакета после отправки запроса.
Используя watch timeout, можно избежать ограничений response timeout и receive timeout для некоторых задач клиентов, ожидающих данных.
После установки watch timeout, начинается расчет receive timeout с момента получения первого пакета.

Синхронное ожидание времени ожидания задачи

Еще одна очень специфическая конфигурация времени ожидания — единственный глобальный синхронный параметр времени ожидания. Мы не рекомендуем его использование, но в некоторых случаях он может обеспечить хорошую производительность.
По умолчанию, целевые серверы имеют лимит на количество соединений (который можно настроить глобально и для upstream). Если соединения достигли лимита, задача клиента обычно завершается ошибкой.
В callback task->get_state() вернет WFT_STATE_SYS_ERROR, а task->get_error() вернет EAGAIN. Если задача была настроена на повторную отправку, она автоматически будет повторена.
Здесь мы позволяем использовать метод task->set_wait_timeout(), чтобы настроить синхронное время ожидания. Если соединение освободилось за это время, задача сможет занять это соединение.
Если пользователь настроил wait_timeout и не получил соединение до истечения времени, в callback будет получен статус WFT_STATE_SYS_ERROR и ошибка ETIMEDOUT.

class CommRequest : public SubTask, public CommSession
{
public:
    ...
    void set_wait_timeout(int wait_timeout) { this->wait_timeout = wait_timeout; }
};

Получение причин времени ожидания

Задачи связи содержат метод get_timeout_reason(), который возвращает причину времени ожидания. Однако, эта информация не слишком детализирована и включает следующие значения:

  • TOR_NOT_TIMEOUT: не время ожидания.
  • TOR_WAIT_TIMEOUT: синхронное время ожидания.
  • TOR_CONNECT_TIMEOUT: время ожидания соединения. Включает в себя все типы соединений TCP, SCTP и SSL.
  • TOR_TRANSMIT_TIMEOUT: любое время ожидания передачи. Нельзя различить, связано ли это с этапом отправки или приема. В будущем возможно дальнейшее разделение.
    • Для задач server причина времени ожидания всегда будет TRANSMIT_TIMEOUT, и это будет связано с этапом отправки ответа.

Реализация функционала времени ожидания

Внутри фреймворк должен обрабатывать больше типов времени ожидания, чем те, которые показаны здесь. Все, кроме wait_timeout, зависят от событий таймера Linux timerfd или kqueue.
Каждый поток опроса содержит timerfd, и по умолчанию число потоков опроса равно четырем, что должно удовлетворять большинство приложений.
Текущий алгоритм времени ожидания использует структуры данных типа список и красно-черное дерево, что делает время выполнения между O(1) и O(log n), где n — это количество fd в потоках опроса.
Обработка времени ожидания в настоящее время не является бутылочным горлышком, поскольку вызовы epoll в ядре Linux также имеют временную сложность O(log n), и переход к O(1) для всех случаев времени ожидания не принес бы существенного улучшения.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/sogou-workflow.git
git@api.gitlife.ru:oschina-mirror/sogou-workflow.git
oschina-mirror
sogou-workflow
sogou-workflow
master