metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2016-08-03 03:33 pm

"Асинхронный" http api

Вчера был на тусовке junolab, где их главные гуру рассказывали, как у них бекенд устроен.
В частности, на входе у них стоят гейтвеи с обычным http протоколом и минимальным набором фич - валидация, проверка авторизации по токенам и прочее такое, которые перекидывают запрос в MQ (nats.io).

При этом, насколько я понял, асинхронность там реализована поверх обычного http, без всяких http2, веб-сокетов и прочих не везде работающих протоколов - т.е. клиент api сначала делает запрос к гейтвею, ему сразу говорят - 200 ок, а потом он должен, по идее, дальше опрашивать гейтвей, пока для него из MQ придет ответ от микросервисов. Или у них там ответы от сервера бесконечно идут, я сходу не понял (т.е. ответ без content-length и соединение просто ждет пока придет что-нибудь, не помню, как эта техника называется).

В принципе, если keep-alive и соединение не обрывается - то реализация дуплексного протокола поверх синхронного http вроде приемлемая. Единственное, что в случае бесконечного ответа - если сервер и клиент долго ничего друг другу не говорят - промежуточные NAT и прочая сетевая муть могут соединение забыть, причем пока TCP keep-alive не проснется (а это два часа по умолчанию, вроде) - это обнаружено той стороной, которая молчит и ждет, не будет. Но теоретически это какие-то heart-beat слать можно со стороны сервера и запросы со стороны клиента.

[identity profile] falcrum.livejournal.com 2016-08-03 12:42 pm (UTC)(link)
Гм, "200 ок" - это "сообщение принято"? А в случае битого сообщения, которое не разобрать - что должен клиент дожидаться в ответе?

[identity profile] http://users.livejournal.com/_slw/ 2016-08-03 12:45 pm (UTC)(link)
это можно сделать двумя коннектами на тупом http/1.0:

по одному урлу получаем ответы, там клиент делает запрос "дай штонибудь, я такой-то!" и ждет до усрачки, у сервера тймаут минут в 15. если ничего нет -- он скажет через 15 минут "нет ничего", клиент переспросит.

кажется это называется long poll mode

по второму урлу клиент срет запросами, сервер сразу отдает queue id, по которому с первого урла будет получен результат.
тут все обычно.

даже кипалив нигде не нужен.

[identity profile] metaclass.livejournal.com 2016-08-03 12:52 pm (UTC)(link)
Я понимаю так - первично сообщение проверяется на корректность формата (json там парсится, токен на месте итп), иначе отлуп по 4хх с чем нибудь.
Если все ок - идет в MQ, а клиенту 200. То, что попавшее в MQ должно обязательно обработаться, вроде у них тестами покрыто (тестов у них там больше чем продакшен кода, по ходу).

[identity profile] filonov.livejournal.com 2016-08-03 01:09 pm (UTC)(link)
Chunked Encoding вполне позволяет отдать 200 ok и потом кормить данными потихоньку.

не совсем так

[identity profile] wildman.livejournal.com 2016-08-03 01:37 pm (UTC)(link)
> т.е. клиент api сначала делает запрос к гейтвею, ему сразу говорят - 200 ок, а потом он должен, по идее, дальше опрашивать гейтвей, пока для него из MQ придет ответ от микросервисов.

в общем случае:
- между клиентом и сервером постоянно (до траблов в сети, обрыва, окончания авторизированной сессии) висит HTTP persistent connections (HTTP keep-alive) == stream
- клиент api сначала делает запрос к гейтвею, ему сразу (после минимальных телодвижений по обеспечению персистента если оно нужно) говорят - 200 ок
- через некоторое время в stream прилетает ответ по запросу (json c `\n` терминаторами)

по этому каналу у нас для надежности раз в секунду летает `\n` (сделано и на уровне gateway и на уровне клиента в зависимости от направления стрима)

в сумме - у нас и клиенты и сервер считают что работают по асинхронному дуплекс каналу. транспортные проблемы изолированы по коду до состояния что переход на любой другой вариант (http2, websockets, raw tcp socket, etc.) затронет до сотни строк в фреймворке на бэкенде и по такому же кусочку в клиентах
Edited 2016-08-03 14:48 (UTC)

Re: не совсем так

[identity profile] http://users.livejournal.com/_slw/ 2016-08-03 03:03 pm (UTC)(link)
а смысл? ведь в такой схеме по одному каналу нельзя сделать больше одного запроса до получения ответа.

Re: не совсем так

[identity profile] wildman.livejournal.com 2016-08-03 03:19 pm (UTC)(link)
в смысле?
запросы - в одном канале (или стрим клиент-сервер или http реквест-респонс)
ответы - в другом

[identity profile] juan-gandhi.livejournal.com 2016-08-03 03:20 pm (UTC)(link)
Два часа как-то не звучит реалистично для человеческого интерефейса.

Идейка так-то хороша, но ведь по жизни уже все так делают. Никто не ждет "списка всех юзеров".

[identity profile] juan-gandhi.livejournal.com 2016-08-03 03:21 pm (UTC)(link)
Я что-то перестал понимать, это белорусский интернет такой, по 15 минут на реакцию?

