이번 포스에서는 비교적 큰 사이즈의 바이너리 파일을 저장하는 메커니즘인 GridFS
에 대해 알아보도록 하겠습니다.
예를 들어, 블로그 같이 글을 작성하는 사이트를 만들어 DB와 연동할 경우 텍스트만이 아닌 이미지, 또는 특정 어플리케이션의 바이너리를 저장해야 할 것입니다. MongoDB는 이러한 바이너리 파일을 효율적으로 관리하는 메커니즘을 제공하는데 이것이 GridFS
입니다.
GridFS
를 사용해서 파일을 저장해야 하는 이유를 들면 다음과 같습니다:
GridFS
는 MongoDB를 위해 설정한replication
이나autosharding
을 활용합니다. 이는 패일오버(Failover) 및 스케일아웃(Scale-out)을 하는데 매우 쉽습니다 (Replication과 Autosharding에 대해서는 추후 자세히 다루도록 하겠습니다).GridFS
는 업로드 시 (NTFS, FAT 등과 같은) 파일시스템에 대한 문제를 말끔히 해결해 줍니다. 예를 들어, 이러한 파일시스템이 문제가 될 수 있는 경우는 동일한 디렉터리 내에 엄청난 개수의 파일들을 저장하는 일입니다.GridFS
를 이용하면 파일 로컬성(Locality)에 대해 매우 유리합니다. 이는, MongDB가 파일 업로드 시 파일의 크기를 2GB 크기의 덩어리로 분할하기 때문입니다.
그러면 이제부터 실질적인 연습을 해 보도록 하겠습니다.
(MacOS 환경으로 설명이 진행되겠지만 Windows도 방식은 동일합니다. 즉, Unix 명령으로 진행되지만 Windows에서도 쉽게 따라할 수 있으리라 생각됩니다.)
GridFS 시작하기: mongofiles
GridFS
를 시작하는 가장 쉬운 방법은 mongofiles
유틸리티를 이용하는 것입니다. 이 유틸리티는 MongoDB 설치 시 다운로드 한 폴더 내에 있습니다.
예를 들면 다음과 유사한 경로입니다:
/mongodb-osx-x86_64-version/bin/mongofiles
mongofiles
는 MacOS(Unix 실행파일)나 Windows(.exe) 또는 Linux 등의 OS에 따라 확장자가 다르게 표시됩니다.
예를 들면 MacOS의 경우, 다음 그림과 같이 Unix 실행파일로 표시됩니다.
mongofiles
를 사용할 경우에도 MongoDB 서버가 실행되고 있어야 합니다.
우선 mongofiles
의 헬프 리스트를 확인해 보도록 하겠습니다:
$ mongofiles --help
Browse and modify a GridFS filesystem.
usage: mongofiles [options] command [gridfs filename]
command:
one of (list|search|put|get)
list - list all files. 'gridfs filename' is an optional prefix
which listed filenames must begin with.
search - search all files. 'gridfs filename' is a substring
which listed filenames must contain.
put - add a file with filename 'gridfs filename'
get - get a file with filename 'gridfs filename'
delete - delete all files with filename 'gridfs filename'
options:
--help produce help message
-v [ --verbose ] be more verbose (include multiple times
for more verbosity e.g. -vvvvv)
--version print the program's version and exit
-h [ --host ] arg mongo host to connect to ( <set
name>/s1,s2 for sets)
--port arg server port. Can also use --host
hostname:port
--ipv6 enable IPv6 support (disabled by
default)
-u [ --username ] arg username
-p [ --password ] arg password
--authenticationDatabase arg user source (defaults to dbname)
--authenticationMechanism arg (=MONGODB-CR)
authentication mechanism
--dbpath arg directly access mongod database files
in the given path, instead of
connecting to a mongod server - needs
to lock the data directory, so cannot
be used if a mongod is currently
accessing the same path
--directoryperdb each db is in a separate directly
(relevant only if dbpath specified)
--journal enable journaling (relevant only if
dbpath specified)
-d [ --db ] arg database to use
-c [ --collection ] arg collection to use (some commands)
-l [ --local ] arg local filename for put|get (default is
to use the same name as 'gridfs
filename')
-t [ --type ] arg MIME type for put (default is to omit)
-r [ --replace ] Remove other files with same name after
PUT
간단한 텍스트 파일을 생성하고 이 파일을 GridFS를 통해 업로드하는 방법은 다음과 같습니다:
$ echo "Hello, world" > foo.txt
$ mongofiles put foo.txt
connected to: 127.0.0.1
added file: { _id: ObjectId('531885f2a743d75dbe96fd17'), filename: "foo.txt", chunkSize: 262144, uploadDate: new Date(1394116082899), md5: "a7966bf58e23583c9a5a4059383ff850", length: 13 }
done!
Hello, world
라는 문자열을 갖는 텍스트 파일 foo.txt
파일을 생성하였고, 이 파일은 mongofiles
를 실행한 폴더 내에서 찾을 수 있을 것입니다.
이제 list
옵션을 통해 업로드가 되었는지 확인해 보도록 하겠습니다:
$ mongofiles list
connected to: 127.0.0.1
foo.txt 13
이제 MongoDB에 저장된 파일을 다운로드 하기에 앞서 foo.txt
파일을 삭제하겠습니다.
폴더 내에서 delete
키를 사용해서 직접 삭제해도 괜찮고 명령을 통해 삭제해도 상관없습니다:
$ rm foo.txt
이제 폴더 내에는 foo.txt
파일이 더이상 존재하지 않습니다. MongDB에 업로드 된 foo.txt
를 다운로드 해 보도록 합니다:
$ mongofiles get foo.txt
connected to: 127.0.0.1
done write to: foo.txt
mongofiles가 실행된 폴더의 파일을 살펴보면 foo.txt
파일이 보일 것입니다.
이렇게 파일이 업로드 된 후, MongoDB 명령 쉘에서 컬렉션 리스트를 살펴보면:
> db.getCollectionNames()
[ "fs.chunks", "fs.files", "school", "schools", "system.indexes" ]
fs.chunks
와 fs.files
두 개의 컬렉션이 생성되어 있음을 확인할 수 있을 것입니다.
우선 fs.chunks
컬렉션의 내용을 살펴보면:
> db.fs.chunks.find().pretty()
{
"_id" : ObjectId("531885f2598bf40a9446eede"),
"files_id" : ObjectId("531885f2a743d75dbe96fd17"),
"n" : 0,
"data" : BinData(0,"SGVsbG8sIHdvcmxkCg==")
}
다른 컬렉션과 마찬가지로 _id
가 부여되고 여기에 더하 파일 아이디 files_id
가 함께 부여됩니다.
data
는 파일 덩어리를 구성하는 바이너리 데이터터를 포함합니다.
이제 fs.files
컬렉션의 도큐먼트를 살펴보도록 하겠습니다:
> db.fs.files.find().pretty()
{
"_id" : ObjectId("531885f2a743d75dbe96fd17"),
"filename" : "foo.txt",
"chunkSize" : 262144,
"uploadDate" : ISODate("2014-03-06T14:28:02.899Z"),
"md5" : "a7966bf58e23583c9a5a4059383ff850",
"length" : 13
}
fs.files
key 값들에 대해 자세하게 알아보도록 하겠습니다:
-
_id
오브젝트 아이디입니다. 이 아이디는
fs.files
컬렉션과fs.chunks
컬렉션이 공유합니다. -
filename
저장된 파일의 이름입니다.
-
chunkSize
파일을 구성하는 각 덩어리(chunk)의 크기이며 바이트(byte)를 의미합니다. 기본적으로 256 KB이나 필요에 따라 조정할 수 있습니다.
-
uploadDate
파일이 업로드 된 날짜입니다.
-
md5
파일 내용의 검사 합(checksum)이며, 서버 측에서 생성됩니다. md5는 일반적으로 파일의 무결성 검사를 위한 암호화 해시(hash) 함수 중 하나입ㄴ다. md5에 대해 자세히 알고 싶다면 여기를 클릭합니다.
-
length
파일 내용의 전체 크기이며 단위는 바이트(byte)입니다.
꽤 간단하지 않나요? 지금까지 예제를 통해 mongofiles
의 옵션 --help
, put
, list
, get
에 대해서 살펴보았습니다.