Задний план
У Echo Nest есть API с ограничением скорости. Данное приложение (идентифицированное в запросах с использованием ключа API) может выполнять до 120 вызовов REST в минуту. Ответ службы включает в себя оценку общего количества вызовов, сделанных за последнюю минуту; повторное злоупотребление API (превышение лимита) может привести к отзыву ключа API.
При использовании с одной машины (веб-сервера, предоставляющего услуги клиентам) легко контролировать доступ — сервер полностью знает историю запросов и может правильно себя регулировать.
Но я работаю над программой, в которой распределенные независимые клиенты делают запросы параллельно.
В таком случае гораздо менее ясно, каким будет оптимальное решение. И вообще проблема представляется неразрешимой - если более 120 клиентов, все без какой-либо истории, одновременно сделают первоначальный запрос, то скорость будет превышена.
Но так как это личный проект, и ожидается, что клиент будет пользоваться им спорадически (всплесками), а мои проекты никогда не были очень успешными, это не должно стать серьезной проблемой. Более вероятная проблема заключается в том, что бывают случаи, когда меньшее количество клиентов хочет сделать много запросов как можно быстрее (например, клиенту может потребоваться в виде исключения сделать несколько тысяч запросов при первом запуске - возможно два клиента запустятся примерно в одно и то же время, поэтому они должны сотрудничать, чтобы разделить доступную полосу пропускания).
Учитывая все вышеизложенное, какие алгоритмы подходят для клиентов, чтобы они правильно ограничивали скорость? Обратите внимание, что ограниченное сотрудничество возможно, поскольку API возвращает общее количество запросов в в последнюю минуту для всех клиентов.
Текущее решение
Мое текущее решение (когда вопрос был написан - в качестве ответа дается лучший подход) довольно простое. У каждого клиента есть запись о времени последнего звонка и количестве вызовов, сделанных за последнюю минуту, согласно отчету API для этого звонка.
Если количество вызовов меньше 60 (половина лимита), клиент не дросселирует. Это позволяет выполнять быстрые всплески небольшого количества запросов.
В противном случае (т. е. когда имеется больше предыдущих запросов) клиент вычисляет предельную скорость, с которой он должен работать (т. е. period = 60 / (120 - number of previous requests)
), а затем ждет, пока разрыв между предыдущим вызовом и текущим временем не превысит этот период (в секундах; 60 секунд в в минуту; не более 120 запросов в минуту). Это эффективно снижает скорость, так что, если бы он действовал один, он не превышал бы предел.
Но у вышеперечисленного есть проблемы. Если вы внимательно все обдумаете, то увидите, что при большом количестве запросов один клиент колеблется и не достигает максимальной пропускной способности (отчасти это происходит из-за «начального всплеска», который внезапно «выпадает за пределы окна», а отчасти потому, что алгоритм не полностью использует свою историю). И несколько клиентов будут сотрудничать до некоторой степени, но я сомневаюсь, что это оптимально.
Лучшие решения
Я могу представить себе лучшее решение, которое использует полную локальную историю клиента и моделирует других клиентов, скажем, со скрытой марковской моделью. Таким образом, каждый клиент будет использовать отчет API для моделирования других (неизвестных) клиентов и соответствующей корректировки своей скорости.
Я также могу представить алгоритм для одного клиента, который постепенно переходит от неограниченного поведения для небольших всплесков к оптимальному, ограниченному поведению для многих запросов без возникновения колебаний.
Существуют ли такие подходы? Может ли кто-нибудь предоставить реализацию или ссылку? Может ли кто-нибудь придумать лучшую эвристику?
Я предполагаю, что это известная проблема где-то. В какой области? Теория очереди?
Я также предполагаю (см. комментарии ранее), что оптимального решения не существует и что могут быть какие-то знания/традиции/принятые эвристики, которые хорошо работают на практике. Я хотел бы знать, что... В данный момент я изо всех сил пытаюсь определить подобную проблему в известных сетевых протоколах (я полагаю, что у Перлмана было бы какое-то красивое решение, если это так).
Я также заинтересован (в меньшей степени, для дальнейшего использования, если программа станет популярной) в решении, которое требует центрального сервера для облегчения совместной работы.
Отказ от ответственности
Этот вопрос вовсе не предназначен для критики Echo Nest; их обслуживание и условия использования великолепны. Но чем больше я думаю о том, как лучше всего это использовать, тем сложнее/интереснее это становится...
Кроме того, у каждого клиента есть локальный кеш, используемый для предотвращения повторных вызовов.
N
запросов и получает разрешение на выполнениеK <= N
запросов в течение следующихt
секунд. Затем, при желании, сервер может расставить приоритеты клиентов в зависимости от того, сколько запросов они хотят сделать и для чего. - person Steve Jessop   schedule 28.08.2012