Чтобы все задачи связи работали точно в соответствии с ожиданиями пользователя, мы предоставляем множество возможностей для конфигурирования времени ожидания и гарантируем его точность.
Некоторые значения времени ожидания являются глобальными, например время ожидания соединения, но вы можете использовать функцию 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()
позволяет установить время ожидания для поддержания соединения. Обычно фреймворк хорошо управляет этим процессом, поэтому пользователю не требуется его использование.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 )