공부/DB

몽고DB에 문서 대량 삽입하기

Stair 2025. 8. 6. 15:17
반응형

MongoDB에 더미파일을 넣으려고 하는데 MongoDB Compass로는 한계가 있어 Java Maven 프로젝트를 활용하여 집어넣어보려고 한다.

Maven 프로젝트에서 Java 드라이버를 사용하여 만든다.

 

이후 클래스 파일을 하나 만들었다.

public class InsertLargeData {

    public static void main(String[] args) {
    	//ip에 따라 localhost의 값이 변경되어야함
        String uri = "mongodb://localhost:27017";

        try (MongoClient mongoClient = MongoClients.create(uri)) {
            Document pingResult = mongoClient.getDatabase("admin").runCommand(new Document("ping", 1));

            System.out.println("MongoDB 연결 성공");
            System.out.println("핑 결과: " + pingResult.toJson());

        } catch (Exception e) {
            System.err.println("MongoDB 연결 실패: " + e.getMessage());
            e.printStackTrace();
        }
    }
}


localhost는 본인의 사정에 맞게 맞추어야 한다.

 

연결 테스트를 시작해보자.

MongoDB 연결 성공!
핑 결과: {"ok": 1.0, "$clusterTime": {"clusterTime": {"$timestamp": {"t": 1754437573, "i": 13}}, "signature": {"hash": {"$binary": {"base64": "HGKgyPnpul1wc04yxJ/Z6CdHQDU=", "subType": "00"}}, "keyId": 7527603671471751174}}, "operationTime": {"$timestamp": {"t": 1754437573, "i": 13}}}

 

정상적으로 연결 된 것을 확인할 수 있다.

 

그럼 이제 문서 대량 삽입을 시도해보도록 하자.

 

과부화를 유발시키기 위해 총 1억개의 문서를 생성하고,한번에 10만개의 문서를 삽입하려 한다.

public class InsertLargeData {
    public static void main(String[] args) {
        // MongoDB 연결 정보
        String uri = "mongodb:// ~ ";
        String dbName = " ~ ";
        String collectionName = " ~ ";

        // 총 생성할 문서 수
        final int totalDocuments = 100_000_000;
        // 한 번에 삽입할 문서 수 (청크 크기)
        final int chunkSize = 100_000;

        try (MongoClient mongoClient = MongoClients.create(uri)) {
            MongoDatabase database = mongoClient.getDatabase(dbName);
            MongoCollection<Document> collection = database.getCollection(collectionName);

            System.out.println("MongoDB에 성공적으로 연결되었습니다.");

            // 청크 단위로 문서 삽입
            for (int i = 0; i < totalDocuments / chunkSize; i++) {
                List<Document> documents = new ArrayList<>();
                int startId = i * chunkSize;

                for (int j = 0; j < chunkSize; j++) {
                    documents.add(
                            new Document("_id", startId + j)
                                    .append("name", "User_" + (startId + j))
                                    .append("email", "user" + (startId + j) + "@example.com")
                                    .append("createdAt", new java.util.Date())
                    );
                }

                collection.insertMany(documents);
                System.out.println((i + 1) * chunkSize + " / " + totalDocuments + "개 문서 삽입 완료");
            }

            System.out.println("\n총 " + totalDocuments + "개의 문서 삽입이 완료되었습니다.");

        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("데이터 삽입 중 오류가 발생했습니다.");
        }
    }
}

 

삽입을 시도하는데 오류가 발생하였다.

 

MongoDB에 성공적으로 연결되었습니다.
com.mongodb.MongoCommandException: Command failed with error 13 (Unauthorized): ...

(뒷부분은 문제가 있을 수 있으므로 잘라내었다.)

 

DB 연결 자체는 되었지만, MongoDB에 인증 없이 연결을 시도했기 때문에 발생하는 에러라고 한다.

사용자 이름과 비밀번호를 사용하여 인증해야만 DB작업을 허용하도록 설정되어있기 때문이라고 한다.

현재 인증정보가 제공되지 않은 상태에서 insert 명령을 실행했기 때문에 발생한 문제랜다.

 

해결 방법 : MongoDB에 연결할 때 사용자 이름과 비밀번호를 제공해주면 된다.

 

