如何备份或同步Amazon S3存储桶?

22

我在Amazon S3桶中有重要的数据。我想每周备份其它内容到另一个云服务,甚至是S3内部。最好的方法是将我的存储桶与不同区域内的新存储桶同步,以防数据丢失。

如何做到这一点?


使用s3cmd http://s3tools.org/s3cmd 或者编写自己的s3 api备份工具。 - qrtt1
3
真的有用吗?S3中的数据是冗余的。从http://aws.amazon.com/s3/#protecting得知:Amazon S3的标准存储被设计为可以承受两个设施同时丢失数据。 - ben
1
为了增加对这种方法的有用性的另一个洞察(来自S3 FAQ): Amazon S3旨在在给定年份内提供99.999999999%的对象耐久性。这种耐久性水平相当于每年平均预期损失的0.000000001%的对象。例如,如果您使用Amazon S3存储10,000个对象,则平均而言,您可以期望每1000万年遭受一次单个对象的损失。此外,Amazon S3还专为两个设施中数据的同时丢失而设计。 - Viccari
58
冗余不等于备份——如果你的一位初级开发人员决定运行“s3cmd del --recursive s3://your-bucket/”命令,那么再多的冗余也无济于事!请注意,此处翻译的是“冗余”而非“备份”的区别。 - Phantomwhale
2
@ben 另外,如果您被锁定在 S3 外面怎么办?您将失去您的数据。 - Danny King
@Phantomwhale - 看起来S3提供了MFA Delete来保护免受此类攻击。 - Yarin
5个回答

14

我更喜欢使用同步本地备份,只更新更改的内容。虽然这不是完美的备份解决方案,但以后您可以根据需要实现定期更新:

s3cmd sync --delete-removed s3://your-bucket-name/ /path/to/myfolder/

如果您从未使用过s3cmd,请安装并配置它:

pip install s3cmd
s3cmd --configure

同时,你可以以每月5美元的价格使用S3备份服务,但我也建议检查Amazon Glacier,如果您使用多部分上传,则可以将近40 GB的单个存档文件放入其中。

http://docs.aws.amazon.com/amazonglacier/latest/dev/uploading-archive-mpu.html#qfacts

请记住,如果您的S3帐户受到攻击,您可能会丢失所有数据,因为您将同步空文件夹或格式错误的文件。因此,最好编写一个脚本来多次归档备份,例如通过检测一周的开始。

更新01/17/2016:

基于Python的AWS CLI现在非常成熟。

请使用:https://github.com/aws/aws-cli
例如:aws s3 sync s3://mybucket .


这些$5的s3备份服务有哪些?我想要一种可以防止人为错误的备份。我们使用s3就像一个共享服务器。 - Lee McAlilly
他们似乎不再存在了,我建议再开一个云账户,比如谷歌云平台,以备份存储。 - hurturk

4

这个脚本可以备份S3存储桶:

#!/usr/bin/env python
from boto.s3.connection import S3Connection
import re
import datetime
import sys
import time

def main():
    s3_ID = sys.argv[1]
    s3_key = sys.argv[2]
    src_bucket_name = sys.argv[3]
    num_backup_buckets = sys.argv[4]
    connection = S3Connection(s3_ID, s3_key)
    delete_oldest_backup_buckets(connection, num_backup_buckets)
    backup(connection, src_bucket_name)

def delete_oldest_backup_buckets(connection, num_backup_buckets):
    """Deletes the oldest backup buckets such that only the newest NUM_BACKUP_BUCKETS - 1 buckets remain."""
    buckets = connection.get_all_buckets() # returns a list of bucket objects
    num_buckets = len(buckets)

    backup_bucket_names = []
    for bucket in buckets:
        if (re.search('backup-' + r'\d{4}-\d{2}-\d{2}' , bucket.name)):
            backup_bucket_names.append(bucket.name)

    backup_bucket_names.sort(key=lambda x: datetime.datetime.strptime(x[len('backup-'):17], '%Y-%m-%d').date())

    # The buckets are sorted latest to earliest, so we want to keep the last NUM_BACKUP_BUCKETS - 1
    delete = len(backup_bucket_names) - (int(num_backup_buckets) - 1)
    if delete <= 0:
        return

    for i in range(0, delete):
        print 'Deleting the backup bucket, ' + backup_bucket_names[i]
        connection.delete_bucket(backup_bucket_names[i])

