2011-05-31 40 views
4

我正在开发一个使用SimpleDB存储其数据的Facebook应用程序,但我意识到亚马逊并没有提供备份该数据的方法(至少我知道)如何做SimpleDB备份?

而且SimpleDB很慢。每秒可以获得约4个列表,每个列表包含100条记录。不是备份大量记录的好方法。

我在网络上发现了一些服务,可以为您提供备份服务,但我不愿意为他们提供我的AWS凭据。

所以我虽然关于使用线程。问题是,如果您为域中的所有键进行选择,则需要等待第一页的next_token值才能处理第二页等等。

我在想这个问题的解决方案是基于Facebook ID的最后两位数字创建一个新属性。因此,我将开始一个选择“00”,另一个为“01”等的线程,可能有可能运行100个线程并且备份速度要快得多(至少在理论上)。一个相关的解决方案是将该域分成100个域(这样我就可以单独备份每个域),但这会破坏我需要做的一些选择。另一个可能更友好的PHP解决方案是使用cron作业来备份可以说10,000条记录并保存“next_token”,然后下一个作业开始于next_token等。

有没有人有更好的解决方案呢?如果它是一个PHP解决方案,它会很棒,但是如果它涉及其他方面的话,无论如何它都会受到欢迎PS:在你提到它之前,据我所知,PHP仍然不是线程安全的。我知道,除非在备份过程中我停止写入,否则会出现一些一致性问题,但在这种情况下我并不担心它。

+0

http://aws.amazon.com/running_databases/#storage_practices的AWS文档说“此外,一些备份工具已经由Amazon SimpleDB生态系统开发,提供域数据到Amazon S3的简单备份。“这是你最好的选择。使用备份工具备份到S3。然后,您可以将数据从S3传输到任何地方。 – 2011-06-01 01:05:43

+0

感谢您的回复Frank!但我似乎没有在任何亚马逊网页上找到这些工具。我发现的唯一的第三方工具,与亚马逊没有任何关系,因此不确定哪些是安全的,哪些不是。 – Cristian 2011-06-01 15:48:01

回答

1

从我的经验来看,创建代理碎片属性的方法当然有效。

另外,我们过去所做的是将备份分解成2个步骤的过程,以获得尽可能多的多处理潜力(虽然这是在Java中,并写入到备份文件,我们可以依靠同步来确保写入安全 - 不知道在PHP方面的交易是什么)。

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

这给了我们在单个域上比在单个线程上旋转更好的吞吐量。最后,尽管我们在夜间备份中有很多域,但我们最终还是恢复了在单线程和“SELECT * FROM domain”类型模型中执行每个域备份,主要是因为我们已经有了一大堆线程正在进行,线程负载过重开始成为备份处理器的问题,但也因为备份程序开始变得非常复杂。

0

我研究过这个问题,因为2012年10月的三大问题似乎支配的选择:

  1. 没有“天然”的方式,以确保一致出口或进口与SimpleDB的。理解和管理本w.t.t的含义是你的责任。你的应用代码。
  2. 亚马逊不提供托管备份解决方案,但各种第三方公司在此空间中提供了一些功能(通常选择“备份到S3”作为选项)。
  3. 在某些数据量下,您需要考虑多线程方法,这同样具有重要意义:一致性。

如果您只需要从单个域中转储数据并且数据量足够低,以便单线程导出有意义,那么这里是我编写的一些对我很好的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()