2012-05-31 14 views
15

通常の生産環境では、djangoアプリケーションを使用している人からデータベース移行をどのように扱いますか?私はsouthがあることを知っていますが、何か実質的なものが関与している場合、それはかなり多く見逃すようです。djangoプロダクションでのデータベース移行

他の2つのオプションは、テストデータベースで変更を行ってから(アプリケーションでオフラインにする)、そのSQLエクスポートをインポートすることです。または、おそらくリスクの高いオプションで、本番データベースで必要な変更をリアルタイムで実行し、何かが間違ってバックアップに復帰した場合。

通常、データベースの移行とスキーマの変更はどのように処理しますか?

+1

ほとんどのDjango開発者は私が南を使用していることを知っています。私は自分自身を使用します。あなたはそれが「かなりたくさん見逃す」と思いますか?私は南との不平を抱いていたが、ほとんどの場合、それは機能する。 – super9

+0

アプリケーションのおおよその容量は? – David542

答えて

14

私はこの問題に2つの部分があると思います。

まず、データベーススキーマの管理とその変更です。 Southを使用してこれを行い、作業モデルと移行ファイルの両方をSCMリポジトリに保存します。安全性(またはパラノイア)のために、マイグレーションを実行する前にデータベースのダンプを取っています。南はこれまでのすべての要求に対して適切でした。

第2に、Southによって生成された移行ファイルを実行するだけのスキーマ変更を導入しています。私の経験では、通常、データベースを変更するには、展開されたコードを変更する必要があります。小さなWebファームでも、展開されたコードをデータベーススキーマの現在のバージョンと同期させておくのは簡単ではないかもしれません。すでにアクティブなサイトユーザーとは異なるキャッシュレイヤーと効果を考えれば悪化します。異なるサイトではこの問題を別々に扱いますが、私はワンサイズの答えがないと思います。


この問題の2番目の部分を解決することは、必ずしも単純ではありません。あなたの状況に最も適したソリューションを提案するために、あなたのウェブサイトと環境に関する情報が不十分であると私は考えています。しかし、私は、ほとんどの状況で展開をガイドするのを助けるために留意できるいくつかの考慮事項があると思います。

サイト全体(ウェブサーバーとデータベース)をオフラインで撮影することは、場合によってはオプションです。それは確かに更新を管理する最も直接的な方法です。しかし、頻繁なダウンタイム(計画されていても)は、ビジネスを迅速に進める良い方法です。小さなコード変更を展開するのも面倒ですし、大規模なデータセットや複雑な移行があると時間がかかることがあります。つまり、私が管理するサイト(内部はすべて一般的に営業日のみ営業時間内にのみ使用されます)では、このアプローチは驚異的です。

masterデータベースのコピーで変更を行う場合は注意が必要です。ここでの主な問題は、サイトがまだ稼動しており、おそらくデータベースへの書き込みを受け入れていることです。後で使用するためにクローンを移行している間にmasterデータベースに書き込まれたデータはどうなりますか?サイト全体がダウンしているか、一時的に読み取り専用の状態になっていなければ、それを失うことになります。

変更が下位互換性があり、Webファームがある場合は、ライブプロダクションデータベースサーバー(ほとんどの場合避けられないものだと思います)を更新してから、それらを短期間ロードバランサから外します。これは正常に動作しますが、主な問題は、すでに更新されたノードがロードバランサレベルで管理できない場合に失敗する、古いノードでサポートされていないURLの要求を送信する場合です。

私は、いくつかの他の方法がうまくいくことを見てきました。

最初に、フィーチャロック内のすべてのコード変更をラップしています。この変更は、サイト全体の構成オプションによって実行時に構成できます。これは基本的に、すべての変更が無効になっているコードをリリースできることを意味し、サーバーに必要なすべての更新を行った後、構成オプションを変更してその機能を有効にします。しかし、これは非常に重いコードを作成します...

2番目のコードは、移行を管理することです。私は、コードの変更が実行時に移行を処理するように記述されているサイトについて聞いたことがあります。使用されているスキーマのバージョンとそれが戻ってきたデータの形式を検出することができます。古いスキーマからのデータであれば、その場所での移行が実行されます。 。自然のサイトの使用状況から、データの大半はサイトを使用している人が移行し、残りは必要に応じていつでも移行スクリプトを使用して移行できます。

しかし私はこの時点でGoogleがあなたの友人になると思います。なぜなら、解決策は非常にコンテキスト固有であり、私はこの回答が無意味になることを心配しているからです。あなたは多くのアイデアを持ったthisのような結果を得るでしょう...

+0

この回答に感謝します。この2番目の部分をどのように達成しているかについて少し簡単に説明してください。 – David542

+1

問題の2番目の部分についてもう少し詳細を追加しました。それはあなたの規模にもよります - あなたの寝室からあなたがホスティングしているかもしれないブログとはまったく異なるこの問題をFacebookが処理しなければなりません! –

+0

あなたの時間のためにすばらしい、ありがとう – David542

4

コードベースが〜40K行のプロダクションサーバーにはSouthを使用していますが、これまでのところ問題はありませんでした。私たちはまた、私たちのモデルのいくつかのためのいくつかの主要なリファクタを介してされており、私たちはゼロの問題を抱えていました。

私たちが持っていることの1つはモデルのバージョン管理であり、ソフトウェア側のモデルに加えた変更を元に戻して、実際のデータよりも多くの部分をSouth側に戻すのに役立ちます。我々は使用するDjango Reversion

+1

私はちょうどDjango Reversionのドキュメントを読んでいますが、なぜなら、同じ方法で(そしてSVNやgitのような)「適切な」SCMを使用してモデルを管理する理由がわかりませんでした。 as)あなたのサイトのコードの残りの部分。私は何を取りこぼしたか? –

+0

@ MarkStreatfield:Reversionは、構造ではなく時間の経過とともにモデルの_content_を管理するためのものです。 –

+0

ああ、わかりました、明確化のおかげで - 私は完全に何とかそれを逃した。だから、この質問に記載されているものに似た何かをするのが役に立ちます。http://stackoverflow.com/questions/39281/database-design-for-revisions/126468? –

1

サウスはどこにでも使われています。私のorgainzationのように、私たちは3レベルのコードテストをしています。 1つはローカル開発環境、もう1つは開発環境です.3つ目はプロダクション環境です。

ローカルデベロッパーは、開発者の手元にあり、必要に応じてプレイすることができます。その後、dbを変更して最初にステージングを行い、すべてがうまく動作しているかどうかを確認してから、手動でプロダクションを変更するまで、dbの変更をライブサイトで実行するまで、生産と同じに保たれているdevをステージングしますdbはそれをステージングと同じにします。

1

データベースが非自明であるとPostgreSQL場合には、優れた選択肢の全体の束は、SQL-賢明あります

  • スナップショットとは、バックアップサーバ
  • トライアルアップグレードに
  • ライブレプリケーションをロールバックその後、

トライアルアップグレードオプションがいいです(ただし、最高のスナップショットとのコラボレーションで行われ)

を生きますあなたは上記の構成を好きですが、あなたはそれが二回アップグレードを実行するのにかかる時間を心配している場合
su postgres 
pg_dump <db> > $(date "+%Y%m%d_%H%M").sql 
psql template1 
# create database upgrade_test template current_db 
# \c upgradetest 
# \i upgrade_file.sql 
...assuming all well... 
# \q 
pg_dump <db> > $(date "+%Y%m%d_%H%M").sql # we're paranoid 
psql <db> 
# \i upgrade_file.sql 

、あなたは書き込みのためデシベルをロックすることができ、その後、upgradetestへのアップグレードがうまくいけば、あなたはその後の名前を変更することができますdb~dboldおよびupgradetest~db。多くのオプションがあります。

あなたがしたいすべての変更、非常に便利にpsqlコマンド\set ON_ERROR_STOP 1を一覧表示するSQLファイルを持っている場合。これは何かがうまくいかなくなったときにそのトラックのアップグレードスクリプトを停止します。そして、多くのテストで、何もしないことを確認できます。

this StackOverflowの答えで述べた番号で、利用可能なツールを差分のデータベーススキーマの全体のホストがあります。しかし、それは基本的に手作業で行うのは非常に簡単です...

pg_dump --schema-only production_db > production_schema.sql 
pg_dump --schema-only upgraded_db > upgrade_schema.sql 
vimdiff production_schema.sql upgrade_schema.sql 
or 
diff -Naur production_schema.sql upgrade_schema.sql > changes.patch 
vim changes.patch (to check/edit) 
3

は、私は時々、この問題に(他の回答を読んで、おそらくそれは型破りではありません)型破りなアプローチをとっています。私はちょうどそれをいくつかの実験を行ったので、私はジャンゴでそれを試したことはありません。要するに

、私はコードが古いスキーマから生じた例外をキャッチし、適切なスキーマのアップグレードを適用してみましょう。私はこれが受け入れられた答えであるとは期待していません。それは、場合によっては(そして決して論外かもしれない)場合にのみ適切です。しかし、私はそれが醜い鴨の優雅さを持っていると思う。もちろん

、私は任意の時点で生産状態にリセットすることができ、テスト環境を持っています。そのテスト環境を使用して、私はいつものように自分のスキーマを更新し、それに対してコードを書く。

次に、スキーマの変更を元に戻して、新しいコードを再度テストします。結果のエラーを捕捉し、スキーマのアップグレードを実行して、間違ったクエリを再試行します。それは一度だけ働き(生産に入れたときに起こり得るような)を複数回呼ばれていた場合ように、それは「害しない」になるよう

アップグレード機能を記述する必要があります。

実際のPythonコード - 私はコンセプトをテストするために私のsettings.pyの終わりにこれを置くが、あなたはおそらく別のモジュールでそれを維持したいでしょう:

from django.db.models.sql.compiler import SQLCompiler 
from MySQLdb import OperationalError 

orig_exec = SQLCompiler.execute_sql 
def new_exec(self, *args, **kw): 
    try: 
     return orig_exec(self, *args, **kw) 
    except OperationalError, e: 
     if e[0] != 1054: # unknown column 
      raise 
     upgradeSchema(self.connection) 
     return orig_exec(self, *args, **kw) 
SQLCompiler.execute_sql = new_exec 

def upgradeSchema(conn): 
    cursor = conn.cursor() 
    try: 
     cursor.execute("alter table users add phone varchar(255)") 
    except OperationalError, e: 
     if e[0] != 1060: # duplicate column name 
      raise 

本番環境が起動したら現在までに、この自己アップグレードコードをコードベースから削除することは自由です。しかし、あなたがそうしなくても、コードは重大な不必要な作業をしていません。

私のケースでは例外クラス(私の場合はMySQLdb.OperationalError)と数字(1054「不明な列」/ 1060「重複列」)をデータベースエンジンとスキーマの変更に合わせる必要がありますが、簡単です。

他のいくつかの問題ではなく、問題のスキーマ変更のために実行中のSQLが実際にエラーが発生していることを確認するために追加のチェックを追加したい場合があります。唯一の不利な点は、そのような状況では、例外を発生させる前にアップグレードと悪質なクエリを2回試行するということです。

のpythonについての私の好きなものの一つは、簡単にこのような実行時にシステム・メソッドをオーバーライドする自分の能力です。非常に柔軟性があります。

関連する問題