Hello! On Thu, Dec 26, 2019 at 02:05:51AM +0500, Илья Шипицин wrote:
> чт, 26 дек. 2019 г. в 01:13, Maxim Dounin <mdou...@mdounin.ru>: > > > Hello! > > > > On Thu, Dec 26, 2019 at 12:32:04AM +0500, Илья Шипицин wrote: > > > > > ср, 25 дек. 2019 г. в 23:20, Maxim Dounin <mdou...@mdounin.ru>: > > > > > > > Hello! > > > > > > > > On Wed, Dec 25, 2019 at 02:58:15PM +0500, Илья Шипицин wrote: > > > > > > > > > ср, 25 дек. 2019 г. в 14:38, Sergey Kandaurov <pluk...@nginx.com>: > > > > > > > > > > > > > > > > > > On 24 Dec 2019, at 23:35, Илья Шипицин <chipits...@gmail.com> > > wrote: > > > > > > > > > > > > > > привет! > > > > > > > > > > > > > > допустим, такая ситуация. есть POST запрос, у него есть хедеры и, > > > > > > собственно, тело запроса. мы отправили хедеры на бекенд, тело не > > успели > > > > > > отправить, и бекенд нам сделал TCP RST. > > > > > > > > > > > > > > должен ли такой POST повторно отправляться, если не указан > > > > > > non_idempotent ? (судя по моим экспериментам - не отправляется. но > > ведь > > > > > > тело не было отправлено ? значит мы должны попасть под условие, что > > > > такой > > > > > > запрос можно отправить повторно ?) > > > > > > > > > > > > Как только мы успешно установили соединение и перешли к отправке > > > > запроса > > > > > > (не важно, успели начать отправку тела или нет), запрос считается > > > > > > отправленным, > > > > > > т.к. в общем случае мы не знаем, был ли он обработан или нет. > > > > > > > > > > > > > > > > я предлагаю такую логику. > > > > > бекенд умеет отличать полностью полученный запрос от неполного > > запроса > > > > > (например, по Content-Length) > > > > > навряд ли бекенд будет обрабатывать неполностью полученный запрос > > > > > > > > > > и считать отправленными только полностью отправленные запросы > > > > > > > > Считать-то можно, но у бекенда может быть своё мнение по этому > > > > вопросу. Каких-либо явных утверждений в RFC 2616 / RFC 7231, > > > > которые бы говорили о том, что так можно - я в своё время не > > > > нашёл. И по факту так скорее всего нельзя, так как на тело > > > > бекенду во многих случаях может быть наплевать. > > > > > > > > > > есть достаточно странный кейс, когда отправляется POST без тела. не > > > конкретно в наших приложениях, а в принципе. > > > я по некоторым разбирался, зачем так делают (ну то есть, можно же GET, но > > > специально сделали POST). ответ меня поразил - > > > по RFC нельзя кешировать POST. ну и чтобы наверняка без кеша, мы выбрали > > > POST )) ну а тело ... надо не надо было > > > > > > в описанном выше случае, действительно, тело (запроса) не предполагалось. > > > > > > если тело предполагается, но не было отправлено, допустим бекенд > > вменяемый, > > > что вполне может быть. он запрос не обработал. > > > можно ретраить. > > > > > > каких-то явных противоречий в этом не вижу > > > > Явных противоречий тут и нет: скорее всего бекенд смотрит на тело, > > и в тех немногих случаях, когда мы точно знаем, что оно отправлено > > не полностью - скорее всего можно ретраить. > > > > > Однако проблем тут две: > > > > - "Скорее всего можно" - не значит "точно можно", наступить на > > ситуацию, когда бекенд на тело не смотрит - на практике вполне > > можно. И каких-либо явных причин требовать от бекенда, чтобы > > смотрел - я, как я уже писал выше, не вижу, и если у такого > > бекенда вдруг что-то пойдёт не так - виноват будет nginx. (Если эти > > причины вдруг есть - с удовольствием ознакомлюсь с соответствующей > > цитатой из RFC.) > > > > - Условие "когда мы точно знаем" не выполняется приблизительно > > никогда: в подавляющем большинстве случаев тело вместе с > > запросом уже сложено в буфер сокета, и что там с ним стало > > дальше - узнать невозможно. То есть мы про микрооптимизацию > > оцень небольшого процента запросов. > > > > > ну вот у меня ситуация, когда я знаю, что можно. > рассказываю. > > берем IIS. на нем хостим ASP.NET > ASP.NET хостится в т.н. AppPool, у этого пула есть режим "пул остановлен" > > можно настроить пул на HttpLevel, либо на TcpLevel, в первом случае > остановленный пул отдает 503, во втором tcp rst. > > вы хотели RFC ? оно есть у меня. смотрите, есть такой хидер Expect. смотрим > RFC, там сказано, что он End-to-End. > итак, рассмотрим цепочку > > Браузер --> nginx --> IIS > > браузер посылает Expect: 100-Continue, по RFC nginx должен его доставить до Какой именно браузер? Из известных мне клиентов - 100-continue шлёт только curl. > IIS ? но этого не происходит. > IIS (и http.sys под капотом) ответил бы Expect, и у nginx была бы инфа, что > запрос не успел отправиться Не было бы: запрос _успел_ отправиться. Тело запроса бекенд не принял - но это вопросы к бекенду, и что он там успел сделать по этому запросу, перед тем как сломаться - вопрос к бекенду. > но nginx не отправляет Expect. И, скорее всего, в ближайшее время не будет. В частности потому, что никто, кроме curl'а этого не поддерживает. Но это отдельный разговор, и он имеет очень мало отношения к обсуждаемому вопросу. > и POST улелает в остановленный пул. если пул настроен на HttpLEvel, то пул > отдает 503 уже после отправки (были бы Expect-ы, отдал бы до). > > ок, меняем режим пула на TcpLevel, пул должен сделать tcp rst. и он его > сделает. но! нюанс. после отправки хидеров. > объяснение простое, на порту, на котором слушает IIS, могут быть несколько > приложений (пулов), чтобы понять, в какой именно пул мы попали, нужно поле > Host. > > но я точно знаю, что tcp rst идет до отправки тела. и nginx это точно знает. Как я уже говорил, в большинстве случаев nginx ничего не знает - тело и заголовки он отправляет вместе. И если connect() к бекенду успешно прошёл - то он просто запишет в буфер сокета запрос целиком. То есть так или иначе ни 503, ни закрытие соединения после его принятия - работать не будут. В большинстве случаев у nginx'а вообще нет информации о том, отправилось ли тело на бекенд, или нет, и даже если она есть - нет оснований считать, что запрос, у которого не отправилось тело, можно отправить куда-то ещё повторно. > а разработчики, которые пишут идеальные приложения ... ну я тоже люблю > фантазировать. В данном конкретном случае есть совсем простое решение: убирать бекенды из балансировки перед тем, как их ломать. -- Maxim Dounin http://mdounin.ru/ _______________________________________________ nginx-ru mailing list nginx-ru@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-ru