TCP, dealing with packet loss
Сокет закрывай на сервере (ты же его открываешь до форка, да?)
Закрывай сокет через 2 минуты. Это стандартное решение. Не самое крутое, но учитывающее, что TCP работает не вакууме и требуется время на "гарантированную" доставку.Дельный совет, я бы ещё заметил, что сначала вычитывай запрос, потом только форкайся (оно вообще насколько надо? пул тредов не подойдёт?). Соотв. в таком случае ты не будешь форкаться для не дошедших запросов.
Или может быть можно наоборот со стороны сервера не однократно засыпать на 0.7 секунд, а десять раз засыпать на 0.1 секунды и как-нибудь заставлять сокет послать недвусмысленные намёки клиенту, что дескать не дошло же предыдущее?а зачем засыпать вообще? у тебя какая-то мутная сетевая часть, делаешь какие-то странные многоходовки, с чем это связано?
Ты не понял.
Мне вообще как бы хочется уложиться в 0.7 секунды!
То есть типа если между этими двумя машинами roundtrip time порядка пары миллисекунд, то это вполне разумное желание, да?
А дефолтный retransmit timeout там то ли секунда, то ли вообще три. Мне не хочется ждать пакет три секунды. Если на пакет не получен ack через десять миллисекунд, значит, скорее всего пакет потерялся. Ну ладно, сто миллисекунд меня тоже вполне устроят. Но не три секунды же! У меня вообще лимит обработки всего запроса — 8 секунд по стандарту, и это дурное соединение между двумя машинами как бы совсем не то место, где я хотел бы тратить отпущенное мне время!
Поэтому я говорю: меня TCP в общем устраивает архитектурно, но в моих условиях (локальная сеть, чувствительность к латенси) мне бы хотелось уменьшить все таймауты в тридцать раз скажем.
Или имплементировать какой-нибудь грязный хак, чтобы получить нужный эффект — но какой? Вот скажем если я как-то умудрюсь послать три пустых пакета следом, а проебётся только первый, то duplicate ACKs would trigger Fast Retransmit, но это какой-то долбоебизм.
Или может кто-нибудь знает где взять ручную реализацию чего-нибудь tcp-подобного поверх udp, заточенную под low latency connections, на C или C++?
Или может кто-нибудь знает где взять ручную реализацию чего-нибудь tcp-подобного поверх udp, заточенную под low latency connections, на C или C++?Думаю, что в твоём странном случае это может быть выходом. По крайней мере сложного тут ничего нет, и трафик сильно уменьшится, так как большинство пакетов будут ходить без подтверждения.
сначала вычитывай запрос, потом только форкайс
В моей ситуации это называется "доёбываться до мышей". Все затраты на форканье, вычитывание запросов и прочую хуиту покрываются первым же запросом к базе данных.
Там ничего не _тормозит_ (то есть производительности хватает). Там у чуваков кривая сетка в тестовой системе в которой один пакет из десятка тысяч проёбывается, вместо того, чтобы его перепослать сразу, комп с клиентом тупит три секунды (согласно стандарта TCP! а сервер при виде этого нервничает и закрывает сокет. А чуваки при виде этого нервничают и не хотят апгрейдить систему в продакшене.
а зачем засыпать вообще?Ну, потому что если запрос не пришёл через какое-то вменяемое время, нужно как бы перестать ждать и завершить процесс наверное.
Мутных многоходовок в той системе достаточно, но это — не одна из них, кажется.
Не, я могу плюнуть на всё и увеличить там таймаут до скажем семи секунд, но блин, как-то это криво и не по нраву мне!
Поэтому я говорю: меня TCP в общем устраивает архитектурно, но в моих условиях (локальная сеть, чувствительность к латенси) мне бы хотелось уменьшить все таймауты в тридцать раз скажем.Ты сам себе противоречишь. TCP тебя не устраивает. Всё что там есть, оно годами отлажено, вылизано и оптимизировано под определённое использование. Ты же хочешь другого, но с помощью TCP.
Может тебе какие ещё транспортные протоколы посмотреть, там вроде какой-то SCTP ещё был и DCCP, правда не знаю какие "фичи" они предоставляют.
автора мог бы немного спасти T/TCP (TCP for Transactions
но его никто не стал писать почему-то.
а DCCP шо за зверь?
Мне не хочется ждать пакет три секунды. Если на пакет не получен ack через десять миллисекунд, значит, скорее всего пакет потерялся. Ну ладно, сто миллисекунд меня тоже вполне устроят. Но не три секунды же! У меня вообще лимит обработки всего запроса — 8 секунд по стандарту, и это дурное соединение между двумя машинами как бы совсем не то место, где я хотел бы тратить отпущенное мне время!вообще, неужели правда нигде нет ручки для этого таймаута.
она же никак идеологически не затрагивает TCP, если я правильно понимаю.
вот в этом вопрос автора.
тут нужен практикующий ежедневную настройку TCP-стека чел.
Там ничего не _тормозит_ (то есть производительности хватает). Там у чуваков кривая сетка в тестовой системе в которой один пакет из десятка тысяч проёбывается, вместо того, чтобы его перепослать сразу, комп с клиентом тупит три секунды (согласно стандарта TCP! а сервер при виде этого нервничает и закрывает сокет. А чуваки при виде этого нервничают и не хотят апгрейдить систему в продакшене.Я теперь лучше понял что происходит.
Точно никакого UDP, потому что такие радикальные шаги обернутся только новыми граблями и костылями.
Таймаут не пересылку пакета скорее всего можно в ядре или настроить, или константу написать другую. Вопрос, надо ли?
Что означает "чуваки при виде этого нервничают и не хотят апгрейдить систему в продакшене"? Это критичные запросы? Просто для критичных запросов принято дольше ждать чем 0.7 секунды, а при некритичных — можно и проебать, никто не станет переживать.
для каждой системы свои по идее
ручки должны бытьТак это... setsockopt вроде как.
для каждой системы свои по идее
а DCCP шо за зверь?А хз. Я про другие протоколы мало знаю. Навскидку назвал пару названий которые помню.
есть разве такая опция?
Вот будут у тебя совсем другие RTT и потери.
Или имплементировать какой-нибудь грязный хак, чтобы получить нужный эффект — но какой?Собственный туннель, чтобы реализовывал перепосылку на низком уровне.
Если ты знаешь, что собственно обработку запроса сервер быстро выполняет, и повторное выполнение одного и того же запроса - не проблема.
Делаешь на клиенте таймаут - если ответ не пришёл вовремя, закрываешь сокет, и ещё раз всё по новой.
Это критичные запросы? Просто для критичных запросов принято дольше ждать чем 0.7 секундыНу, вот ты засовываешь карточку в банкомат и банкомат посылает запрос своему банку, тоже по tcp/ip, кстати. В банке запрос попадает в некую программную систему, которая при помощи Оракла открывает коннекшен к особому демону (у меня такое ощущение, что система собственно и состоит из кучи скриптов внутри Оракли!) и пересылает ему командную строку вида "./sslc 172.16.19.13 3434 |1231|1233123123|3123123123123|312123123|123123|12312313123|". Демон эту командную строку исполняет и пересылает обратно её stdout когда она завершается, sslc — это и есть мой "клиент" (только писал его не я, а какие-то мудаки и пидарасы, а я в нём исправляю баги). sslc парсит командную строку, составляет запрос в каком-то ISO формате, коннектится к серверу (который писали те же пидарасы и в котором я тоже исправляю баги) и посылает ему этот запрос. Сервер форкается, его сын принимает и парсит запрос, патчит там пару полей, засовывает запись в БД (на этот раз Постгрес собирает запрос опять, засовывает его в UNIX Message Queue и посылает сигнал ещё одному процессу, который тоже запущен сервером. Тот процесс достаёт мессагу из очереди и посылает её в следующую систему с которой у него постоянное соединение (тоже tcp/ip типа для аппрувала, типа таким образом всё синхронизируется опять. Потом ответ передаётся в обратном направлении.
THIS! IS! ENTERPRISE!
Впрочем, я до сих пор не очень представляю, какой именно тёмный культ призывает подобных ктулху, у нас тоже есть всякий маразм, но далеко не такой суровый. Причём я бы понимал, если б от этого надёжность возрастала или ещё что-то, так ведь нет, all links in this chain are weakest, от любого неосторожного движения всё по очереди валится в корку если не чего похуже, того, кто дал этим пидарасам в руки C надобно повесить за яйца!
Ну так вот, на всё про всё есть восемь секунд по всяким Визовским стандартам. А вообще лучше бы чтобы и побыстрее происходило, понятно. Когда в середине процесса очередной совершенно бессмысленный обмен данными внезапно добавляет три секунды задержки, это как бы не очень хорошо, наверное. Совершенно бессмысленные три секунды задержки, 100мс было бы достаточно даже для интернетов in this day and age, оно же всё адаптивное, подчеркну!
Ладно, пох, я ещё почитал всякого, поразмыслил и решил, что мне влом что-нибудь придумывать, скажу чувакам чтобы опустили глобальные minimal and initial retransmit delays на серверах до 500мс и наоборот подняли таймаут на именно это соединение в настройках проги до 4 секунд (на случай если они забудут подпатчить задержки в продакшене, лол). Я начинаю овладёвывать Энтерпрайзным Подходом, кажется!
а DCCP шо за зверь?Надо уже CCCP.
меня вполне устраивает TCP как таковое, вот только если б можно было как-нибудь уменьшить все таймауты раз в 10 или 100!TCP весь описан в RFCях. По RTO читаем RFC2988, так как ничего новее по теме не было (не считая F-RTO, но это как раз наоборот )
...В линуксе у нас
In some situations it may be beneficial for a TCP sender to be more
conservative than the algorithms detailed in this document allow.
However, a TCP MUST NOT be more aggressive than the following
algorithms allow.
...
(2.4) Whenever RTO is computed, if it is less than 1 second then the
RTO SHOULD be rounded up to 1 second.
Traditionally, TCP implementations use coarse grain clocks to
measure the RTT and trigger the RTO, which imposes a large
minimum value on the RTO. Research suggests that a large
minimum RTO is needed to keep TCP conservative and avoid
spurious retransmissions [AP99]. Therefore, this
specification requires a large minimum RTO as a conservative
approach, while at the same time acknowledging that at some
future point, research may show that a smaller minimum RTO is
acceptable or superior.
#define TCP_RTO_MIN unsignedHZ/5
и ручек нет, ибо не должно их хотеть.
Я год назад делал свой недо-tcp layer в пару тыщ LOC, делал RTO 50ms, вроде жила система и весь стек, но у меня, например, гарантированно не было роутеров и прочего посередине между сервером на CAN и клиентом на Ethernet кроме Ethernet2CAN конвертера на rt-оське и витой пары 2 метра длиной, ибо embedded. В cruel world такое лучше не пускать, причина описана в приведённом куске rfc - флууууудеров и/или нервно обрывающих коннект через 200ms надо специально любить в каком-нибудь изолированном от детей месте.
Я год назад делал свой недо-tcp layer в пару тыщ LOC, делал RTO 50ms, вроде жила система и весь стек, но у меня, например, гарантированно не было роутеров и прочего посередине между сервером на CAN и клиентом на Ethernet кроме Ethernet2CAN конвертера на rt-оське и витой пары 2 метра длиной, ибо embedded. В cruel world такое лучше не пускать, причина описана в приведённом куске rfc - флууууудеров и/или нервно обрывающих коннект через 200ms надо специально любить в каком-нибудь изолированном от детей месте.ну у него специфический случай, в гугле есть саксесс-стори чувака из кетая,
который пересобрал ядро с TCP_RTO_MAX в 10 секунд.
не понятно, насколько свое ядро увеличит суммарный ЭНТЕРПРАЙЗ, правда.
а что это за банк, говоришь?
а что это за банк, говоришь?Это была достаточно большая хреновина, туда кладут живого человека, вращают и сканируют, МРТ называется. По схеме выше шёл только control flow, конечно.
По схеме выше шёл только control flow, конечно.ыыы!
Research suggests that a large minimum RTO is needed to keep TCP conservative and avoid spurious retransmissions [AP99].вооот! а ты можешь на пальцах объяснить этот ресерч?
и ручек нет, ибо не должно их хотеть.
(2.4) Whenever RTO is computed, if it is less than 1 second then the RTO SHOULD be rounded up to 1 second.если я правильно понимаю, в сети, в которой максимальное время прихода ответного ACK-а сильно меньше секунды (как у фж правило округления RTO вверх до 1 секунды сильно тормозит потерявшиеся пакеты. возможна ли такая потеря на физическом уровне? может ли сеть физически работать стабильно кроме каждого десятитысячного пакета, который просто исчезает (пенартурово гамма-излучение)?
Spurious retransmission timeouts cause suboptimal TCP performanceМои имхо:
because they often result in unnecessary retransmission of the last
window of data.
если я правильно понимаю, в сети, в которой максимальное время прихода ответного ACK-а сильно меньше секунды (как у фж правило округления RTO вверх до 1 секунды сильно тормозит потерявшиеся пакеты.
Да, это так. Но тех же линуксовых 200ms вполне должно хватать, к сожалению не скажу детали, как их получить наверняка, лишь то, что это destination-зависимое значение, которое эмпирически высчитывается, следовательно в силе только при длительном, и скорее всего частом, обмене данными.
возможна ли такая потеря на физическом уровне?Абсолютно возможна, более того, это должна быть причина 100% потерь при ненагруженных сетевых девайсах и нормальной реализации стека поверх них, просто администратор Вася сделал слишком маленький радиус закругления витой пары в офисе на углах, например.
Да, оно уже так и есть
может ли сеть физически работать стабильно кроме каждого десятитысячного пакета, который просто исчезает (пенартурово гамма-излучение)?
Research suggests that a large minimum RTO is needed to keep TCP conservative and avoid spurious retransmissions [AP99]Ну, я это видел, но у меня есть сильное подозрение, что не то они лечат этим, ох не то и ох не так.
То есть, как я понимаю, spurious retransmissions это когда мы например захуячили 100 пакетов сразу, подождали 100мс, не дождались ни одного ацка, и тут же захуячили эти 100 пакетов ещё раз, потому что у каждого из них внезапно экспайрнулся таймер. И ещё раз, через 200мс. Тут начинают приходить ацки про первые сто пакетов, но поскольку seq у каждого батча одинаково росли от 1 до 100, мы понятия не имеем, на какие именно из наших три раза посланных пакетов нам наконец пришли ацки. Ну и типа аццкий флуд и угар.
Но там же это, и так уже есть разные клёвые штуки вроде Slow Start, которые это должны предотвращать как бы. Типа, нужно послать одинокий пакет — ну, посылаем, и ещё раз через 100мс, и ещё раз через 200мс, наконец приходит ацк, дальше экспериментируем с посылкой двух пакетов и ждём уже 300мс на всякий случай.
Плюс Fast Retransmit для ситуаций когда теряется один пакет в ситуации когда у нас уже стабилизировалось окошко в десять пакетов шириной например: вдруг приходят два или три ацка, которые все сообщают, что ждут 117 пакет. Ага, думаем мы, 117 пакет проебался, но раз ацки приходят, значит, пакеты после 117 дошли, надо перепослать только его для начала прям сразу не дожидаясь его таймаута, и продолжать слать новые.
Перепосылка одного пакета как бы не может зафлудить сетку, каким бы маленьким начальное значение RTO не было, если оно растёт экспоненциально. Вот уже есть фишки, которые в общем-то довольно надёжно гарантируют, что стрёмные ситуации могут приводить только к перепосылке одного пакета.
Так почему у нас по-прежнему по дефолту используется трёхсекундный таймаут (и 0.2 секунды в линуксе, если я правильно понимаю где значение "три секунды" было определено методом научного тыка во времена когда 56кбод модемы стоили штуку баксов?
Алсо, кстати почитал про SCTP, там ручка для настройки этих таймаутов таки доступна on per socket basis, via setsockopt, но SCTP отсутствует в дефолтной поставке HP-UX, что как бы наводит на мысли атакже предвещает баттхёрт при попытке объяснить чувакам, как (а главное, зачем) его надобно ставить.
а что это за банк, говоришь?
лол, не скажу!
и ручек нета в линуксе в маршрутах можно задавать какие-то rtt и rttvar, это не то?
а что это за банк, говоришь?Какая разница? Они же все такие.
а в линуксе в маршрутах можно задавать какие-то rtt и rttvar, это не то?Да, это косвенно как раз об этом, но нельзя зафиксировать значения, только дать начальное и оценку вариации.
попытаться поправить сетку совсем не вариант ?
Проблема в том, что сетка в том месте, где это происходит, не очень хорошая, и иногда запрос от клиента теряется.
А какого размера сообщения туда-обратно? Т.к. если они совсем небольшие (до MTU то TCP — это явно overkill, мне кажется.
: ну, пара сотен байт... Видишь ли, оверкиллы бывают важные и неважные. Технический оверкилл (количество фич, которые я не использую, но которые still incur overhead) меня тут не волнует абсолютно, потому как не боттлнек ни разу и ни в какой возможной будущей ситуации не может внезапно стать боттлнеком. А вот написание собственного велосипеда на базе UDP было бы абсолютно необоснованным оверкиллом с организационной, так сказать, точки зрения.
Видишь ли, оверкиллы бывают важные и неважные. Технический оверкилл (количество фич, которые я не использую, но которые still incur overhead) меня тут не волнует абсолютно, потому как не боттлнек ни разу и ни в какой возможной будущей ситуации не может внезапно стать боттлнекомНу вот ты говоришь, что тебя не волнует overkill, который привносит tcp. Но та проблема, что у тебя стоит — не что иное, как следствие этого overkill-а.
Тебе достаточно послать туда-обратно всего 2 пакета, а ты посылаешь 9. Если есть потери, то 9 пакетов проще сломаются, чем 2. UPD можно перепослать (хоть это и дополнительная работа а в TCP придётся мириться с таймаутами или чинить сессию как-нибудь, но это уже тоже дополнительная работа, причём она скорее всего будет системно-зависима и неизвестно как поведёт себя при изменениях в реализации TCP.
Оставить комментарий
bleyman
Есть две программы на двух компьютерах. Клиент коннектится к серверу, посылает немножко данных, shutdown(sock, SHUT_WR после чего ждёт ответа. Сервер слушает клиентов, при виде клиента форкается, в чайлде ждёт запроса 0.7 секунд, обрабатывает запрос, посылает ответ, закрывает сокет.Вот как выглядит нормальный обмен:
Проблема в том, что сетка в том месте, где это происходит, не очень хорошая, и иногда запрос от клиента теряется.
Что видит клиент:
Что видит сервер:
Вроде всё понятно, да?
Вопрос в том, как сделать чтобы потеря пакета не ломала всё нафиг? Видимо, 0.7 секунд недостаточно чтобы клиент решил ретрансмитнуть пакет, сколько будет достаточно и есть ли общепринятые средства ускорения этого (btw, client runs on a recent enough HP-UX, server runs on RHEL5)? Вот например можно общесистемно делать вещи вроде ndd -get /dev/tcp tcp_rexmit_interval_initial_lnp (и ещё парочка похожих параметров). А можно как-нибудь из конкретной программы конкретную настройку для себя сделать? В man 7 tcp вроде ничего похожего нет...
Или может быть можно наоборот со стороны сервера не однократно засыпать на 0.7 секунд, а десять раз засыпать на 0.1 секунды и как-нибудь заставлять сокет послать недвусмысленные намёки клиенту, что дескать не дошло же предыдущее?
Конструировать велосипед на основе UDP что-то очень не хочется, меня вполне устраивает TCP как таковое, вот только если б можно было как-нибудь уменьшить все таймауты раз в 10 или 100!