Redmine で添付ファイルはデータベースに格納しないの?

先日の記事でもちょっと書いていましたが、Redmine ではチケットへの添付ファイルや文書の登録、また Wiki に貼り付けた画像やその他の添付ファイルは、REDMINE_ROOT 以下の files フォルダに格納されます。

チケットへの添付ファイルの追加

  • (snip)
  • 添付ファイルは REDMINE_HOME のfiles 以下にファイル名に prefix をつけて格納される
    • これは文書やそれ以外での添付のときでも同じ


改めて考えてみると、添付ファイル等だけがディスクで管理されるのは、以下の問題があるようにも思えてきます。


データベースだけでなく files 以下も忘れずにバックアップしないといけないのは微妙に面倒ですし、クラスタを組んだ場合にローカルディスク管理の添付ファイルをほかのインスタンスからどう参照するか? といった問題もついてまわります。


Redmine.JP で「Apache上でRuby on Railsアプリケーションを動かす/Passenger(mod_rails for Apache)の利用」なんて記事も見かけましたが、複数インスタンスを並列稼働させることによるレスポンスの改善には言及されているものの、添付ファイルまわりの解決についてはとくに触れられてなかったりします。


で、こんなことはすでに誰かが考えてるだろうと思って、Web を漁ってたらフォーラムで次の投稿を見かけました。

Adding the attachments to the database means one entity to backup, one entity to restore (or migrate). Also allows redmine to be proxied across machines in a cluster for load balancing without doing special filesystem sharing.

2008年の4月頃に起票されて、すでにクローズとなっているチケットです。 (^^;
上記のとおり、添付ファイルもデータベースに格納できるようにしてほしい、といった要望なのですが、


... ここから抜粋 & 適当訳 ...

The idea of storing files in the db may have some merit, but this is clearly a design decision and not a defect.

添付ファイルをディスクに管理するようにしたのは、設計上の判断。

This would make an excellent feature as a configurable option for the reasons Carl mentioned.

設定オプションで切り替えられるってのはいいね。

Storing standalone files in databases is just totally missing the point of what filesystems are made for. I admit one might like the idea of a single-point, network-enabled, access to all the data. But putting blobs in the DB is a poor design, really. Jean Philippe was right in his design.

If you want single-point access to the data, accessible through network, do not put blobs in the DB, this will not be the correct design. Better write an abstraction client/server layer, let's call this a proxy, between RedMine data access and actual data storage. You might find inspiration from the ZEO / ZODB design for Zope, although I would not recommend to mimic it entirely.

DB に blob でただつっこむってのはイケてない設計だよ。
ネットワーク越しにアクセスできるようにしたいなら、blob につっこむのは正しい設計じゃない。クライアント/サーバーな抽象化層を挟んだほうがよいよ。Redmine のデータアクセスと実際のデータストレージ間のプロキシと呼べるもの。この発想は Zope の ZEO / ZODB からも得られるよ。ただ真似するってのはおすすめじゃないけどね。

I can think of a lot of good reasons to not toss files into the database:

  1. It balloons the db size, making backups take longer.
  2. It puts extra work on the db, which has plenty to do as is.
  3. It means files would have to be serialized through rails (because there is no file for the webserver to point to) -- which means that rails process will block incoming web requests while the file is being downloaded. There are ways around this, but they are really hackish, or don't lend well to simple deployments.
  4. There are a ton of database "gotchas" that ActiveRecord can't abstract away when dealing with blobs.

Plus, backing up files is exceedingly easy. Just rsync them to another box. I admit it might not be blatantly obvious that you need to do it, but I think that's a point for documentation rather than creating a ton of work with little real-world benefit.

If you need single-point access to the data over a network, just use a NFS/SMB share. It is plenty fast for attachments.

ファイルをデータベースに格納しないほうがよい理由がたくさん思いつくよ。
DB のサイズも増えるし、その分バックアップ時間もかかる。余計な仕事を DB にさせたくない。ファイルは Railsシリアライズされることになるし、ファイルがダウンロードされてる間は Rails プロセスもブロックされる。AR は blob を抽象的に扱えない、とかね。

ファイルをバックアップするのはずっと簡単。別筐体に rsync すればいい。複数インスタンスをたてた場合は、NFS や SMB で共有すればいいじゃん。速いしね。

If it's a bad idea, then I suggest dropping the feature. If so, I'll file feature request for configurable storage location and a backup script that backs up the db, attachment files, and configuration to some specified location.

格納場所を設定可能するとか、DB / 添付ファイル / 設定ファイルなどをバックアップするスクリプトがほしいよ。

I've added a few words about this at the end of RedmineInstall guide.

(そんな感じのスクリプトを) Redmine インストールガイドの最後にちょっと追記しといた。


... ここまで ...


ってな感じでチケットはクローズしています。

実際、インストールガイドを見てみると、こんな感じ。

Installing Redmine

Backups
Redmine backups should include:

  • data (stored in your redmine database)
  • attachments (stored in the files directory of your Redmine install)

Here is a simple shell script that can be used for daily backups (assuming you're using a mysql database):

# Database
/usr/bin/mysqldump -u -p | gzip > /path/to/backup/db/redmine_`date +%y_%m_%d`.gz

# Attachments
rsync -a /path/to/redmine/files /path/to/backup/files