curl "s3.aws.amazon.com/bucket/file.xml" if cmp "file.xml" "current.xml" then echo "no change" else echo "file changed" cp "file.xml" "current.xml" fi sleep(10s)
有没有更好的方法来检查每10秒减少GET请求的数量? (这是建立在rails应用程序之上,所以我可以在rails中构建一个处理程序?)
S3和“最终一致性”
S3为覆盖的对象提供“最终一致性”.从S3 FAQ开始,你有:
Q: What data consistency model does Amazon S3 employ?
Amazon S3 buckets in all Regions provide read-after-write consistency for PUTS of new objects and eventual consistency for overwrite PUTS and DELETES.
覆盖的最终一致性意味着,每当更新对象时(即,只要您的小XML文件被覆盖),检索文件的客户端可能会看到新版本,或者他们可能会看到旧版本.多长时间?对于一个不确定的时间.它通常在不到10秒的时间内实现一致性,但您必须假设最终需要10秒以上才能实现一致性.更有趣的是(遗憾的是?),即使在成功检索到新版本之后,客户端仍可能会在以后收到旧版本.
您可以确定的一件事是:如果客户端开始下载该文件的一个版本,它将下载整个版本(换句话说,您不可能收到例如,XML文件的前半部分为旧版本和下半年作为新版本).
考虑到这一点,请注意您的脚本可能无法在10秒的时间范围内识别更改:即使在更改之后,您也可以发出多个请求,直到脚本下载更改的版本.即便如此,在您检测到更改后,(很遗憾)完全有可能下一个请求将下载以前的(!)版本,并在您的代码中触发另一个“更改”,然后下一个将提供当前版本,并在您的代码中触发另一个“更改”!
如果您对S3提供最终一致性这一事实感到满意,那么您可以通过某种方式改进系统.
想法1:S3事件通知SNS
你提到过你考虑过使用SNS.这肯定是一个有趣的方法:您可以启用S3事件通知,然后在文件更新时通过SNS获得通知.
想法1.1:S3事件通知SNS是一个“网络应用”
如果您有一个“Web应用程序”,即在公共可访问的HTTP端点中运行的任何内容,您可以创建一个HTTP订阅者,因此SNS会在发生时通过您的服务器调用通知.在您的方案中,这可能是也可能不可能或不可取
想法2:S3事件通知SQS
您可以在SQS中创建消息队列,并让S3将通知直接发送到队列.这也可以作为S3事件通知SNS SQS,因为您可以将队列作为订阅者添加到SNS主题(优点是,如果您以后需要添加功能,您可以添加更多队列并订阅它们到相同的主题,因此获得通知的“多个副本”).
要检索通知,您需要调用SQS.你仍然需要轮询 – 即,有一个循环并在SQS上调用GET(与S3 GET相比,它的成本大致相同,或者可能更多一些,具体取决于区域).稍有不同的是,您可以减少总请求的数量 – SQS支持长达20秒的长轮询请求:您在SQS上进行GET调用,如果没有消息,SQS保持请求为up如果消息到达则立即返回20秒,如果在20秒内没有可用消息则返回空响应.因此,您每20秒只发送1次GET,以获得比您目前更快的通知.你可以将你所获得的GET数量减半(每隔10s到S3一次,每20s一次到SQS).
此外 – 您可以选择使用单个SQS队列来聚合对所有XML文件或多个SQS队列的所有更改,每个XML文件一个.使用单个队列,您将大大减少GET请求的总数.每个XML文件有一个队列,就像你现在可能“减半”GET请求的数量一样.
想法3:S3事件通知AWS Lambda
您也可以使用Lambda函数.这可能需要对您的环境进行一些更改 – 您不会使用Shell脚本进行轮询,但可以将S3配置为为您调用Lambda函数作为对事件的响应,例如对XML文件的更新.你可以用Java,Javascript或Python编写你的代码(有些人设计了一些“hacks”来使用其他语言,包括Bash).
这样做的好处是没有更多的轮询,你不必维护一个Web服务器(如“想法1.1”).只要有变化,您的代码“只会运行”.
请注意,无论您使用哪种创意,您仍然需要处理最终的一致性.换句话说,你知道发生了PUT / POST,但是一旦你的代码发送了GET,你仍然可以收到旧版本……
想法4:改用DynamoDB
如果您能够对系统进行更多结构性更改,则可以考虑使用DynamoDB执行此任务.
我建议这是因为DynamoDB支持强一致性,即使对于更新也是如此.请注意,它不是默认值 – 默认情况下,DynamoDB在最终一致性模式下运行,但“检索”操作(例如,GetItem)支持完全一致的读取.
此外,DynamoDB具有我们称之为“DynamoDB Streams”的功能,这种机制允许您获取对表中任何(或所有)项目所做的更改流.这些通知可以被轮询,或者它们甚至可以与Lambda函数一起使用,只要发生更改就会自动调用它们!这一点,再加上DynamoDB可以使用强大的一致性,可能会帮助您解决问题.
在DynamoDB中,保持记录较小通常是一种很好的做法.你在评论中提到你的XML文件大约是2kB – 我说这可以被认为是“足够小”,因此它非常适合DynamoDB! (推理:DynamoDB读取通常计算为4kB的倍数;因此要完全读取1个XML文件,您只需要读取1个;同样,根据您的操作方式,例如使用Query操作而不是GetItem操作,您可能能够从DynamoDB读取2个XML文件,只消耗1次读取操作).
一些参考:
> http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html
> http://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html
> http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html