我正在开发一个使用SimpleDB存储数据的Facebook应用程序,但我意识到亚马逊没有提供备份数据的方法(至少我知道)
SimpleDB很慢。您每秒可以获得大约4个列表,每个列表包含100个记录。不是备份大量记录的好方法。
我在网络上找到了一些为您提供备份的服务,但是我不愿意为他们提供我的AWS凭证。
所以我虽然使用线程。问题是,如果对域中的所有键执行选择,则需要等待第一页的next_token值以处理第二页,依此类推。
我想到的解决方案是根据Facebook ID的最后2位数设置一个新属性。所以我开始一个选择为“00”的线程,另一个选择为“01”,依此类推,可能会运行100个线程并更快地进行备份(至少在理论上)。一个相关的解决方案是将该域分成100个域(因此我可以单独备份每个域),但这会破坏我需要做的一些选择。另一个可能更友好的PHP解决方案是使用cron作业备份让我们说10,000条记录并保存“next_token”,然后下一个作业从next_token开始,等等。
有没有人有更好的解决方案呢?如果它是一个PHP解决方案,它会很棒,但如果它涉及其它方面,那么无论如何它都会受到欢迎。
PS:在你提到它之前,据我所知,PHP仍然不是线程安全的。而且我知道除非我在备份期间停止写入,否则会出现一些一致性问题,但在这种特殊情况下我并不太担心。
答案 0 :(得分:1)
根据我的经验,创建代理分片属性的方法确实有效。
或者,我们过去所做的是将备份分解为两个步骤,以便尽可能多地进行多处理(尽管这是在java和写入备份)文件我们可以依靠同步来确保写安全 - 不确定php方面的交易是什么。)
基本上我们有一个线程可以对域内的数据进行选择,而不是“SELECT * FROM ...”,它只是“SELECT itemName FROM ...”来获取需要的条目的键备份。然后将这些项目放入一个项目键队列中,一个线程池使用getItem API读取,并以线程安全的方式写入备份文件。
这使我们在单个域上获得比在单个线程上旋转更好的吞吐量。
最终,在我们的夜间备份中有多个域,我们最终还原为在单线程中执行每个域备份和“SELECT * FROM域”类型模型,主要是因为我们已经有了大量的线程正在进行和线程负担过重开始成为备份处理器上的问题,但也因为备份程序开始变得危险复杂。
答案 1 :(得分:0)
我从2012年10月开始研究这个问题。三个主要问题似乎决定了选择:
如果您只需要从单个域转储数据并且您的数据量足够低以使单线程导出有意义,那么我编写的一些Python代码对我来说非常有用。不作任何明示或暗示的保证,只有在您理解的情况下才使用此保证:
#simpledb2json.py
import boto
import simplejson as json
AWS_KEY = "YOUR_KEY"
AWS_SECRET = "YOUR_SECRET"
DOMAIN = "YOUR_DOMAIN"
def fetch_items(boto_dom, dom_name, offset=None, limit=300):
offset_predicate = ""
if offset:
offset_predicate = " and itemName() > '" + offset + "'"
query = "select * from " \
+ "`" + dom_name + "`" \
+ " where itemName() is not null" \
+ offset_predicate \
+ " order by itemName() asc limit " + str(limit)
rs = boto_dom.select(query)
# by default, boto does not include the simpledb 'key' or 'name' in the
# dict, it is a separate property. so we add it:
result = []
for r in rs:
r['_itemName'] = r.name
result.append(r)
return result
def _main():
con = boto.connect_sdb(aws_access_key_id=AWS_KEY, aws_secret_access_key=AWS_SECRET)
dom = con.get_domain(DOMAIN)
all_items = []
offset = None
while True:
items = fetch_items(dom, DOMAIN, offset=offset)
if not items:
break
all_items += items
offset = all_items[-1].name
print json.dumps(all_items, sort_keys=True, indent=4)
if __name__ == "__main__":
_main()