Ограничение скорости вызовов для API с использованием кеша в ColdFusion

Привет, я использую ColdFusion для вызова api last.fm, используя пакет cfc, полученный из здесь.

Я обеспокоен превышением лимита запросов, который составляет 5 запросов на исходящий IP-адрес в секунду, в среднем за 5-минутный период.

В пакете cfc есть центральный компонент, который вызывает все остальные компоненты, которые разделены на разделы, такие как «исполнитель», «трек» и т. Д. Этот центральный компонент «lastFmApi.cfc». инициируется в моем приложении и сохраняется в течение всего срока службы приложения

// Application.cfc example
    <cffunction name="onApplicationStart">
        <cfset var apiKey = '[your api key here]' />
        <cfset var apiSecret = '[your api secret here]' />

        <cfset application.lastFm = CreateObject('component', 'org.FrankFusion.lastFm.lastFmApi').init(apiKey, apiSecret) />
    </cffunction>

Теперь, если я хочу вызвать api через обработчик / контроллер, например мой обработчик художника ... я могу сделать это

<cffunction name="artistPage" cache="5 mins">
 <cfset qAlbums = application.lastFm.user.getArtist(url.artistName) />
</cffunction>

Я немного смущен кешированием, но я кэширую каждый вызов api в этом обработчике в течение 5 минут, но имеет ли это какое-либо значение, потому что каждый раз, когда кто-то попадает на страницу нового исполнителя, это не будет считаться новым попаданием в api ?

Хотите знать, как лучше с этим справиться

Спасибо


person namtax    schedule 26.04.2010    source источник


Ответы (2)


Поскольку это простая модель данных, я бы не стал усложнять ситуацию с помощью специальных механизмов кеширования. Я бы поместил простую структуру / запрос: searchTerm / result, timestamp где-нибудь. Там вы могли сделать это:

<cffunction name="artistPage" cache="5 mins">
    <cfargument name="artistName" type="string" required="true"/>
    <cfif structKeyExists(application.artistCache, arguments.artistName) and structfindkey(application.artistCache, arguments.artistName)>
        <cfif (gettickcount() - application.artistCache[arguments.artistName].timestamp ) lte 5000 >

        <cfset result = application.artistCache[arguments.artistName].result >
    <cfelse>
        <cfset qAlbums = application.lastFm.user.getArtist(arguments.artistName) />
        <cfset tempStruct = structnew()>
        <cfset structNew.result = qAlbums >
        <cfset structNew.timestamp = getTickCount() >
        <cfset structInsert(application.artistCache, arguments.artistName, tempstruct, true) >

        <cfset result = qAlbums >

    </cfif>

    <cfreturn result >
</cffunction>

РЕДАКТИРОВАТЬ: да, вы должны поместить где-нибудь также метод, который удалял бы структурные ключи, где разница в отметках времени равна gt, а затем срок действия вашего кеша.

Рисунок фасада рекомендуется для того, чтобы его можно было менять в будущем.

Извините за опечатки :)

person zarko.susnjar    schedule 26.04.2010
comment
Привет, спасибо за ответ, просто пытаюсь лучше понять. Интересно, где бы я поместил yourCacheStruct в application.cfc? Также этот метод, похоже, ограничивает только вызовы для каждой функции, а не для всего приложения? Т.е. вы можете делать только 5 запросов на каждый исходящий IP-адрес в секунду, в среднем за 5-минутный период. Эти запросы могут поступать из любого места приложения, от обработчика страницы исполнителя выше или, может быть, от обработчика страницы трека. Таким образом, приложение должно гарантировать, что все звонки из любого места не превышают лимит. - person namtax; 26.04.2010
comment
Я отредактировал код в этом ответе, чтобы дать более четкое представление о том, как хранить кеш в области приложения. В конечном итоге я мог бы подумать о добавлении контроллера кеша, который обрабатывает все кэширование данных с помощью нескольких вызовов функций, вместо того, чтобы переписывать его в каждом методе, который должен использовать кеширование; но это должно дать вам представление о том, как это делается. - person Adam Tuttle; 26.04.2010
comment
Я не уверен, почему @zarko решил добавить cache="5 mins" в определение функции. Он ничего не делает, кроме добавления некоторых настраиваемых метаданных. - person Adam Tuttle; 26.04.2010
comment
Зависит от того, как вы пишете приложение: объектно-ориентированный или процедурный. Вы можете объединить эту логику в 50 различных сценариев. Вы можете сделать один singleton cfc инициированным в application.cfc, как и в случае с lastFM cfc, и поместить туда всю логику. Методы вставки, обновления, очистки и т. Д. Если вы также добавите метод для подсчета вызовов синглтона, у вас также будет ограничитель, который может запускать какое-нибудь приятное предупреждение, чтобы информировать пользователя о том, что в настоящее время служба перегружена, попробуйте через X минут. - person zarko.susnjar; 26.04.2010
comment
@Adam - я скопировал / вставил его текст, чтобы сэкономить пару секунд, набирая его :) - person zarko.susnjar; 26.04.2010
comment
Спасибо за это ... Не будет ли application.artistCache изменено на application.lastFMCache, чтобы охватить все вызовы API, будь то данные об исполнителе или треках? Также нужно ли добавить счетчик попаданий в application.artistCache, чтобы гарантировать, что ограничение скорости не будет превышено в течение 5-минутного периода? - person namtax; 26.04.2010
comment
Да, поместите это в одну структуру. Вы можете сделать стек для ограничителя также в рамках приложения. Когда фактический вызов API отправляется в API, добавьте отметку времени в широкий массив приложения (application.hitCounter) и удалите элементы 6+. Перед вызовом проверьте, есть ли по крайней мере 5 вызовов в массиве, проверьте ArrayMin (application.hitCounter) и если разница между текущим временем и самым старым (5-м) вызовом превышает 5 минут API вызова, если не предупреждает пользователя или что-то еще. - person zarko.susnjar; 26.04.2010

Я бы попробовал кастомный кеш.

Это может быть структура, где ключи - это имена исполнителей или другие уникальные идентификаторы ваших записей.

Если вы используете CF9 или Railo 3.1.2+, вы можете использовать встроенное кеширование (функции CachePut, CacheGet и т. Д.), Оно может обрабатывать таймауты и прочее.

В противном случае вы можете сохранить кеш в области приложения, но вам нужно будет включать метку времени с каждой записью и проверять ее на событиях кеша (получение / размещение / удаление) или даже при каждом запросе.

person Sergey Galashyn    schedule 26.04.2010
comment
Привет, спасибо за ваш ответ .. я думаю, что хранение кеша в области приложения меня привлекает. Затем я предполагаю, что я проверяю каждую запись, добавленную в сохраненный кеш, и гарантирую, что она не превышает лимит в течение определенного периода времени. - person namtax; 26.04.2010