Я спросил, что теперь является вопросом, удаленным сообществом, на SO о том, почему кто-то использует javascript Promise.race
, и пользователь с высокими репутациями прокомментировал это:
Если у вас есть две службы, которые вычисляют какое-то значение, вы можете запрашивать их обе параллельно и использовать, какое значение всегда возвращается первым, вместо того, чтобы запрашивать одно, ожидать сбоя и затем запрашивать второе.
Я погуглил по поводу избыточности и этого варианта использования в целом, но ничего не смог найти, и из моего POV никогда не было бы хорошей идеей просто добавить рабочую нагрузку на сервер / службу, если вы не собираетесь использовать ответ.
programming-practices
Аделин
источник
источник
Ответы:
Я бы сказал, что это больше вопрос экономики. Тем не менее, это призыв к суждению, который должен сделать инженер. Следовательно, я отвечаю.
Я делю свой ответ на четыре части:
Управление рисками
Таким образом, иногда ваш клиент не может получить ответ от сервера. Я предполагаю, что это не из-за программной ошибки (в противном случае решение состоит в том, чтобы исправить это, так что иди и сделай это). Вместо этого, это должно быть из-за случайной ситуации вне вашего контроля ...
Но не за пределами ваших знаний. Ты должен знать:
Например, если сбой и повторная попытка происходят только около 2% времени, вероятно, не стоит их устранять. Если это происходит в 80% случаев, хорошо ... зависит ...
Сколько времени клиент должен ждать? И как это приводит к затратам ... вы видите, у вас небольшая задержка в обычном приложении, это, вероятно, не имеет большого значения. Если это важно, и у вас есть приложение в реальном времени или онлайн-видеоигра, это отвлечет пользователей, и вам, вероятно, лучше инвестировать в большее или большее количество серверов. В противном случае вы, вероятно, можете поместить сообщение «загрузка» или «ожидание сервера». Если задержка действительно велика (порядка десятков секунд), то она может быть слишком большой даже для обычного применения.
Стратегии
Как я уже говорил выше, есть несколько способов решения этой проблемы. Я предполагаю, что у вас уже есть реализация цикла try-fail-retry. Итак, давайте посмотрим ...
Теперь обратите внимание, я говорю, что они все еще могут потерпеть неудачу. Если предположить, что запрос к серверу имеет 80% вероятности сбоя, то параллельный запрос к двум серверам имеет 64% вероятности сбоя. Таким образом, вам все равно придется повторить попытку.
Дополнительным преимуществом выбора более быстрого сервера и его дальнейшего использования является то, что более быстрый сервер также менее подвержен сбоям из-за проблем с сетью.
Что напоминает мне, если вы можете выяснить, почему запрос не выполнен, сделайте это. Это может помочь вам лучше управлять ситуацией, даже если вы не можете предотвратить сбои. Например, вам нужна большая скорость передачи на стороне сервера?
Еще немного:
И кто сказал, что вы должны сделать только один из них? Вы можете поместить сообщение о загрузке, запросить несколько серверов, которые распределены по всему миру, чтобы выбрать более быстрый и использовать его только после этого, при повторной попытке сбоя в цикле, и чтобы каждый из этих серверов был кластером машин с балансировкой нагрузки , Почему нет? Ну, стоит ...
Расходы
Есть четыре стоимости:
Вы должны сбалансировать их.
Например, допустим, вы зарабатываете около доллара на одного довольного пользователя. Это у вас 3000 пользователей в день. То, что запросы терпят неудачу около 50% времени. И это 2% пользователей уходят без оплаты, когда запрос не удается. Это означает, что вы теряете (3000 * 50% * 2%) 30 долларов в день. Теперь предположим, что разработка новой функции обойдется вам в 100 долларов, а развертывание серверов обойдется вам в 800 долларов, а игнорирование затрат времени выполнения означает, что вы получите возврат инвестиций в ((100 + 800) / 30. ) 30 дней. Теперь вы можете проверить свой бюджет и принять решение.
Не считайте эти ценности представительными для реальности, я выбрал их для удобства математики.
Дополнения:
Дело в том, что если вы рассматриваете проблему с точки зрения балансирования затрат, вы можете оценить стоимость стратегий, которые вы рассматриваете, и использовать этот анализ для принятия решения.
Интуиция
Интуиция, если воспитывается на опыте. Я не предлагаю проводить такой анализ каждый раз. Некоторые люди делают, и это нормально. Я предлагаю вам иметь некоторое понимание этого и выработать интуицию для этого.
Кроме того, в области машиностроения, помимо знаний, которые мы получаем от реальной науки, мы также учимся на практике и собираем рекомендации о том, что работает, а что нет. Поэтому часто бывает мудро увидеть, в каком состоянии находится искусство ... хотя иногда вам нужно видеть за пределами своего района.
В этом случае я бы посмотрел на онлайн видеоигры. У них есть экраны загрузки, у них есть несколько серверов, они выбирают сервер в зависимости от времени ожидания, и они могут даже позволить пользователю переключать серверы. Мы знаем, что работает.
Я бы предложил сделать это вместо того, чтобы тратить сетевой трафик и серверное время на каждый запрос, а также помнить, что даже с резервным сервером может произойти сбой.
источник
Это приемлемо, если время клиента более ценно, чем время на сервере.
Если клиент должен быть быстрым и точным. Вы можете обосновать запрос нескольких серверов. И приятно отменить запрос, если получен действительный ответ.
И, конечно же, всегда полезно проконсультироваться с владельцами / менеджерами серверов.
источник
Эта техника может уменьшить задержку. Время ответа сервера не является детерминированным. В масштабе, вероятно, будет по крайней мере один сервер, показывающий плохое время отклика. Поэтому все, что использует этот сервер, также будет иметь низкое время отклика. Отправляя сообщения на несколько серверов, вы снижаете риск разговора с плохо работающим сервером.
Затраты включают в себя дополнительные трафики в сети, потерю обработки сервера и сложность приложения (хотя это может быть скрыто в библиотеке). Эти затраты могут быть уменьшены путем отмены неиспользованных запросов или краткого ожидания перед отправкой второго запроса.
Вот один документ , а другой . Я помню, как читал статью о Google и их реализацию.
источник
Я в основном согласен с другими ответами, но я думаю, что это должно быть чрезвычайно редко на практике. Я хотел бы поделиться гораздо более распространенным и разумным примером того, когда вы будете использовать
Promise.race()
, то, что мне довелось использовать это пару недель назад (ну, эквивалент Python).Скажем, у вас есть длинный список задач, некоторые из которых могут выполняться параллельно, а некоторые должны выполняться раньше других. Вы можете запустить все задачи без зависимостей, а затем подождать в этом списке с помощью
Promise.race()
. Как только первая задача завершится, вы можете запустить любые задачи, которые зависели от этой первой задачи, иPromise.race()
снова в новом списке в сочетании с незавершенными задачами из исходного списка. Продолжайте повторять, пока все задачи не будут выполнены.Обратите внимание, что API Javascript не идеально подходит для этого. Это почти тот минимум, который работает, и вы должны добавить немало клея. Однако я хочу сказать, что подобные функции
race()
редко используются для резервирования. Они предназначены в первую очередь для тех случаев, когда вы действительно хотите получить результаты всех обещаний, но не хотите ждать завершения всех из них, прежде чем предпринимать последующие действия.источник
new Promise
вызывается, и не перезапускаются приPromise.race()
вызове. Некоторые реализации обещаний ленивы, но стремление встречается гораздо чаще. Вы можете проверить, создав обещание в консоли, которое регистрируется в консоли. Вы увидите это журналы сразу. Тогда передайте это обещаниеPromise.race()
. Вы увидите, что он не регистрируется снова.В дополнение к техническим соображениям вы можете использовать этот подход, когда он является частью вашей реальной бизнес-модели.
Вариации этого подхода относительно распространены в ставках в реальном времени на рекламу. В этой модели издатель (поставщик рекламного пространства) попросит рекламодателей (поставщиков рекламы) сделать ставку на показ определенного пользователя. Таким образом, для каждого такого показа вы должны запросить каждого из подписчиков рекламодателя, отправив запрос с деталями показа в конечную точку, предоставленную каждым рекламодателем (или, в качестве альтернативы, сценарий, предоставленный рекламодателем в качестве конечной точки на ваших собственных серверах), участвуя в гонке. все эти запросы до тайм-аута (например, 100 мс), а затем принимают самую высокую ставку, игнорируя остальные.
Конкретный вариант этого, который помогает сократить время ожидания клиента, состоит в том, чтобы издатель разрешил минимальное целевое значение для ставки, чтобы первая ставка рекламодателя, превышающая это значение, была немедленно принята (или, если ни одна из ставок не превышает значение, максимальное будет принято). Таким образом, в этом варианте первый поступающий запрос может быть выигран, а другой - отброшен, даже если он такой же хороший или даже лучший.
источник