使用 ColdFusion 中的缓存来限制对 API 的调用频率

5

你好,我正在使用ColdFusion调用last.fm api,使用的是从这里获取的cfc bundle。

我担心超过请求限制,即每个来源IP地址每秒5个请求,平均分布在5分钟内。

cfc bundle有一个中央组件,调用所有其他组件,这些组件分为“artist”、“track”等部分...这个中央组件“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的新请求?如何最好地解决这个问题?谢谢。
2个回答

3

由于数据模型简单,我不会用自定义的缓存引擎使事情变得复杂。我会将简单的结构/查询:搜索术语/结果、时间戳放在某个地方。你可以这样做:

<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>

编辑:是的,你应该放置一个方法,在这个方法中移除时间戳差异大于缓存有效期的结构体键。

门面模式建议用于将来更改。

抱歉打错字了 :)


我不确定为什么@zarko决定在函数定义中加入cache="5 mins"。虽然它除了添加一些自定义元数据之外并没有做任何事情。 - Adam Tuttle
取决于您编写应用程序的方式,是面向对象还是过程化。您可以将此逻辑包装成50种不同的情况。您可以创建一个单例CFC,在application.cfc中初始化,就像您使用lastFM cfc一样,并将所有逻辑放在那里。插入、更新、清除等方法。如果您还为计算对单例的调用次数添加了方法,您还可以拥有“限制器”,它可以触发一些漂亮的警报,通知用户“当前服务已超载,请在X分钟后再试”。 - zarko.susnjar
@Adam - 我复制/粘贴了他的文本,以节省几秒钟的打字时间 :) - zarko.susnjar
谢谢你提供这个建议。如果将application.artistCache更改为application.lastFMCache,是否可以涵盖对API的所有调用(无论是艺术家还是曲目数据)?此外,需要向application.artistCache添加命中计数以确保在5分钟内未超过速率限制吗? - namtax
把它放在一个结构体中。您还可以在应用程序范围内创建限制器的堆栈。 当实际的API调用被发送到API时,将时间戳添加到应用程序范围的数组(application.hitCounter)中,并删除第6个及以上元素。 在调用之前检查数组中是否至少有5个调用,检查ArrayMin(application.hitCounter),如果当前时间和最旧的(第5个)调用之间的差异超过5分钟,则调用API,否则警告用户或其他操作。 - zarko.susnjar
显示剩余2条评论

0

我会尝试使用自定义缓存。

可以使用一个结构,其中键是艺术家名称或其他条目的唯一标识符。

如果您正在使用CF9或Railo 3.1.2+,则可以使用内置缓存(函数CachePut、CacheGet等),它可以为您处理超时和其他事项。

否则,您可以将缓存存储到应用程序范围中,但需要在每个条目中包含时间戳,并在缓存事件(获取/放置/删除)甚至每个请求上进行检查。


嗨,感谢您的回复。我认为将缓存存储在应用程序范围内很有吸引力。然后,我假设我会检查添加到存储缓存中的每个条目,并确保它在特定时间范围内不超过限制。 - namtax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接