简体   繁体   English

如何进行 SimpleDB 备份?

[英]How to do a SimpleDB Backup?

I'm developing a Facebook application that uses SimpleDB to store its data, but I've realized Amazon does not provide a way to backup that data (at least that I know of)我正在开发一个 Facebook 应用程序,它使用 SimpleDB 来存储其数据,但我意识到亚马逊没有提供备份数据的方法(至少我知道)

And SimpleDB is slow.而且 SimpleDB 很慢。 You can get about 4 lists per second, each list of 100 records.您每秒可以获得大约 4 个列表,每个列表包含 100 条记录。 Not a good way to backup tons of records.不是备份大量记录的好方法。

I found some services in the web that offer to do the backup for you, but I'm not comfortable about giving them my AWS Credentials.我在 web 中找到了一些可以为您提供备份的服务,但我不愿意给他们我的 AWS 凭证。

So I though about using threads.所以我想使用线程。 Problem is that if you do a select for all the keys in the domain, you need to wait for the next_token value of the first page in order to process the second page and so on.问题是,如果您对域中的所有键执行 select,则需要等待第一页的 next_token 值才能处理第二页,依此类推。

A solution I was thinking for this was to have a new attribute based on the last 2 digits of the Facebook id.我为此考虑的一个解决方案是根据 Facebook id 的最后 2 位数字创建一个新属性。 So I'd start a thread with a select for "00", another for "01", and so on, potentially having the possibility of running 100 threads and doing backups much faster (at least in theory).所以我会用 select 为“00”启动一个线程,另一个为“01”,依此类推,可能有可能运行 100 个线程并更快地进行备份(至少在理论上)。 A related solution would be to split that domain into 100 domains (so I can backup each one individually), but that would break some of the selects I need to do.一个相关的解决方案是将该域拆分为 100 个域(这样我可以单独备份每个域),但这会破坏我需要做的一些选择。 Another solution, probably more PHP friendly, would be to use a cron job to backup lets say 10,000 records and save "next_token", then the next job starts at next_token, etc.另一种解决方案,可能对 PHP 更友好,将使用 cron 作业来备份假设 10,000 条记录并保存“next_token”,然后下一个作业从 next_token 开始,等等。

Does anyone have a better solution for this?有没有人对此有更好的解决方案? If its a PHP solution it'd be great, but if it involves something else its welcome anyway.如果它是一个 PHP 解决方案,那就太好了,但如果它涉及其他东西,无论如何它都是受欢迎的。

PS: before you mention it, as far as I know, PHP is still not thread safe. PS:在你提到之前,据我所知,PHP 仍然不是线程安全的。 And I'm aware that unless I stop the writes during the backup, there will be some consistency problems, but I'm not too worried about it in this particular case.而且我知道除非我在备份期间停止写入,否则会出现一些一致性问题,但在这种特殊情况下我并不太担心。

The approach of creating a proxy shard attribute certainly works, from experience where I am.根据我的经验,创建代理分片属性的方法当然有效。

Alternatively, what we have done in the past is to break down the backup into a 2 step process, in order to get as much potential for multi-processing as possible (though this is in java and for the write to the backup file we can rely on synchronization to ensure write-safety - not sure what the deal is on php side).或者,我们过去所做的是将备份分解为两步过程,以便尽可能多地进行多处理(尽管这是在 java 中,对于写入备份文件,我们可以依靠同步来确保写安全 - 不确定 php 方面的交易是什么)。

Basically we have one thread which does a select across the data within a domain, but rather than "SELECT * FROM...", it is just "SELECT itemName FROM..." to get the keys to the entries needing backing up.基本上,我们有一个线程在域内的数据上执行 select,而不是“SELECT * FROM ...”,它只是“SELECT itemName FROM ...”来获取需要备份的条目的密钥。 These are then dropped into a queue of item keys which a pool of threads read with the getItem API and write in a thread safe manner to the backup file.然后将它们放入项目密钥队列中,线程池使用 getItem API 读取该队列,并以线程安全的方式写入备份文件。

This gave us better throughput on a single domain than spinning on a single thread.这给了我们在单个域上比在单个线程上旋转更好的吞吐量。

Ultimately though, with numerous domains in our nightly backup we ended up reverting back to doing each domain backup in the single thread and "SELECT * FROM domain" type model, mainly because we already had a shedload of threads going on and the thread overburden started to become an issue on the backup processor, but also because the backup program was starting to get dangerously complex.最终,由于我们的夜间备份中有许多域,我们最终恢复为在单线程中执行每个域备份,并且“SELECT * FROM domain”类型为 model,主要是因为我们已经有大量线程在运行并且线程过载开始成为备份处理器上的一个问题,还因为备份程序开始变得非常复杂。

I've researched this problem as of October 2012. Three major issues seem to govern choice:截至 2012 年 10 月,我已经研究了这个问题。三个主要问题似乎支配着选择:

  1. There is no 'native' way to ensure a consistent export or import with SimpleDB.没有“本机”方法来确保与 SimpleDB一致的导出或导入。 It is your responsibility to understand and manage the implications of this w.r.t.您有责任了解和管理此 w.r.t 的含义。 your application code.您的应用程序代码。
  2. No managed backup solution is available from Amazon, but a variety of third-party companies offer something in this space (typically with "backup to S3" as an option).亚马逊没有提供托管备份解决方案,但许多第三方公司在这个领域提供了一些东西(通常带有“备份到 S3”作为选项)。
  3. At some volume of data, you'll need to consider a multi-threaded approach which, again, has important implications re: consistency.在一定数量的数据中,您需要考虑一种多线程方法,这同样具有重要意义:一致性。

If all you need is to dump data from a single domain and your data volumes are low enough such that single-threaded export makes sense, then here is some Python code I wrote which works great for me.如果您只需要从单个域转储数据并且您的数据量足够低以至于单线程导出有意义,那么这里是我编写的一些 Python 代码,它对我很有用。 No warranty is expressed or implied, only use this if you understand it:没有明示或暗示的保证,只有在您理解的情况下才使用它:

#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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM