如何进行SimpleDB备份?

时间:2011-05-31 23:26:10

标签: php backup amazon-simpledb

我正在开发一个使用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仍然不是线程安全的。而且我知道除非我在备份期间停止写入,否则会出现一些一致性问题,但在这种特殊情况下我并不太担心。

2 个答案:

答案 0 :(得分:1)

根据我的经验,创建代理分片属性的方法确实有效。

或者,我们过去所做的是将备份分解为两个步骤,以便尽可能多地进行多处理(尽管这是在java和写入备份)文件我们可以依靠同步来确保写安全 - 不确定php方面的交易是什么。)

基本上我们有一个线程可以对域内的数据进行选择,而不是“SELECT * FROM ...”,它只是“SELECT itemName FROM ...”来获取需要的条目的键备份。然后将这些项目放入一个项目键队列中,一个线程池使用getItem API读取,并以线程安全的方式写入备份文件。

这使我们在单个域上获得比在单个线程上旋转更好的吞吐量。

最终,在我们的夜间备份中有多个域,我们最终还原为在单线程中执行每个域备份和“SELECT * FROM域”类型模型,主要是因为我们已经有了大量的线程正在进行和线程负担过重开始成为备份处理器上的问题,但也因为备份程序开始变得危险复杂。

答案 1 :(得分:0)

我从2012年10月开始研究这个问题。三个主要问题似乎决定了选择:

  1. 没有'原生'确保一致导出或导入SimpleDB的方法。您有责任了解和管理此w.r.t的含义。你的申请代码。
  2. 亚马逊没有可用的托管备份解决方案,但各种第三方公司在这个领域提供了一些东西(通常使用"备份到S3"作为选项)。
  3. 在一定数量的数据中,您需要考虑一种多线程方法,这种方法再次具有重要意义:一致性。
  4. 如果您只需要从单个域转储数据并且您的数据量足够低以使单线程导出有意义,那么我编写的一些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()