ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [MongoDB] 7. GridFS로 대용량 파일 처리
    CSE/MongoDB 2015. 6. 13. 11:48

    이번 포스팅은 GridFS로 파일처리를 해보도록 하겠습니다!

    우선 GridFS란??
     "데이터에비스에 이진 데이터를 저장하기 위한 몽고DB의 해법"이라고 일단락 지어두죠.
     
     이론적 설명: 설계상, 몽고DB 다큐먼트(BSON 객체)는 16MB를 넘을 수 없습니다. 이런 제약은 최적의 수준으로 성능을 유지하기 위해서 입니다. 위 크기보다 커지게 되면, 질의시 메모리를 엄청나게 소비합니다. GridFS는 대규모 파일을 여러 다큐먼트로 쪼개는 기법을 명세합니다. 이를 구현하는 언어 드라이버(ex: PHP driver)가 저장된 파일을 분리하는 작업은 이면에 숨겨져 있죠. 이 드라이버를 사용하는 개발자는 내부 지식이 필요하지 않습니다. 이런 식으로 GridFS는 개발자에게 파일을 투명하고 효율적인 방법으로 저장하고 조작하는 작업을 허용하게 됩니다. 

    자 그럼 이번 장의 실습 순서를 보겠습니다.
     1. GridFS로 이미지 올리기
     2. GridFS에서 이미지 서비스하기
     3. chunks에서 이미지 읽기

    먼저, dbconnection.php와 style.css를 가져와 둡시다.








    1. GridFS로 이미지 올리기
    먼저, upload.php를 작성합니다.

    upload.php
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
     
    <?php
    require 'dbconnection.php';
     
    $action = (isset($_POST['upload']) && $_POST['upload'] === 'Upload') ? 'upload' : 'view';
     
    switch ($action) {
    case 'upload': {
    // 파일 업로드 성공을 검사
    if ($_FILES['image']['error'] !== 0) {
    die("Error uploading file. Error code ".$_FILES['image']['error']);
    }
     
    $mongodb = DBConnection::instantiate();
    $gridFS = $mongodb->database->getGridFS();
    $filename = $_FILES['image']['name'];
    $filetype = $_FILES['image']['type'];
    $tmpfilepath = $_FILES['image']['tmp_name'];
    $caption = $_POST['caption'];
     
    // 업로드된 파일을 저장
    $id = $gridFS->storeFile($tmpfilepatharray('filename' => $filename,
     'filetype' => $filetype,
     'caption' => $caption)
    );
    break;
    }
     
    default:
    }
    ?>
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <link rel="stylesheet" href="style.css"/>
            <title> Upload Files </title>
        </head>
        <body>
            <div id="contentarea">
                <div id="innercontentarea">
                    <h1> Upload Image </h1>
                    <?php if ($action === 'upload'):?>
                        <h3> File Uploaded. Id <?php echo $id;?>
                            <a href="<?php echo $_SERVER['PHP_SELF']; ?>">
                                Upload another?
                            </a>
                        </h3>
                    <?php else:?>
                        <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST" accept-charset="utf-8" enctype="multipart/form-data">
                            <h3> Enter Caption&nbsp;
                                <input type="text" name="caption" />
                            </h3>
                            <p>
                                <input type="file" name="image"/>
                            </p>
                            <p>
                                <input type="submit" name="upload" value="Upload"/>
                            </p>
                        </form>
                    <?php endif;?>
                </div>
            </div>
        </body>
    </html>
     
    cs




    다음, dbconnection.php의 DBNAME상수를 'myfiles'로 변경합니다.







     

    1
    2
    3
     
            const DBNAME = 'myfiles';
     
    cs




    브라우저에서 upload.php를 열어줍니다. 파일 Caption을 입력하고, 파일 선택을 눌러 이미지 파일을 골라주세요.
    그러고나서 Upload를 눌러주면 됩니다.






    아래와 같이 나오면 성공!!



     




    몽고 쉘에서도 확인해 봐야겠죠???

    use myfiles
    db.fs.files.find() 


    해주시면 이미지가 들어간게 나옵니다!!!




     







    2. GridFS에서 이미지 서비스하기
    list.php 파일을 작성합니다.

    list.php


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    <?php
    require 'dbconnection.php';
     
    $mongo = DBConnection::instantiate();
    $gridFS = $mongo->database->getGridFS();
    $objects = $gridFS->find();
    ?>
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <link rel="stylesheet" href="style.css"/>
            <title> Uploaded images </title>
        </head>
        <body>
            <div id="contentarea">
                <div id="innercontentarea">
                    <h1> Uploaded images </h1>
                    <table class="table_list" cellpadding="0" cellspacing="0">
                        <thead>
                            <tr>
                                <th width="40%">Caption </th>
                                <th width="30%">Filename </th>
                                <th width="*">Size </th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php while ($object = $objects->getNext()):?>
                                <tr>
                                    <td><?php echo $object->file['caption'];?></td>
                                    <td>
                                        <a href="image.php?id=<?php echo $object->file['_id'];?>">
                                            <?php echo $object->file['filename'];?>
                                        </a>
                                    </td>
                                    <td><?php echo ceil($object->file['length'] / 1024).' KB';?></td>
                                </tr>
                            <?php endwhile;?>
                        </tbody>
                    </table>
                </div>
            </div>
        </body>
    </html>
     
    cs


     



    다음으로 image.php파일을 작성합니다.

    image.php
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    <?php
    $id = $_GET['id'];
    require 'dbconnection.php';
     
    $mongo = DBConnection::instantiate();
    $gridFS = $mongo->database->getGridFS();
     
    // 파일 객체를 질의
    $object = $gridFS->findOne(array('_id' => new MongoId($id)));
     
    // Content-type 헤더를 설정, 브라우저 출력
    header('Content-type: '.$object->file['filetype']);
     
    echo $object->getBytes();
    ?>
     
     
    cs


     



    브라우저에서 list.php파일을 수행합니다. 그러면 아까 1번에서 올린 사진이 들어가 있습니다. 사진파일 명을 클릭해주세요!




     





    그러면 저는 Eva green을 좋아하기 때문에 요런 사진을 출력하네요~












    3. Chunks에서 이미지 읽기
     직전 예제에서 getBytes() 메소드를 사용해 파일 내용을 읽었습니다. getBytes()가 파일의 전체 내용을 메모리에 올리려고 시도하기에 이런 접근 방식에 잠재적인 문제가 있습니다!! 그래서!!! chunks에 파일 내용이 나뉘어져 있습니다. 이 chunk를 이용한 실습을 진행하겠습니다.


    stream.php


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    <?php
    $id = $_GET['id'];
    require 'dbconnection.php';
     
    $mongo = DBConnection::instantiate();
    $gridFS = $mongo->database->getGridFS();
    $object = $gridFS->findOne(array('_id' => new MongoId($id)));
     
    // 이파일에 대한 chunk를 찾는다.
    $chunks = $mongo->database->fs->chunks->find(array('files_id' => $object->file['_id']))->sort(array('n' => 1));
     
    header('Content-type: '.$object->file['filetype']);
     
    foreach($chunks as $chunk) {
    echo $chunk['data'] -> bin;
    }
     
    ?>
     
     
    cs


     


    다음으로 list.php 파일에서 <a href="image.php?id................ 요부분을 찾아서 아래처럼 바꿔주세요!!



     

    1
    2
    3
     
    <a href="stream.php?id=<?php echo $object->file['_id'];?>">
                                        
    cs





    그 다음, 실행!!!!! 아까와 똑같은 list.php입니다. 기능적으로는 동일하죠. Filename을 클릭하세요.



     







    그러면 아래와 같이 chunks를 읽어서 이미지를 출력합니다.(이번에도 Eva green~)











    chunks를 이용하면 직전의 image.php보다 작업 과정에서 메모리를 적게 소비합니다. 왜냐하면 stream.php에서는 동일한 메모리를 계속해서 재사용하기 때문이죠~


    자 이렇게 좋은 GridFS가 사용이 되면 안될 때가 있습니다~
     몽고DB는 주 핵심은 확장성입니다. 어플리케이션을 수평 확장하도록 도와주기 위한 기능을 염두해서 설계되었죠. 이러한 몽고DB가 트래픽의 규모가 작거나 중간 정도인데 이 GridFS를 쓰면 파일 서비스는 Xhit 입니다!!!!! 

     또한, 작은 정적 파일(웹사이트에서 JS와 CSS등)을 서비스할 경우에 파일 시스템 상에서 아파치나 엔진엑스 웹 서버를 사용하는 경우가 GridFS보다 더 빠르다는 사실이 벤치마크 결과로 나와있다네요~ 따라서 HTTP로 작은 파일만 서비스할 필요가 있다면 파일 시스템에 의존해야 마땅하답니다~



    개념 정리를 마지막으로 이 포스팅을 마치겠습니다~


    댓글

Designed by Tistory.