gpt4 book ai didi

amazon-web-services - 亚马逊 SimpleDB 问题 : Implementing counter attributes

转载 作者:行者123 更新时间:2023-12-03 00:52:14 24 4
gpt4 key购买 nike

长话短说,我正在重写系统的一部分,并且正在寻找一种方法来在 AWS SimpleDB 中存储一些命中计数器。

对于那些不熟悉 SimpleDB 的人,存储计数器的(主要)问题是云传播延迟通常超过一秒。我们的应用程序目前每秒获得约 1,500 次点击。并非所有这些点击都会映射到同一个键,但大致数字可能是每秒对一个键进行 5-10 次更新。这意味着,如果我们使用传统的更新机制(读取、增量、存储),我们最终会无意中丢弃大量命中。

一种可能的解决方案是将计数器保留在内存缓存中,并使用 cron 任务推送数据。这样做的最大问题是这不是“正确”的方法。 Memcache 不应该真正用于持久存储……毕竟,它是一个缓存层。此外,当我们执行推送时,我们最终会遇到问题,确保我们删除了正确的元素,并希望在我们删除它们时没有争用它们(这很有可能)。

另一个潜在的解决方案是保留一个本地 SQL 数据库并在那里写入计数器,每隔这么多请求更新我们的 SimpleDB 带外,或者运行一个 cron 任务来推送数据。这解决了同步问题,因为我们可以包含时间戳来轻松设置 SimpleDB 推送的边界。当然,还有其他问题,虽然这可能适用于大量的黑客攻击,但它似乎不是最优雅的解决方案。

有没有人在他们的经历中遇到过类似的问题,或者有什么新颖的方法?任何建议或想法都将不胜感激,即使它们没有完全消失。我一直在考虑这个问题,并且可以使用一些新的观点。

最佳答案

现有的 SimpleDB API 并不适合作为分布式计数器。但它肯定可以做到。

严格在 SimpleDB 中工作,有两种方法可以使其工作。一种简单的方法,需要像 cron 作业这样的东西来清理。或者是一种更复杂的技术,可以随时清洁。

简单的方法

简单的方法是为每个“命中”制作不同的项目。只有一个属性是关键。快速轻松地用计数泵送域。当您需要获取计数时(可能不太频繁),您必须发出查询

SELECT count(*) FROM domain WHERE key='myKey'

当然,这会导致您的域无限增长,并且随着时间的推移执行查询所需的时间会越来越长。解决方案是汇总记录,您可以在其中汇总迄今为止为每个键收集的所有计数。它只是一个具有键 {summary='myKey'} 属性和粒度小至毫秒的“上次更新”时间戳的项目。这还要求您将“时间戳”属性添加到“命中”项目中。摘要记录不需要在同一个域中。事实上,根据您的设置,最好将它们保存在单独的域中。无论哪种方式,您都可以使用键作为 itemName 并使用 GetAttributes 而不是执行 SELECT。

现在获取计数是一个两步过程。您必须提取摘要记录,并查询“时间戳”严格大于摘要记录中的“上次更新”时间,并将这两个计数加在一起。
SELECT count(*) FROM domain WHERE key='myKey' AND timestamp > '...'

您还需要一种方法来定期更新您的摘要记录。您可以按计划(每小时)执行此操作,也可以根据其他一些标准动态执行此操作(例如,在查询返回多于一页时在常规处理期间执行此操作)。只要确保当你更新你的摘要记录时,你所基于的时间已经足够远,你已经过了最终的一致性窗口。 1 分钟是安全的。

该解决方案在并发更新时有效,因为即使同时写入许多摘要记录,它们都是正确的,无论哪个获胜仍然是正确的,因为计数和“最后更新”属性将与每个记录保持一致其他。

即使您将摘要记录与命中记录一起保存,这也适用于多个域,您可以同时从所有域中提取摘要记录,然后并行向所有域发出查询。这样做的原因是,如果您需要比从一个域获得的吞吐量更高的 key 吞吐量。

这适用于缓存。如果您的缓存失败,您将拥有权威备份。

到了有人想要返回并编辑/删除/添加具有旧“时间戳”值的记录的时候了。届时您将必须更新您的摘要记录(针对该域),否则您的计数将被关闭,直到您重新计算该摘要。

这将为您提供与一致性窗口中当前可查看的数据同步的计数。这不会为您提供精确到毫秒的计数。

艰难的道路

另一种方法是执行正常的读取 - 增量 - 存储机制,但也写入一个包含版本号和您的值的复合值。您使用的版本号比您正在更新的值的版本号大 1。

get(key) 返回属性 value="Ver015 Count089"

在这里,您检索存储为版本 15 的 89 计数。当您进行更新时,您会写入这样的值:

put(key, value="Ver016 Count090")

之前的值为 不是 删除,您最终会得到让人联想到 lamport 时钟的更新审计跟踪。

这需要你做一些额外的事情。
  • 每次执行 GET 时识别和解决冲突的能力
  • 一个简单的版本号是行不通的,您需要包含一个分辨率至少为毫秒的时间戳,也可能包含一个进程 ID。
  • 在实践中,您会希望您的值包括当前版本号和更新所基于的值的版本号,以便更轻松地解决冲突。
  • 您不能在一个项目中保留无限的审计跟踪,因此您需要随时为旧值发出删除。

  • 你用这种技术得到的就像一棵不同更新的树。您将拥有一个值,然后突然间会发生多次更新,并且您将拥有一系列基于相同旧值的更新,而这些更新彼此都不知道。

    当我说在 GET 时解决冲突时,我的意思是如果您阅读一个项目并且该值如下所示:
          11 --- 12
    /
    10 --- 11
    \
    11

    您必须能够计算出实际值是 14。如果您为每个新值包含您正在更新的值的版本,您就可以做到这一点。

    这不应该是火箭科学

    如果您只需要一个简单的计数器: 这太过分了 .制作一个简单的计数器不应该是火箭科学。这就是 SimpleDB 可能不是制作简单计数器的最佳选择的原因。

    这不是唯一的方法,但如果您实现 SimpleDB 解决方案而不是实际拥有锁,那么大多数事情都需要完成。

    不要误会我的意思,我实际上很喜欢这种方法,因为它没有锁,并且可以同时使用此计数器的进程数限制在 100 左右。(因为项目中的属性数有限制)通过一些更改,您可以超过 100。

    笔记

    但是如果所有这些实现细节都对你隐藏了,而你只需要调用 increment(key),它就不会很复杂。使用 SimpleDB,客户端库是使复杂的事情变得简单的关键。但目前没有公开可用的库来实现此功能(据我所知)。

    关于amazon-web-services - 亚马逊 SimpleDB 问题 : Implementing counter attributes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1496066/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com