def backup(connection, src_bucket_name):
    now = datetime.datetime.now()
    # the month and day must be zero-filled
    new_backup_bucket_name = 'backup-' + str('%02d' % now.year) + '-' + str('%02d' % now.month) + '-' + str(now.day);
    print "Creating new bucket " + new_backup_bucket_name
    new_backup_bucket = connection.create_bucket(new_backup_bucket_name)
    copy_bucket(src_bucket_name, new_backup_bucket_name, connection)


def copy_bucket(src_bucket_name, dst_bucket_name, connection, maximum_keys = 100):
    src_bucket = connection.get_bucket(src_bucket_name);
    dst_bucket = connection.get_bucket(dst_bucket_name);

    result_marker = ''
    while True:
        keys = src_bucket.get_all_keys(max_keys = maximum_keys, marker = result_marker)

        for k in keys:
            print 'Copying ' + k.key + ' from ' + src_bucket_name + ' to ' + dst_bucket_name

            t0 = time.clock()
            dst_bucket.copy_key(k.key, src_bucket_name, k.key)
            print time.clock() - t0, ' seconds'

        if len(keys) < maximum_keys:
            print 'Done backing up.'
            break

        result_marker = keys[maximum_keys - 1].key

if  __name__ =='__main__':main()

我在一个Rake任务中使用了这个(针对Rails应用程序):
desc "Back up a file onto S3"
task :backup do
     S3ID = "AKIAJM3FAKEFAKENRWVQ"
     S3KEY = "0A5kuzV+F1pbaMjZxHQAZfakedeJd0dfakeNpry"
     SRCBUCKET = "primary-mzgd"
     NUM_BACKUP_BUCKETS = 2

     Dir.chdir("#{Rails.root}/lib/tasks")
     system "./do_backup.py #{S3ID} #{S3KEY} #{SRCBUCKET} #{NUM_BACKUP_BUCKETS}"
end

2
请注意...您的S3 ID和Key似乎在此答案中被公开。 - T. Brian Jones

2

现在AWS CLI已经支持此功能。

aws s3 cp s3://第一个桶名称 s3://第二个桶名称 --recursive


0

我曾经尝试过这个,但是对于大型的、多GB、数百万文件的存储桶来说,仍然非常困难。我找到的最好的解决方案是S3S3Mirror,它专门为此而设计。

这并不像简单地切换开关那么容易,但它仍然比我尝试过的大多数其他DIY解决方案要好。它是多线程的,会比类似的单线程方法更快地复制文件。

一个建议:在单独的EC2实例上设置它,一旦你运行它,就关闭那台机器,但保留AMI。然后,当你需要重新运行时,再次启动机器,你就可以了。虽然这远远不如真正自动化的解决方案那么好,但对于每月或每周备份来说是可管理的。


0
最好的方法是在数据丢失的情况下,能够将我的存储桶与不同区域的新存储桶进行同步。
截至2015年3月24日,使用S3的跨区域复制功能可以实现这一点。
列出的用例场景之一是“合规要求”,似乎符合您对关键数据增加保护以防数据丢失的用例:
尽管默认情况下,Amazon S3会在多个地理位置不同的可用区中存储您的数据,但合规要求可能要求您将数据存储在更远的距离。跨区域复制允许您在远程AWS区域之间复制数据,以满足这些合规要求。
请参见如何设置跨区域复制以获取设置说明。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接