О HTTP-proxy, C10K и софте
Есть системный вызов sendfile (= splice который замыкает открытый на чтение сокет на открытый на запись.sendfile этого не делает. А что такое splice? Это из линукса?
замкнули один на другой — и контент поехал самостоятельно на другой сервера разомкнуть потом?
sendfile этого не делает. А что такое splice? Это из линукса?http://linux.die.net/man/2/splice :
Name
splice - splice data to/from a pipe
Synopsis
#define _GNU_SOURCE#include <fcntl.h>long splice(int fd_in, off_t *off_in,
int fd_out, off_t *off_out, size_t lenunsigned int " flags );
Description
splice moves data between two file descriptors without copying between kernel address space and user address space. It transfers up to len bytes of data from the file descriptor fd_in to the file descriptor fd_out, where one of the descriptors must refer to a pipe.
If fd_in refers to a pipe, then off_in must be NULL. If fd_in does not refer to a pipe and off_in is NULL, then bytes are read from fd_in starting from the current file offset, and the current file offset is adjusted appropriately. If fd_in does not refer to a pipe and off_in is not NULL, then off_in must point to a buffer which specifies the starting offset from which bytes will be read from fd_in; in this case, the current file offset of fd_in is not changed. Analogous statements apply for out_fd and off_out.
The flags argument is a bit mask that is composed by ORing together zero or more of the following values:
http://portal.acm.org/citation.cfm?id=511446.511449
http://haproxy.1wt.eu/download/1.3/doc/tcp-splicing.txt
И этот splicing встроен уже в HAProxy последних версий.
И этот splicing встроен уже в HAProxy последних версий.Где-то вчера находил вопрос про splice, заданный Сысоеву в рассылке, который ответил что у нгинкса это sendfile.
Судя по мануалу этот линуксовый splice односторонний, что сильно накладывает ограничения на его использование в прокси.
То, что ты хочешь, умеют делать всякие "чёрные ящики" за кучу денег.
а разомкнуть потом?А это вроде не нужно, "оно само".
Ну и я не специалист по низкоуровневым оптимизациям, я хочу аплоадить большие файлы, несколько Гб, на сервера, а все известные прокси почему-то сначала считывают весь запрос, а только потом обрабатывать начинают.
То есть в случае несколько Гб-ного файла нгинкс сначала сложит его себе на диск, только потом проксировать будет.
имхо, проще всего будет сделать так, чтобы аплоад-ссылка указывала сразу на бэкенд.
А это вроде не нужно, "оно само".Судя по ману, нужно указать длину, которая не всегда известна.
я хочу аплоадить большие файлы, несколько ГбА ты должен этого хотеть? В HTTP докачка хотя бы предусмотрена для этого случая?
То есть в случае несколько Гб-ного файла нгинкс сначала сложит его себе на диск, только потом проксировать будет.В принципе, идея для nginx правильная.
Потому что с одной стороны у него много медленных клиентов, а с другой - бекэнд, который ест сотни памяти на каждый запрос.
То есть надо, чтоб бекэнд быстро обработал запрос и освободил память для следующих, а клиент пусть не спеша скачивает/закачивает.
Судя по мануалу этот линуксовый splice односторонний, что сильно накладывает ограничения на его использование в прокси.Хм, почитал про HAProxy, действительно, вроде он splice использует только для отправки ответа клиенту. Наверно я плохо понимаю как оно работает.
Тем не менее, непонятно почему прокси типа нгинкса не умеет проксировать запрос не получив его целиком. Пусть без splice. Этому что-то мешает? "Черные ящики" (что это?) для этого не нужны?
И вопрос про API ко всей этой штуке: пусть не splice, пусть перекладывалка контента из одного сокета в другом не в ядре, но почему все прокси в принципе устроены по типу "конфиг-файл", не дают API для нормальной манипуляции запросами?
Судя по ману, нужно указать длину, которая не всегда известна.Написана в заголовке должна быть.
А ты должен этого хотеть? В HTTP докачка хотя бы предусмотрена для этого случая?
А что это меняет? У нгинкса как-то будет работать докачка, лучше чем у бэкенда?
Допустим, у меня прокси, за которым прокси, за которым бэкенд.
Потому что с одной стороны у него много медленных клиентов, а с другой - бекэнд, который ест сотни памяти на каждый запрос.
Нгинкс это не только вебсервер, это еще и прокси.
Я предполагаю, что просто такой сценарий использования, как у тебя, ещё никому не был настолько нужен, чтобы напрягаться из-за него.
Ну ты спрашиваешь, почему никто так не делает.Да, мне непонятно есть ли принципиальные ограничения и насколько сложно реализуемо то что я хочу.
Вопрос про overhead на API все равно интересен:
В нгинксе есть embedded Perl & embedded Lua, и мне непонятно зачем нужны хитрые конфигурационные трюки с nginx, например, если неблокирующие быстрые операции легко выразимы на том же lua — поменять заголовки запроса, например, поменять url и тп. — просто никому не приходит в голову написать такой простой прокси или он будет медленный, опять же?
Судя по мануалу этот линуксовый splice односторонний, что сильно накладывает ограничения на его использование в прокси.Какие все-таки ограничения?
нашел вот такие опции HAProxy:
option splice-auto
option splice-request
option splice-response
http://haproxy.1wt.eu/download/1.3/doc/configuration.txt
имхо, проще всего будет сделать так, чтобы аплоад-ссылка указывала сразу на бэкенд.Бэкендов много, они стоят за прокси как раз.
PS: Я извращенец.
у splice один из дескрипторов должен быть пайпом, чтоб передать на другой хост нужно два сплайса: в пайп и из пайпа. sendfile теперь так и работает со временным пайпом в ядре.
Бэкендов много, они стоят за прокси как раз.Конечно ссылка должна генериться. Чтобы на разные бэкенды попадала.
Думаю, что такая конфигурация как у тебя действительно не задумывалась авторами проксей, а все кто с ней сталкиваются делают примерно так, как я предлагаю.
Я вижу прокси который splice умеет делать во все стороны — HAProxy.
Я вижу что Nginx & Lighttpd его вызывают только когда выдают статику.
Поэтому, вроде, требуемое поведение реализуемо в принципе. Так?
Суть в том, что sendfile отдаёт файл, а потом мы снова имеем дескриптор сокета из которого можно читать и писать. Если же бы существовал системный вызов, который в ядре свяжет два сокета, то потом мы уже не сможем попасть внутрь этого соединения, мы уже перестанем быть прокси. А современный HTTP подразумевает несколько запросов в одном соединении, то есть в большинстве сценариев после обработки отдельного запроса, нужно опять иметь контроль над сокетом, чтобы прочитать следующий запрос.
но за два сискола через пайп который тут работает как ядерный буфер:
splice(in_sock, NULL, out_pipe, NULL, len, SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
splice(in_pipe, NULL, out_sock, NULL, size, SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
как-то так
А ты должен этого хотеть? В HTTP докачка хотя бы предусмотрена для этого случая?Может какой-нибудь WebDAV такое описывает и автору проще им воспользоваться?
Конечно внутри какой-то буфер будет, но быстрый.
Или ты говоришь что 2 системных вызова это долго.
Непонятно.
Как я себе это дело представляю:
splice говорит "перекидывать отсюда туда байты", когда данные заканчиваются или байты идут в обратную сторону — splice прерывается и возвращает значение — кол-во переданных байтов. Сокеты при этом никуда не деваются, можно вызвать на них splice в обратную сторону.
При таком представлении не понимаю чем splice мешает прокси.
И вопрос про оверхед на апи все еще интересен
Может какой-нибудь WebDAV такое описывает и автору проще им воспользоваться?Автору сложно воспользоваться WebDAV, так как он этот webdav реализует
или байты идут в обратную сторону — splice прерываетсяРазве такое в мане написано?
1. Почему не используют splice.
2. Почему так обращаются с контентом — не передают его сразу дальше. Даже опции такой нет.
3. Почему не делают нормальный API вместо конфигов.
как раз пытаюсь понять стоит ли копать в ту сторону — сколько надо копать чтобы решить такую проблемуА зачем тебе такое крутое вертикальное масштабирование? Мне кажется, что все вертикальные решения делаются дольше, устроены сложнее, содержат больше багов, и при этом всё равно ограничены.
Разве такое в мане написано?Там написано что можно указать количество байтиков, которые этот splice работает. Так вот, мы же знаем количество байтиков которые мы хотим отдать бэкенду.
Что будет если хочется в другую сторону записывать — не сказано.
Теоретически будет работать. Но имхо проще отучить прокси класть запрос на диск, а начать его отдавать по мере поступления.
Теоретически будет работать. Но имхо проще отучить прокси класть запрос на диск, а начать его отдавать по мере поступления.Про сплайс я спросил в связи с API:
Есть всякие асинхронные приблуды для Python, начиная со стандартного asyncore и до Tornado.
Там перекладывание данных реализуется как, грубо говоря, socket1.write(socket2.read(<кол-во байт>. Для меня пока загадка как быстро это работает для перелопачивания нескольких Гб по сравнению со splice и с буфером в том же nginx.
Для меня пока загадка как быстро это работает для перелопачивания нескольких Гб по сравнению со splice и с буфером в том же nginx.read+write - это одно лишнее копирование (или два? туплю)
скорость памяти представляешь - так что можешь понять, имеет ли смысл экономить на этом в твоей задаче
По идее аплоады 1 Гб это же тяжёлый, но редкий процесс. Обычно их не оптимизируют. Ну в смысле через диск конечно ахтунг, но через юзерленд память ничего страшного.
По идее аплоады 1 Гб это же тяжёлый, но редкий процесс. Обычно их не оптимизируют.Как раз дело в том что надо сделать сервис для upload и download файлов, причем больших. В нем кроме этого ничего особо и не будет.
Ну в смысле через диск конечно ахтунг, но через юзерленд память ничего страшного.
Понял.
Как раз дело в том что надо сделать сервис для upload и download файлов, причем больших.имхо, надо делать распределённую систему, а не вертикальную.
имхо, надо делать распределённую систему, а не вертикальную.Да. Но ее делать сложнее в условиях сжатых сроков и непонятной квалификации смежников. На распределенную систему надо еще уговорить. Занимаюсь.
Но даже при распределенной системе в Интернет должно что-то торчать. И перед бэкендами (пусть даже они лопатят данные) должно что-то стоять — балансировать, резервировать, от DDoS защищать, скорость соединения ограничивать и т.п.
Но даже при распределенной системе в Интернет должно что-то торчать. И перед бэкендами (пусть даже они лопатят данные) должно что-то стоять — балансировать, резервировать, от DDoS защищать, скорость соединения ограничивать и т.п.Ну так и должно быть. И только ссылка на сам аплоад должна идти прямо на бэкенд.
Оставить комментарий
pilot
Сейчас в моде асинхронная обработка входящих соединений и высоконагруженные приложения.То бишь сервер слушает какие происходят события на куче открытых сокетов и обрабатывает события по мере поступления, а не форкается или создает новый тред.
Есть системный вызов sendfile (= splice который замыкает открытый на чтение сокет на открытый на запись. Этот вызов хорошо использует HAProxy — прокси TCP.
Так вот, непонятно:
1) почему HTTP-proxy типа Nginx & Lighttpd используют его только изредка, для отправки статики.
Казалось бы хорошая схема: из открытого сокета прочитали HTTP-заголовки запроса, определились с тем куда запрос отправить, открыли сокет на запись, напихали в него заголовки, замкнули один на другой — и контент поехал самостоятельно на другой сервер.
2) Насколько серьезным будет overhead если дать при настройке proxy настройщику api (например, на lua — вроде быстрый и хорошо интегрируется то есть вызвать функцию:
на вход (сокет, HTTP-заголовки на выходе (сокет, HTTP-заголовки(по пути их можно изменить куда_посылать сервер открывает соединение к "куда посылать", пихает туда HTTP-заголовки, замыкает один сокет на другой и не парится больше.
Естественно, для полноценной работы нужна поддержка failover, балансировки нагрузки, подзапросов, но по такой же схеме эта проблема тоже решается.
Почему так не делают?