我问过什么是SO上现在被社区删除的问题,为什么有人会使用javascript的问题Promise.race
,而一个高级用户则对此发表了评论:
如果您有两个计算某个值的服务,则可以并行查询它们,并使用第一个返回的值,而不是查询一个,等待失败,然后查询第二个。
我已经在冗余和这种用例上进行了全面的搜索,但是我什么也找不到,而且从我的POV中来看,如果不打算使用响应,只向服务器/服务添加工作负载绝不是一个好主意。
我问过什么是SO上现在被社区删除的问题,为什么有人会使用javascript的问题Promise.race
,而一个高级用户则对此发表了评论:
如果您有两个计算某个值的服务,则可以并行查询它们,并使用第一个返回的值,而不是查询一个,等待失败,然后查询第二个。
我已经在冗余和这种用例上进行了全面的搜索,但是我什么也找不到,而且从我的POV中来看,如果不打算使用响应,只向服务器/服务添加工作负载绝不是一个好主意。
Answers:
我认为这更多是经济学问题。但是,这是工程师应该能够做出的判断。因此,我在回答。
我将答案分为四个部分:
因此,有时您的客户端无法从服务器获得响应。我将假定这不是由于程序错误引起的(否则解决方案是要修复它,因此请执行此操作)。相反,这一定是由于您无法控制的偶然情况造成的。
但并非超出您的了解。您必须知道:
例如,如果失败和重试仅发生在大约2%的时间,则可能不值得解决。如果发生这种情况的时间大约是80%,那么...取决于...
客户需要等待多少时间?以及如何将其转化为成本...您看到的是,在常规应用程序中的延迟很小,可能没什么大不了的。如果这很重要,并且您有实时应用程序或在线视频游戏,那么这将使用户拒之门外,您可能最好投资更多或更好的服务器。否则,您可能会发出“正在加载”或“正在等待服务器”消息。除非延迟真的很大(大约几十秒),否则即使对于常规应用程序也可能太大。
正如我上面所说,解决这个问题有多种方法。我将假定您已经具有try-fail-retry循环工具。所以,让我们看看...
现在,请注意我说这些仍然可能失败。如果我们假设对一台服务器的查询有80%的失败机会,那么对两台服务器的并行查询有64%的失败机会。因此,您可能仍然需要重试。
选择较快的服务器并继续使用它的一个额外好处是,较快的服务器也不太可能由于网络问题而出现故障。
这提醒我,如果您能弄清请求失败的原因,请这样做。即使您无法防止失败,它也可以帮助您更好地管理情况。例如,您是否需要在服务器端提高传输速度?
多一点:
谁说您只需执行其中一项?您可以放置一条加载消息,查询分布在整个仓库中的多个服务器以选择更快的服务器,并仅在此之后使用它,然后在发生故障的循环中重试,并使这些服务器中的每一个成为具有负载平衡功能的计算机集群。为什么不?好吧,费用...
有四个费用:
您必须平衡它们。
例如,假设您每个满意的用户赚取大约1美元。您每天有3000个用户。请求失败约有50%的时间。并且当请求失败时,有2%的用户离开时不付费。这意味着您每天损失(3000 * 50%* 2%)30美元。现在,让我们说开发新功能将花费您100美元,部署服务器将花费您800美元-而忽略了运行时成本-这意味着您将获得((100 + 800)/ 30 ) 30天。现在,您可以检查预算并做出决定。
不要认为这些代表现实的价值,我出于数学上的考虑而选择它们。
附录:
事实是,如果您以固定成本的角度考虑问题,则可以估算所考虑策略的成本,然后使用此分析来确定。
凭经验培养直觉。我不建议每次都进行这种分析。有人这样做,没关系。我建议您对此有所了解,并为此建立直觉。
此外,在工程方面,除了我们从实际科学中获得的知识外,我们还在实践中学习并编写了哪些行之有效的指南。因此,明智的做法是了解最新技术水平……尽管有时您需要查看所在区域之外的地方。
在这种情况下,我将看在线视频游戏。它们具有加载屏幕,具有多个服务器,它们将根据延迟选择一个服务器,甚至可以允许用户切换服务器。我们知道这可行。
我建议这样做,而不是在每个请求上浪费网络流量和服务器时间,还要注意即使使用冗余服务器,也会发生故障。
如果客户端的时间比服务器上的时间更有价值,这是可以接受的。
如果客户需要快速准确。您可以证明查询多个服务器是合理的。如果收到有效答案,则取消请求非常好。
当然,咨询服务器的所有者/经理总是明智的。
我大多同意其他答案,但是我认为这在实践中应该很少见。我想分享一个更常见,更合理的示例,说明您何时使用Promise.race()
,几周前我碰巧使用了它(嗯,相当于python)。
假设您有一长串任务,有些可以并行运行,有些必须在其他任务之前运行。您可以开始所有不依赖项的任务,然后使用来等待该列表Promise.race()
。第一个任务完成后,您就可以启动任何依赖于该第一个任务的任务,然后Promise.race()
再启动新列表,再结合原始列表中未完成的任务。继续重复直到完成所有任务。
注意Javascript的API并不是为此而设计的。这几乎是最低限度的工作原理,并且您必须添加很多胶合代码。但是,我的意思是,类似这样的功能race()
很少用于冗余。当您实际上想要所有承诺的结果,但又不想等待所有承诺完成后再采取后续行动之前,它们就在那里。
new Promise
调用时立即启动,而在调用时不会重新启动Promise.race()
。一些promise实现是懒惰的,但是渴望更加普遍。您可以通过在控制台中创建登录到控制台的Promise进行测试。您会立即看到它的日志。然后把那个诺言传递给Promise.race()
。您会看到它不再记录。
除了技术方面的考虑之外,您还可能希望在实际业务模型中使用这种方法。
这种方法的变体在广告实时出价中相对常见。在此模型中,发布者(广告空间提供商)将要求广告商(广告提供商)针对特定用户的展示出价。因此,对于每一个这样的印象,你会查询每个广告主的订阅,发送的印象细节查询到每个广告商提供的端点(或者,运行作为自己的服务器上的端点由广告客户提供的脚本),赛车所有这些请求直到超时(例如100毫秒),然后采用最高出价,而忽略其他请求。
有助于减少客户等待时间的一个特定变体是使发布者允许出价的最低目标值,这样,超过该值的第一个广告客户出价将被立即接受(或者,如果没有一个出价超过该值)该值,将采用最大值)。因此,在这种变体中,第一个到达的查询可能会获胜,而另一个则会被丢弃,即使它们同样好甚至更好。