HeadlinesBriefing favicon HeadlinesBriefing.com

Принципы для быстрых приложений на Tokio

Hacker News •
×

Я возвращаюсь с Rust Conf. На Unconf у нас была продуктивная дискуссия об отладке и бенчмаркинге асинхронных приложений. Было поделено много интересных идей. Я пытаюсь перечислить некоторые из них здесь, вместе с некоторыми моими собственными опытами. Это первый черновик того, что, я надеюсь, может стать живым документом лучших практик. Не стесняйтесь открыть issue или отправить PR. Я также надеюсь добавить пример приложения в ближайшие дни, демонстрирующий эти проблемы вместе с тем, как выглядит trace dial9.— Russell

Существует мало жёстких и неизменных правил для написания кода, который хорошо работает на рантаймах Tokio; ответ на многие вопросы — «зависит от ситуации». Производительность рабочей нагрузки зависит от того, что ещё работает на рантайме в этот момент. Именно поэтому так много проблем проявляется только в продакшене! Написание асинхронных приложений с хорошей производительностью — это баланс между справедливостью и батчингом, конкуренцией и изоляцией. Этот пост излагает некоторые общие принципы и охватывает исключения, где я могу. Он предполагает базовое знакомство с work-stealing рантаймом Tokio; общее резюме включено в приложении.

Общие принципы

Сначала определите, есть ли у вас проблема. Если вы начнёте искать тревожные сигналы в приложении на Tokio, вы их найдёте. Почти каждое реальное приложение, которое я видел, имеет polls намного длиннее 10-100 микросекунд, которые рекомендует Alice Ryhl в своём превосходном посте What is Blocking?. Эти проблемы могут или не могут влиять на метрики или поведение приложения, которые вас действительно волнуют. Важно работать в обратном направлении от реальной метрики, которую вы пытаетесь улучшить. Например, приложение может иметь длинные polls, которые полностью безвредны; их «исправление» не окажет измеримого влияния на пользовательские метрики. В подавляющем большинстве проблем, с которыми я сталкивался, проблема была в самом коде приложения, часто во взаимодействии между несколькими компонентами распределённой системы (а не собственно в Tokio). dial9 дал много видимости в Tokio; по крайней мере так же часто, как он находит проблему Tokio, он фактически ясно демонстрирует её отсутствие. Конечно, иногда это проблема Tokio. Что касается метрик Tokio, наиболее полезной является недавно добавленная гистограмма задержки планирования (schedule latency). Задержка планирования — это количество времени между тем, как ваша задача готова к выполнению, и тем, как Tokio фактически выполняет poll future. Хотя это не скажет вам, в чём причина, задержка планирования является наиболее распространённым симптомом плохого взаимодействия между Tokio и вашим кодом.

Разделяйте для задержки, группируйте для пропускной способности. Делайте yield чаще, чтобы оптимизировать задержку. Низкая задержка при множестве запросов требует справедливости между соединениями. Рассмотрите Redis (или любое приложение, поддерживающее pipelining запросов). Наивная реализация будет читать данные напрямую из соединения, пока доступно больше данных. Когда запросы pipelined, весь pipelined запрос окажется в буфере в памяти. Когда вы читаете из него frames, каждый будет Poll::Ready без возврата к сети. Это создаёт как длинные polls, так и несправедливость между клиентами. Влияние на пропускную способность обычно меньше: обрабатывается то же количество запросов. Однако задержка меняется кардинально, потому что целый pipeline может ждать за другим. Явный yield после каждого запроса может снизить задержку примерно в 10× в этом примере. Вы можете сделать ещё лучше, делая yield только после нескольких последовательных немедленно готовых чтений.

Ключевые сущности: Компании: Tokio, Redis | Люди: Russell, Alice Ryhl | Места: Rust Conf