7

今私は毎晩自分のデータベースのスナップショットを撮るのにremote_apiとappcfg.py download_dataを使用します。それは長い時間(6時間)を要し、高価です。自分の変更ベースのバックアップを実行することなく(私はあまりにもそういうことをするのは怖いだろう)、データが失敗から安全であることを確認するための最良の選択肢は何ですか?appengineのデータストアをバックアップするための推奨戦略

PS:Googleのデータはおそらく私のものより安全だと認識しています。しかし、ある日私が間違ってすべてを削除するプログラムを書いたらどうなるでしょうか?

+0

最後の質問については、[776](http://code.google.com/p/googleappengine/issues/detail?id=776) –

答えて

3

あなたはあなたの選択肢のすべてをかなり特定したと思います。

  1. Googleはあなたのデータを失うことはないと信じています。あなたが誤ってそれを破壊するように指示しないことを願います。
  2. download_dataで完全バックアップを実行してください。これは、非常に高額な場合は、1泊あたり1回よりも少なくなる可能性があります。
  3. 独自の増分バックアップソリューションをロールバックします。

オプション3は実際には興味深いアイデアです。すべてのエンティティでタイムスタンプを変更する必要があり、削除されたエンティティは捕捉されませんが、それ以外の場合はremote_apiとカーソルで非常に有効です。

編集

ここでのremote_apiで使用するための簡単な増分ダウンローダです。この場合も、削除されたエンティティに気付かれず、すべてのエンティティがupdated_atという名前のプロパティに最後の変更時刻を格納しているとみなされます。あなた自身の危険でそれを使用してください。

import os 
import hashlib 
import gzip 
from google.appengine.api import app_identity 
from google.appengine.ext.db.metadata import Kind 
from google.appengine.api.datastore import Query 
from google.appengine.datastore.datastore_query import Cursor 

INDEX = 'updated_at' 
BATCH = 50 
DEPTH = 3 

path = ['backups', app_identity.get_application_id()] 
for kind in Kind.all(): 
    kind = kind.kind_name 
    if kind.startswith('__'): 
    continue 
    while True: 
    print 'Fetching %d %s entities' % (BATCH, kind) 
    path.extend([kind, 'cursor.txt']) 
    try: 
     cursor = open(os.path.join(*path)).read() 
     cursor = Cursor.from_websafe_string(cursor) 
    except IOError: 
     cursor = None 
    path.pop() 
    query = Query(kind, cursor=cursor) 
    query.Order(INDEX) 
    entities = query.Get(BATCH) 
    for entity in entities: 
     hash = hashlib.sha1(str(entity.key())).hexdigest() 
     for i in range(DEPTH): 
     path.append(hash[i]) 
     try: 
     os.makedirs(os.path.join(*path)) 
     except OSError: 
     pass 
     path.append('%s.xml.gz' % entity.key()) 
     print 'Writing', os.path.join(*path) 
     file = gzip.open(os.path.join(*path), 'wb') 
     file.write(entity.ToXml()) 
     file.close() 
     path = path[:-1-DEPTH] 
    if entities: 
     path.append('cursor.txt') 
     file = open(os.path.join(*path), 'w') 
     file.write(query.GetCursor().to_websafe_string()) 
     file.close() 
     path.pop() 
    path.pop() 
    if len(entities) < BATCH: 
     break 
関連する問題