일단 root 권한을 가진 사용자를 생성하기 위해 MongoDB Compass에서 createUser()를 해주기로 결정하였다.

 

db.createUser(
   {
     user: "admin",
     pwd: passwordPrompt(),
     roles: [
        { role: "root", db: "~" }
     ]
   }
);

본인의 DB 이름과 같게 매칭을 하고 role을 root로 부여하여야 한다.

passwordPrompt()를 사용하면 프롬프트에서 비밀번호를 설정할 수 있다.

MongoServerError[Unauthorized]: not authorized on ...

 

또 에러가 발생하였다. 이번엔 MongoDB에 로그인한 사용자가 DB에 새로운 사용자를 생성할 권한이 없다고 한다.

 

현재 내가 사용하고 있는 DB는 Local이 아니라 업체 측이 가지고 있는 DB여서, 지금 당장 내가 해결할 수 없는 것 같아. 업체측에 문의를 드렸다.

 

확인 결과 현재 사용자의 role 문제였고, 문제를 해결한 뒤 프로그램을 실행하였다.

 

솔직히 못버틸 줄 알았는데 OPS Manager의 Metrics를 확인해보니 아직까지는 괜찮은 것 같다. 한번에 삽입하는 청크 크기가 10만개여도 버틴다. 한번에 100만개도 테스트 해보고 된다하면 1000만개 1억개까지 넣어보려고 한다.

 

 

쓰레드를 나누어 대량삽입하는 코드를 만들었다.

        // MongoDB 연결 정보
        String uri = "mongodb://";
        String dbName = "";
        String collectionName = "";

        // 과부하를 위한 설정
        final int totalDocuments = 100_000_000;  // 총 1억 개
        final int chunkSize = 1_000_000;       // 한 번에 100만 개씩 삽입
        final int concurrentTasks = 100;       // 동시에 100개 작업 실행

        // 청크 수를 계산
        final int totalChunks = totalDocuments / chunkSize;

        // 스레드 풀 생성 (동시에 실행할 작업 수만큼 스레드를 만듭니다)
        ExecutorService executor = Executors.newFixedThreadPool(concurrentTasks);

        try (MongoClient mongoClient = MongoClients.create(uri)) {
            MongoDatabase database = mongoClient.getDatabase(dbName);
            MongoCollection<Document> collection = database.getCollection(collectionName);

            System.out.println("MongoDB에 성공적으로 연결되었습니다.");

//             기존 데이터 삭제 (선택 사항)
//             collection.deleteMany(new Document());

            long startTime = System.currentTimeMillis();

            // 청크 단위로 작업을 스레드 풀에 제출
            for (int i = 0; i < totalChunks; i++) {
                final int chunkIndex = i;
                executor.submit(() -> {
                    try {
                        List<Document> documents = new ArrayList<>();
                        int startId = chunkIndex * chunkSize;

                        for (int j = 0; j < chunkSize; j++) {
                            documents.add(
                                    new Document("_id", startId + j)
                                            .append("data", Math.random())
                                            .append("timestamp", new java.util.Date())
                            );
                        }

                        collection.insertMany(documents);
                        System.out.printf("✅ %d / %d개 문서 삽입 완료 (청크 #%d)\n",
                                (chunkIndex + 1) * chunkSize, totalDocuments, chunkIndex);
                    } catch (Exception e) {
                        System.err.printf("❌ 청크 #%d 삽입 중 오류 발생: %s\n", chunkIndex, e.getMessage());
                    }
                });
            }

            // 모든 작업이 완료될 때까지 대기
            executor.shutdown();
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);

            long endTime = System.currentTimeMillis();
            System.out.printf("\n🎉 총 %d개의 문서 삽입이 완료되었습니다. (소요 시간: %.2f초)\n",
                    totalDocuments, (endTime - startTime) / 1000.0);

        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("데이터 삽입 중 오류가 발생했습니다.");
        }
    }

 

코드를 돌려보니 클라이언트PC가 버티질 못한다...

 

과부하테스트는 더이상 진행을 못할거 같다

 

반응형

'공부 > DB' 카테고리의 다른 글

MongoDB 4장(MongoDB 모델링)  (2) 2025.08.01
MongoDB 3장  (4) 2025.07.31
MongoDB 2장  (3) 2025.07.30
MongoDB 1장  (1) 2025.07.28