[identity profile] wildman.livejournal.com 2016-08-03 03:24 pm (UTC)(link)
> в случае битого сообщения, которое не разобрать

- не тот encoding пейлоада - лесом на уровне гетвея
- отсутствует хидер с токеном - лесом на уровне гетвея
- токен не проходит валидацию (не раскодируется, истёк, etc.) - лесом на уровне гетвея
- секьюрити группа не подходит по пермишенам для этого эндпоинта - лесом на уровне гетвея
- не валидный payload (не валидный json) - лесом на уровне гетвея
- etc.

если это всё прошло - пейлоад дальше в недра backend согласно маппингу endpoint-microservice, и клиенту `200 OK`

если микросервис определяет что пейлоад не соответствует контракту - уже в стрим пойдёт бизнес-ошибка
Edited 2016-08-03 15:25 (UTC)

[identity profile] klonkaktusa.livejournal.com 2016-08-03 03:38 pm (UTC)(link)
https://en.wikipedia.org/wiki/Push_technology#Long_polling

[identity profile] http://users.livejournal.com/_slw/ 2016-08-03 03:47 pm (UTC)(link)
я такого нигде не говорил.

RE: Re: не совсем так

[identity profile] http://users.livejournal.com/_slw/ 2016-08-03 03:50 pm (UTC)(link)
в твоем описании наличие двух каналов очень завуалированно и на самом деле не видно (более того, утверждением "по этому каналу" подразумевает что канал только один).

[identity profile] metaclass.livejournal.com 2016-08-03 03:54 pm (UTC)(link)
Два часа это если не принимать мер - т.е. не гнать раз в несколько секунд какой-нибудь мелкий запрос для проверки "а живо ли наше подключение до сих пор".

[identity profile] juan-gandhi.livejournal.com 2016-08-03 04:13 pm (UTC)(link)
А. Ну это обычное ж дело. По мне так это просто синхронизация.

[identity profile] juan-gandhi.livejournal.com 2016-08-03 04:13 pm (UTC)(link)
Я так прочитал. :)

[identity profile] juan-gandhi.livejournal.com 2016-08-03 04:14 pm (UTC)(link)
А смысл-то поддерживать живую коннекцию, если апдейты раз в два часа?

[identity profile] nivanych.livejournal.com 2016-08-03 05:11 pm (UTC)(link)
Обычно нет смысла, наверное.
Но иногда, кто знает, мож важно получить сообщение от сервера с наименьшей задержкой?
Например, на пульте атомной станции! ;-)

[identity profile] http://users.livejournal.com/_slw/ 2016-08-03 05:52 pm (UTC)(link)
а вы оба в гугле работаете?

[identity profile] nivanych.livejournal.com 2016-08-03 05:58 pm (UTC)(link)
Кто "оба"?
Влад когда-то работал в гугле, я никогда там не работал.
Этот вопрос как-то связан с моим шутливым ответом? ;-)

[identity profile] berezovsky.livejournal.com 2016-08-03 06:01 pm (UTC)(link)
почему Влад отверг гугл

[identity profile] juan-gandhi.livejournal.com 2016-08-03 06:02 pm (UTC)(link)
А вот это другое дело. И тут нужно две коннекции как минимум. Как на порносайтах.

[identity profile] http://users.livejournal.com/_slw/ 2016-08-03 06:09 pm (UTC)(link)
влад? что-то я всегда думал что он вова.
а ответ...
ну так, конечно быстрее будет ответ получен.
но вовсе не в этом основной смысл у данной методики

[identity profile] nivanych.livejournal.com 2016-08-03 06:14 pm (UTC)(link)
NAME: Vlad Patryshev
Ну как же. Всего можно добится и вовсе тупым поллингом, но при этом ещё и больше сервер напрягать.
И вообще, сейчас это всё меньше имеет смысл.
Уже совсем мало используется браузеров, не умеющих веп-сокеты.

[identity profile] berezovsky.livejournal.com 2016-08-03 06:20 pm (UTC)(link)
прочитал "тупым троллингом"

надо завязывать с чтением интернетов

[identity profile] http://users.livejournal.com/_slw/ 2016-08-03 06:21 pm (UTC)(link)
новодел какой-то

2:5030/119 Vova Patryshev from SPb Russia 1993.12.10 - 1998.05.29

> Ну как же. Всего можно добится и вовсе тупым поллингом, но при этом ещё и больше сервер напрягать.

воот. нагрузка -- это основное

> Уже совсем мало используется браузеров, не умеющих веп-сокеты.

они не работают через прокси.
и вроде, через некоторых мобильных операторов

[identity profile] vp.livejournal.com 2016-08-03 06:41 pm (UTC)(link)
Меня больше интересует, есть ли сегодня какие-то реальные препятствия для работы веб-сокетов, с учетом, что сервер у нас всегда сервер, а клиенты у нас мобильные. Т.е. не строят ли операторы какие-то козни по противодействию этому.
Потому что все-таки это лучше делать веб-сокетами.

[identity profile] nivanych.livejournal.com 2016-08-03 06:58 pm (UTC)(link)
Напрягал сервер тупым троллингом.
;-) Прикольно!

