Migrieren von GAE Blobstore zu einem HRD Anwendung
Wenn Sie planen, Ihr Google App Engine Anwendung auf die "neue" High Replication Database Schema migriert werden, dann wissen Sie wahrscheinlich, dass die Google Migrationsprozess wird sich nicht umgehen Blobstore Dateien.
Hier finden Sie einige Python-Skripte, die Ihnen helfen, die Blobstore Dateien aus dem alten Anwendung auf die neue zu verschieben, und korrigieren Sie alle Verweise in der neuen Datenbank. Wie immer auf eigene Gefahr zu nutzen, versuchen Sie nicht, alles ohne Lesen und Verstehen der Skripts zu tun, sonst können Sie Ihre Daten endgültig zu verlieren.
Einige Überlegungen:
- Wir haben diese Skripte in unserem eigenen Anwendung verwendet werden, so kann ich sagen, es funktioniert. Allerdings habe ich die Original-Skripte zu bearbeiten, damit sie besser "generische" hatten, entfernen Sie meine Referenzen und Namen, etc.
- Ich werde versuchen, die Schritte der Migration beschreiben, aber bitte nicht versuchen, etwas vor dem Lesen Sie den ganzen Artikel zuerst tun.
- Dies ist keineswegs beabsichtigt, um eine vollautomatische Migration sein, in der Tat braucht die Schritte, die manuell ausgeführt werden eins nach dem anderen.
- Die Skripte werden nicht migriert große Dateien. Wir haben migrierte Dateien bis zu 40MB ohne Probleme, aber wenn Sie Dateien größer als das haben, wird es wahrscheinlich scheitern. Zum Beispiel haben wir eine 300Mb Datei versuchte erfolglos, ist der Grund, dass die Datei von der alten auf die neue App heruntergeladen werden muss, und es gibt eine 1 Minute Timeout für den App-Zugriffe, also, wenn der Download mehr als dass sie scheitern nimmt .
Wie funktioniert das Skript funktioniert
Sie müssen das Skript in Ihren Anwendungen gelegt, sowohl die neue (HRD) und die alte. Es besteht im Wesentlichen macht vier URLs und Sie müssen auf zwei von ihnen aus dem HRD-Anwendung zugreifen.
Auf diese Weise finden Sie alle BLOB-Dateien aus dem alten Programm herunterladen, um die neue, wird das Skript ein Modell erstellen, die eine Karte zwischen den alten und neuen Referenzen hält.
Der letzte Schritt ist, um die alten Verweise auf die neue HRD in den Datenbanken zu migrieren.
Voraussetzungen
- Alle Verweise auf die BLOB-Dateien in Ihren Modellen muss Typ
blobstore.BlobReferenceProperty, wenn nicht Sie benötigen, um sie zuerst anpassen. - Migrieren Sie die Datenbanken vom alten auf den neuen App App HRD mit dem Standard-Google Migration Methode .
Steps
- Fügen Sie die URLs auf Ihre Bewerbung
def main():
application = webapp.WSGIApplication(
[
# ... Your app URLs here ...
# TODO - REMOVE THIS AFTER MIGRATION
('/mig/__getblob/(.+)', GetBlob),
('/mig/__getblobkeys/?', GetBlobKeys),
('/mig/__migrateblobs/?', MigrateBlobs),
('/mig/__migratereferences/?', MigrateBlobReferences),
], debug=True)
run_wsgi_app(application)
if __name__ == '__main__':
main()
- Dann fügen Sie den Code Migration
####
# TEMPORARY BLOBSTORE MIGRATION CODE
####
MODELS = (
# add your (model, blobinfo_field_name) tuples here
("myModel1", "blobinfofield"),
("myModel2", "BlobInfo"),
)
class mig_BlobMig(db.Model):
fname = db.StringProperty()
blobinfo = blobstore.BlobReferenceProperty()
origkey = db.StringProperty()
class MigrateBlobReferences(blobstore_handlers.BlobstoreDownloadHandler):
'''Migrate blob info references'''
def get(self):
import models
tb = dict([(str(blob.origkey), blob.blobinfo) for blob in mig_BlobMig.all()])
for modelname, field in MODELS:
to_put = []
skipped = 0
for obj in db.GqlQuery('SELECT * FROM %s'%modelname):
oldkey = getattr(obj, field)
if oldkey:
oldkey = str(oldkey.key())
if oldkey in tb:
setattr(obj, field, tb[oldkey])
to_put.append(obj)
else:
skipped += 1
db.put(to_put)
self.response.out.write("[%s] - Migrated %d references!<br/>Skipped: %d<br/>\n"%(modelname, len(to_put), skipped))
class MigrateBlobs(blobstore_handlers.BlobstoreDownloadHandler):
'''Migrate blobs from myoldapp to mynewapp'''
def get(self):
import time
from google.appengine.api import files, urlfetch
start_time = time.time()
timed_out = False
migrated_keys = set([str(blob.origkey) for blob in mig_BlobMig.all()])
all_blobs = eval(urlfetch.fetch("https://myoldapp.appspot.com/mig/__getblobkeys", deadline=15.0).content)
all_keys = set(all_blobs.keys())
missing_keys = list(all_keys-migrated_keys)
if not missing_keys:
self.response.out.write("Nothing to migrate!")
return
# Download 20 blobs per round
download_keys = missing_keys[:20]
MAXSIZE = (10*1024*1024) # 10MB
for origkey in download_keys:
blob = all_blobs[origkey]
url = "https://myoldapp.appspot.com/mig/__getblob/%s"%urllib.quote_plus(origkey)
blob_path = files.blobstore.create(mime_type=blob["content_type"], _blobinfo_uploaded_filename=blob["filename"])
fsize = int(blob["size"])
with files.open(blob_path, 'a') as f:
for first_byte in range(0, fsize, MAXSIZE):
last_byte = (first_byte+MAXSIZE-1)
if last_byte>=fsize: last_byte=(fsize-1)
bytes_range = "bytes=%d-%d"%(first_byte,last_byte)
logging.info("Downloading [%s] range [%s] key=[%s]"%(blob["filename"], bytes_range, origkey))
res = urlfetch.fetch(url, deadline=35.0, headers={"Range": bytes_range})
f.write(res.content)
del res.content
del res
if (time.time()-start_time > 40.0):
timed_out = True
break
if timed_out:
self.response.out.write("Stopped due to time limit!<br/>")
break
files.finalize(blob_path)
blob_key = files.blobstore.get_blob_key(blob_path)
blob_info = blobstore.BlobInfo.get(blob_key)
mig_BlobMig(fname=blob["filename"], blobinfo=blob_info, origkey=origkey).put()
logging.info("Successfully downloaded [%s]!!!"%(blob["filename"]))
self.response.out.write("Migrated %s<br/>"%blob["filename"])
self.response.out.write("<br/>SUCCESS!")
class GetBlobKeys(blobstore_handlers.BlobstoreDownloadHandler):
'''Retrieve all Blob Keys, as a JSON string'''
def get(self):
from simplejson.encoder import JSONEncoder
blobs = {}
for blob_info in blobstore.BlobInfo.all():
blobs[str(blob_info.key())] = {
"filename":str(blob_info.filename),
"content_type":str(blob_info.content_type),
"size":int(blob_info.size),
"key":str(blob_info.key()),
}
self.response.headers["Content-type"] = "application/json"
self.response.out.write(JSONEncoder().encode(blobs))
class GetBlob(blobstore_handlers.BlobstoreDownloadHandler):
'''Download a blob given its key'''
def get(self, blobkey):
blobkey = str(urllib.unquote(blobkey))
blob_info = blobstore.BlobInfo.get(blobkey)
if not blob_info:
self.error(404)
return
self.response.headers["Content-type"] = str(blob_info.content_type)
self.send_blob(blob_info, save_as=True)
####
# END OF TEMPORARY BLOBSTORE MIGRATION CODE
####
- Ändern Sie die
MODELSvariabler Addition der Modelle und Blob-Info-Felder, die Sie aktualisieren müssen - Ersetzen
myoldappURLs mit der tatsächlichen URL Ihrer alten Anwendung - Synchronisieren Sie den Code auf beiden Anwendungen
- Öffnen Sie einen Browser und verweisen Sie auf
http://mynewapp.appspot.com/mig/__migrateblobs. Natürlichmynewappmüssen mit Ihrem tatsächlichen Namen HRD Anwendung ersetzt werden. Dadurch werden die Blobs von der alten auf die neue App heruntergeladen wird. Da gibt es einen Timeout-Beschränkung, müssen Sie nennen es viele Male. WARNUNG: Sie müssen nur eine Anforderung der Zeit zu machen, nie nennen es von beiden Browsern / Tabs gleichzeitig oder werden Sie die Migration Datenbank durcheinander!. Dieser Schritt muss sorgfältig ausgeführt werden, eine Anfrage an Zeit und warten Sie, bevor Sie die nächsten ein bis zum Ende. Wiederholen Sie dies, bis Sie die Meldung sehen,Nothing to migrate!. Dieser Schritt kann sehr langsam sein, je nachdem wie viele Dateien Sie haben in der blobstore und der Größe von ihnen, könnte es lange dauern, bis alle Dateien heruntergeladen bekommen. Seien Sie geduldig! - Sobald alle Dateien werden in das neue App kopiert, weisen den Browser an,
http://mynewapp.appspot.com/mig/__migratereferences. Sollte schnell, und es muss nur einmal ausgeführt werden. Allerdings schadet nicht, um es mehr als einmal anrufen. - Der letzte Schritt, entfernen Sie den Code Migration und URLs und synchronisieren Sie den Code erneut ein. Sie können auch die
mig_BlobMigDatenbank.
Gute Migration.
