04-30 02:19
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[MongoDB] GridFS 본문

Data Science/MongoDB

[MongoDB] GridFS

cinema4dr12 2014. 3. 6. 22:52

by Geol Choi | 

이번 글에서는 비교적 큰 사이즈의 바이너리 파일을 저장하는 메커니즘인 "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"에 대해서 살펴보았다.


이전 글에서 JavaScript 기반의 서버 스크립팅인 Node.js를 통해 MongoDB를 사용하는 방법에 대해 다룬바 있다. Node.js의 MongoDB 오브젝트 모델인 mongoose를 통해 GridFS를 구현하고자 한다면 다음 자료를 참고하기 바란다.


Comments