[identity profile] metaclass.livejournal.com 2016-08-03 07:46 pm (UTC)(link)
Да не факт что всякие говно-прокси прозрачные и прочее такое их умеют.
И что-то мне говорили, что heart-beats в этих веб-сокетах тоже под вопросом, а без них - всякие блядские наты имеют свойство про коннект забывать.

И еще веб-сокеты непонятно кто из фреймворков умеет. Например, у нас http.sys и то что поверх него сделано - не умеет.

[identity profile] anonim-legion.livejournal.com 2016-08-04 07:51 pm (UTC)(link)
Я как-то раз отправил PM'у письмо с вопросом, от которого он сначала завис на полдня, разбираясь в вопросе, а потом сильно обиделся, потому что вопроса-то в сущности и не было.

[identity profile] berezovsky.livejournal.com 2016-08-05 03:52 am (UTC)(link)
затралел пма азазаза

[identity profile] chemodax.livejournal.com 2016-08-06 02:55 pm (UTC)(link)
Ждать до таймаута сервера может быть проблематично, если по дороге есть NAT ну или еще что-нить: если сервер дропнет connection, то клиент может не получить информации об: TCP FIN (или как он там называется) не будет получен, потому что NAT запись протухла. А клиент не узнает что connection умер, пока сам что-ить не начнет отправлять и не получит ACK в ответ. Можно использовать TCP keepalive, но не факт что все браузеры/intermediate proxy включают достаточно маленький TCP keepalive. Говорят что есть NAT-ы у которых дефолтная настройка таймаута 2 минуты.

[identity profile] http://users.livejournal.com/_slw/ 2016-08-06 03:27 pm (UTC)(link)
> Говорят что есть NAT-ы у которых дефолтная настройка таймаута 2 минуты.

мне кажется в такой жопе жить не стоит.
ну или тогда делать таймаут сервера 2 минуты.

[identity profile] chemodax.livejournal.com 2016-08-06 05:28 pm (UTC)(link)
Ну я так понимаю что start topic как раз и хочет чтобы работать и в жопе. А если того требования нет можно использовать WebScoket-ы или intermediate http responses (1xx)

[identity profile] http://users.livejournal.com/_slw/ 2016-08-06 05:58 pm (UTC)(link)
двух минутный таймаут у ната -- это не просто жопа, жопа жопы.
там и часть сайтов работать не будет и ssh и месанджеры...
в общем все будет очень плохо.

[identity profile] chemodax.livejournal.com 2016-08-06 06:21 pm (UTC)(link)
Я же не спорю что это плохо, но реальность такова. Я думаю не спроста Firefox использует 115 секунд для настройки TCP keep-alive.

[identity profile] http://users.livejournal.com/_slw/ 2016-08-06 06:24 pm (UTC)(link)
вообще-то 600

[identity profile] berezovsky.livejournal.com 2016-08-06 06:26 pm (UTC)(link)
где-то в петербурге один невзоров радуется этому комментарию

[identity profile] chemodax.livejournal.com 2016-08-06 06:28 pm (UTC)(link)
В интернетах пишут что поддержка вебсокетов появилась в IIS 8.0 (Win8/WS2012):
https://www.iis.net/learn/get-started/whats-new-in-iis-8/iis-80-websocket-protocol-support

Но в API http.sys при этом никаких изменений нет, что странно.

[identity profile] berezovsky.livejournal.com 2016-08-06 06:31 pm (UTC)(link)
пару тредиков взад у топикстартеров было про реальный сектор и двухтыщетретью простигосподи винду :-)

[identity profile] chemodax.livejournal.com 2016-08-06 06:35 pm (UTC)(link)
Был неправ -- перепутал с HTTP connection keep-alive (http.keep-alive.timeout) -- он 115 секунд. С TCP keep-alive сложнее, потому что там несколько параметров для "shot-lived" и "long-lived" коннектов.

[identity profile] chemodax.livejournal.com 2016-08-06 06:37 pm (UTC)(link)
Лично я этого конечно не могу понять, но знаю что достаточно много людей так живут.

[identity profile] http://users.livejournal.com/_slw/ 2016-08-06 06:40 pm (UTC)(link)
беглый взгляд в сырцы ничего такого не показывает.

[identity profile] chemodax.livejournal.com 2016-08-06 06:51 pm (UTC)(link)
Я исходники не проверял, но у меня в about:config настройки есть.

[identity profile] chemodax.livejournal.com 2016-08-06 06:54 pm (UTC)(link)
Можно и так, но для этого надо убедиться что в RFC есть требования что intermediate proxy не могут буфферизовать chunk-ы, а должны их перенаправлять as-is. Но еще есть антивирусы которые иногда очень фривольно обращаются с HTTP траффиком.

[identity profile] sergiej.livejournal.com 2016-08-08 07:55 pm (UTC)(link)
Мне казалось это стандарт давно. Два коннекшна, на одном запрашиваем чего нужно, на втором всё время читаем поток ответов. Регулярно "передёргиваем" если долго ничего не просили или не получали. Масса мессенджеров и нотификаторов всяких так работает.