MongoDB Atlas로 복원력이 뛰어난 애플리케이션 구축하기
이 페이지의 내용
미션 크리티컬 애플리케이션 을 구축할 때는 프로덕션 환경에서 발생할 수 있는 예기치 않은 이벤트에 대비하는 것이 중요합니다. 여기에는 예기치 않은 느린 쿼리, 누락된 인덱스 또는 워크로드 볼륨의 급격한 증가가 포함됩니다.
MongoDB Atlas 는 상황에 사전에 대비하고 사후적으로 대응할 수 있는 즉시 사용 가능한 기능을 갖추고 있어 복원력이 뛰어난 애플리케이션 을 빌드 할 수 있도록 도와줍니다. 복원력이 뛰어난 애플리케이션 을 빌드 하려면 다음 클러스터 회복 탄력성 과 애플리케이션 및 클라이언트 사이드 권장사항에 따라 MongoDB deployment 를 구성하는 것이 권장사항.
클러스터 복원력
클러스터 의 복원력을 개선하려면 클러스터 를 MongoDB 8.0으로 업그레이드 합니다. MongoDB 8.0 은 회복 탄력성 과 관련된 다음과 같은 성능 개선 사항 및 새로운 기능을 도입합니다.
비용이 많이 드는 쿼리를 반응적으로 완화하는 작업 거부 필터
값비싼 읽기 작업에 대한 사전 예방적 보호를 위한 클러스터 수준의 시간 초과
moveCollection 명령으로 워크로드 격리 개선
향상된 메모리 관리
프로덕션 환경에서 애플리케이션 을 안전하게 실행 하려면 메모리 사용률이 여유 공간을 확보하는 것이 중요합니다. 노드 의 사용 가능한 메모리가 부족하면 Linux 메모리 부족 킬러 에 취약해질 mongod
수 있습니다. 프로세스 를 종료합니다.
MongoDB 8.0 은(는) 모든 배포에 대해 업그레이드된 TCMalloc 을 자동으로 사용하여 시간 경과에 따른 평균 메모리 조각화 증가를 줄입니다. 이처럼 조각화가 낮으면 최대 로드 시 운영 안정성이 향상되고 결과적으로 메모리 사용률이 전반적으로 향상됩니다.
작업 거부 필터
의도하지 않은 리소스 집약적인 작업은 즉시 처리하다 하지 않으면 프로덕션에 문제를 일으킬 수 있습니다.
MongoDB 8.0 에서는 작업 거부 필터를 사용하여 이러한 작업의 영향 을 최소화할 수 있습니다. 작업 거부 필터를 사용하면 해당 쿼리 형태의 쿼리를 다시 활성화할 때까지 쿼리 실행 을 거부하도록 MongoDB 를 구성할 수 있습니다.
즉, 느린 쿼리 를 식별하면 애플리케이션 팀이 느린 쿼리의 영향 을 포함하기 위해 쿼리를 수정할 때까지 기다릴 필요가 없습니다. 대신 쿼리 프로파일러, 실시간 성능 패널 또는 쿼리 로그에서 성능이 저하된 쿼리 를 발견하면 해당 쿼리 형태 에 거부 필터하다 를 설정하다 수 있습니다. 그런 다음 MongoDB 는 들어오는 쿼리 형태 의 새 인스턴스가 실행되는 것을 방지합니다. 쿼리 를 수정한 후에는 쿼리 형태 를 다시 활성화할 수 있습니다.
다음을 수행하려는 경우 작업 거부 필터하다 를 사용해야 합니다.
수정이 진행되는 동안 느린 쿼리의 영향 을 빠르게 억제합니다.
과부하 시 덜 중요한 쿼리를 거부하여 더 중요한 워크로드의 우선 순위를 지정합니다.
클러스터가 최대 리소스 사용률에 근접한 경우 클러스터 에 복구 시간을 제공합니다.
Atlas UI 에서 느린 쿼리 식별 및 거부
Atlas UI 에서 작업 거부 필터하다 를 사용하려면 다음을 수행합니다.
AtlasGo Atlas 에서 프로젝트 의 Clusters 페이지로 고 (Go) 합니다.
아직 표시되지 않은 경우 탐색 표시줄의 Organizations 메뉴에서 원하는 프로젝트가 포함된 조직을 선택합니다.
아직 표시되지 않은 경우 탐색 표시줄의 Projects 메뉴에서 원하는 프로젝트를 선택합니다.
아직 표시되지 않은 경우 사이드바에서 Clusters를 클릭합니다.
Clusters(클러스터) 페이지가 표시됩니다.
현재 프로젝트 내에서 지정된 클러스터 에 대한 쿼리 프로파일러 로 고 (Go) 합니다.
프로젝트 패널에서 해당 인스턴스에 대해 View Monitoring을 클릭합니다.
Query Insights 탭을 클릭합니다.
Query Profiler 탭을 클릭합니다.
특정 쿼리 형태 의 작업을 거부합니다.
db.adminCommand()
함수에서 setQuerySettings
를 사용합니다.
거부 또는 시간 초과 후 쿼리 모니터링
Metrics(지표) 탭에서 나중에 쿼리가 어떻게 실행 되는지 모니터 할 수 있습니다.
읽기 작업에 대한 클러스터 수준 시간 초과
쿼리가 프로덕션 환경에 도달하기 전에 개발 프로세스 에서 쿼리의 효율성 을 신중하게 고려하는 것이 중요합니다. 예외는 항상 발생할 수 있지만 비효율적인 쿼리에 대해 사전에 완화하면 클러스터 성능 문제를 방지하는 데 도움이 될 수 있습니다.
MongoDB 8.0 을 사용하면 서버 측 defaultMaxTimeMS
가 클러스터 로 유입되는 인덱싱되지 않은 작업으로부터 쿼리를 보호할 수 있습니다. 작업이 이 제한 시간을 초과하면 MongoDB 는 쿼리가 너무 오래 실행 되어 리소스를 보유하는 것을 방지하기 위해 작업을 취소합니다. 이를 통해 다음을 수행할 수 있습니다.
타임아웃 설정 책임을 개별 애플리케이션 팀에서 데이터베이스 중심 팀으로 이전하세요.
쿼리 에 인덱스 가 누락된 경우 컬렉션 스캔 의 영향 을 최소화합니다.
프로덕션 환경에 도달하는 데 소요되는 비용이 많이 드는 작업에 대한 마지막 단계의 완화 조치를 취하세요.
분석 쿼리와 같이 다른 시간 제한이 필요한 쿼리가 있는 경우 maxTimeMS 메서드로 작업 수준 시간 제한을 설정하여 이를 재정의할 수 있습니다.
Atlas 관리 API 에서 읽기 작업에 대한 기본 시간 제한 설정
Atlas 관리 API 를 통해 defaultMaxTimeMS
매개 변수를 설정하다 하려면 1개의 클러스터에 대한 고급 구성 옵션 업데이트를 참조하세요.
Atlas UI 에서 읽기 작업에 대한 기본 시간 제한 설정하기
Atlas UI 에서 defaultMaxTimeMS
매개 변수를 설정하다 하려면 다음을 수행합니다.
구성 옵션으로 이동합니다.
기존 클러스터 가 있는 경우 클러스터 편집 페이지로 이동합니다.
새 클러스터 를 생성하는 경우 Select a version 드롭다운에서 MongoDB 8.0 을 선택합니다.
Additional Settings를 클릭합니다.
아래로 스크롤하여 More Configuration Options 을 클릭합니다.
종료된 작업의 동작을 보려면 거부 또는 시간 초과 후 쿼리 모니터링 을 참조하세요. 학습 내용은 defaultMaxTimeMS
및 읽기 작업에 대한 기본 시간 제한 설정을 참조하세요.
사용량이 많은 비샤드 컬렉션의 영향 격리
샤딩 을 사용하면 클러스터 를 수평으로 확장하다 할 수 있습니다. MongoDB 를 사용하면 일부 컬렉션을 샤드 하면서 동일한 클러스터 의 다른 컬렉션은 샤딩되지 않은 상태로 유지할 수 있습니다. 새 데이터베이스 를 생성하면 기본값 클러스터 에서 데이터 양이 가장 적은 샤드 가 해당 데이터베이스의 프라이머리 샤드 로 선택됩니다. 해당 데이터베이스 의 샤딩되지 않은 모든 컬렉션은 기본값 해당 프라이머리 샤드 에 있습니다. 이로 인해 워크로드가 증가함에 따라 프라이머리 샤드 에 대한 트래픽이 증가할 수 있으며, 특히 워크로드 워크로드 가 프라이머리 샤드 의 샤딩되지 않은 컬렉션에 집중되는 경우 더욱 그렇습니다.
이 워크로드 를 더 잘 분산하기 위해 MongoDB 8.0 에서는 moveCollection
명령을 사용하여 샤딩되지 않은 컬렉션 을 프라이머리 샤드 에서 다른 샤드로 이동할 수 있습니다. 이를 통해 예상 리소스 사용량이 적은 샤드에 활성이고 사용량이 많은 컬렉션을 배치할 수 있습니다. 이를 통해 다음을 수행할 수 있습니다.
더 크고 복잡한 워크로드에서 성능을 최적화합니다.
리소스 활용도를 높일 수 있습니다.
샤드 전체에 날짜를 더 균등하게 배포합니다.
다음과 같은 상황에서는 컬렉션 을 격리하는 것이 좋습니다.
처리량이 많은 여러 개의 비샤드형 컬렉션으로 인해 프라이머리 샤드 에 상당한 워크로드 가 발생하는 경우.
샤딩되지 않은 컬렉션 이 다른 컬렉션의 병목 현상이 될 수 있는 향후 성장을 경험할 수 있을 것으로 예상합니다.
클러스터당 하나의 컬렉션 배포서버 설계를 실행 우선 순위 또는 워크로드를 기준으로 해당 고객을 격리하려고 합니다.
샤드에는 샤드되지 않은 컬렉션의 수로 인해 비례하는 양 이상의 데이터가 있습니다.
mongosh
를 사용하여 샤딩되지 않은 컬렉션 을 이동하는 방법을 학습 보려면 컬렉션 이동을 참조하세요 .
애플리케이션 및 클라이언트 사이드 권장사항
MongoDB deployment 및 드라이버 라이브러리의 기능을 구성하여 네트워크 장애 및 페일오버 이벤트를 견딜 수 있는 회복 탄력성 있는 애플리케이션을 만들 수 있습니다. MongoDB Atlas의 상시 기능을 최대한 활용하는 애플리케이션 코드를 작성하려면 다음 작업을 수행해야 합니다.
애플리케이션 에 적합한
majority
쓰기 고려 (write concern) 와 읽기 고려 (read concern) 를 사용하세요.애플리케이션 의 오류를 처리합니다 .
최신 드라이버 설치
MongoDB 드라이버 에서 해당 언어 에 맞는 최신 드라이버를 설치합니다. 드라이버는 애플리케이션 에서 데이터베이스 로 쿼리를 연결하고 릴레이합니다. 최신 드라이버를 사용하면 최신 MongoDB 기능을 사용할 수 있습니다.
그런 다음 애플리케이션에서 종속성을 가져옵니다.
Maven을 사용하는 경우 pom.xml
종속성 목록에 다음을 추가합니다.
<dependencies> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-sync</artifactId> <version>4.0.1</version> </dependency> </dependencies>
Gradle을 사용하는 경우, build.gradle
종속성 목록에 다음을 추가합니다:
dependencies { compile 'org.mongodb:mongodb-driver-sync:4.0.1' }
// Latest 'mongodb' version installed with npm const MongoClient = require('mongodb').MongoClient;
# Install the latest 'pymongo' version with pip and # import MongoClient from the package to establish a connection. from pymongo import MongoClient
연결 문자열
참고
Atlas 는 사전 구성된 연결 string 을 제공합니다. 사전 구성된 string 을 복사하는 단계는 Atlas에서 제공하는 연결 문자열을 참조하세요.
cluster의 모든 노드를 지정하는 연결 을 string Atlas 사용하여 애플리케이션을 데이터베이스에 연결합니다. 클러스터가 복제본 세트 투표 를 수행하고 새 프라이머리가 선택되면 클러스터의 모든 노드를 지정하는 연결 string 이 애플리케이션 로직 없이 새 프라이머리를 검색합니다.
둘 중 하나를 사용하여 클러스터의 모든 노드를 지정할 수 있습니다.
표준 연결 문자열 형식 또는
DNS 시드 목록 연결 형식 (Atlas에서 권장).
연결 string 은 옵션, 특히 retryWrites 및 writeConcern을 지정할 수도 있습니다.
Atlas는 비공개 엔드포인트 서비스의 로드 밸런서를 사용하여 샤딩된 클러스터에 대해 최적화된 SRV 연결 문자열을 생성할 수 있습니다. 최적화된 연결 문자열을 사용하는 경우 Atlas는 애플리케이션과 샤딩된 클러스터 간의 mongos
당 연결 수를 제한합니다. mongos
당 제한된 연결은 연결 수가 급증하는 동안 성능을 향상시킵니다.
참고
Atlas는 Google Cloud 또는 Azure에서 실행되는 클러스터에 대해 최적화된 연결 문자열을 지원하지 않습니다.
비공개 엔드포인트 샤딩된 클러스터의 최적화된 연결 문자열에 대해 자세히 알아보려면 비공개 엔드포인트 샤딩된 클러스터를 위한 연결 성능 향상을 참고하세요.
Atlas에서 제공하는 연결 문자열
Atlas 클러스터 인터페이스에서 연결 문자열을 복사하는 경우, 연결 문자열은 클러스터에 대해 미리 구성되어 있고, DNS 시드 목록 형식을 사용하며, 회복 탄력성을 위해 권장되는 retryWrites
및 w
(쓰기 고려) 옵션이 포함되어 있습니다.
Atlas에서 연결 문자열 URI를 복사합니다.
AtlasGo Atlas 에서 프로젝트 의 Clusters 페이지로 고 (Go) 합니다.
아직 표시되지 않은 경우 탐색 표시줄의 Organizations 메뉴에서 원하는 프로젝트가 포함된 조직을 선택합니다.
아직 표시되지 않은 경우 탐색 표시줄의 Projects 메뉴에서 원하는 프로젝트를 선택합니다.
아직 표시되지 않은 경우 사이드바에서 Clusters를 클릭합니다.
Clusters(클러스터) 페이지가 표시됩니다.
연결 string URI를 복사합니다.
연결 문자열 또는 전체 드라이버 예시를 애플리케이션 코드에 복사합니다. 데이터베이스 사용자 자격 증명을 제공해야 합니다.
참고
이 가이드 에서는 연결 을 통한 SCRAM 인증 string 을 사용합니다. X.509 인증서를 사용하여 인증하는 방법을 학습 보려면 X.509 를 참조하세요.
연결 문자열을 사용하여 애플리케이션에서 MongoDB 클라이언트를 인스턴스화합니다.
// Copy the connection string provided by Atlas String uri = <your Atlas connection string>; // Instantiate the MongoDB client with the URI MongoClient client = MongoClients.create(uri);
// Copy the connection string provided by Atlas const uri = <your Atlas connection string>; // Instantiate the MongoDB client with the URI const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
# Copy the connection string provided by Atlas uri = <your Atlas connection string> # Pass your connection string URI to the MongoClient constructor client = MongoClient(uri)
재시도 가능 쓰기 및 읽기
참고
MongoDB 버전 4.0 부터 4.2호환 드라이버 를 사용하는 경우, MongoDB는 기본적으로 쓰기와 읽기를 모두 한 번 재시도합니다.
재시도 가능한 쓰기
재시도 가능 쓰기 를 사용하면 특정 쓰기 작업이 실패할 경우 한 번만 다시 시도할 수 있습니다. 에서 연결 을 string 복사한 Atlas 경우에는 가 포함됩니다."retryWrites=true"
자체 연결 string 을 제공하는 경우 "retryWrites=true"
를 쿼리 매개변수로 포함합니다.
애플리케이션이 일시적으로 정상적인 기본 노드를 찾을 수 없는 일시적인 네트워크 오류와 복제본 세트 선택을 처리하기 위해서는 쓰기를 정확히 한 번만 재시도하는 것이 가장 좋습니다. 재시도가 성공하면 작업 전체가 성공하고 오류가 반환되지 않습니다. 작업이 실패하는 경우 다음과 같은 이유 때문일 수 있습니다.
지속적인 네트워크 오류
잘못된 명령
작업이 실패하면 애플리케이션에서 오류 자체를 처리해야 합니다.
재시도 가능한 읽기
읽기 작업은 MongoDB 버전 4.0 및 4.2호환 드라이버 에서 시작하여 실패할 경우 자동으로 한 번만 재시도됩니다. 읽기 재시도를 위해 추가 구성이 필요하지 않습니다.
쓰기 및 읽기 고려
쓰기 고려와 읽기 고려를 사용하여 애플리케이션의 일관성과 가용성을 조정할 수 있습니다. 고려가 엄격할 수록 데이터베이스 작업이 더 강력한 데이터 일관성 보장을 기다리며, 일관성 요구 사항을 완화하면 더 높은 가용성을 제공합니다.
예시
애플리케이션에서 금전적 잔액을 처리하는 경우 일관성이 매우 중요합니다. 오래된 데이터나 롤백될 수 있는 데이터를 읽지 않도록 하기 위해 majority
쓰기 및 읽기 고려를 사용할 수 있습니다.
또는 애플리케이션이 수백 개의 센서에서 초당 온도 데이터를 기록하는 경우, 가장 최근의 판독값이 포함되지 않은 데이터를 읽더라도 걱정하지 않아도 됩니다. 일관성 요구 사항을 완화하고 해당 데이터에 더 빠르게 액세스할 수 있습니다.
쓰기 고려
연결 URI를 통해 복제본 세트의 쓰기 고려 수준 을 설정할 수 있습니다.Atlas string majority
쓰기 고려를 사용하여 데이터가 데이터베이스에 성공적으로 기록되고 지속되는지 확인합니다. 이는 권장되는 기본값이며 대부분의 사용 사례에 충분합니다. 에서 연결 을 string 복사한 Atlas 경우에는 가 포함됩니다."w=majority"
majority
와 같이 승인이 필요한 쓰기 고려를 사용하는 경우, 해당 승인 수준에 도달하기 위한 최대 쓰기 시간 제한을 지정할 수도 있습니다.
모든 쓰기에 대한 wtimeoutMS 연결 문자열 매개 변수 또는
단일 쓰기 작업을 위한 wtimeout 옵션입니다.
시간 제한의 사용 여부와 사용하는 값은 애플리케이션 컨텍스트에 따라 다릅니다.
중요
쓰기에 대한 시간 제한을 지정하지 않고 쓰기 고려 수준을 달성할 수 없는 경우 쓰기 작업이 무기한 중단됩니다.
readConcern
연결 URI를 통해 복제본 세트의 읽기 고려 수준 을 설정할 수 있습니다.Atlas string 이상적인 읽기 고려 는 애플리케이션 요구 사항에 따라 다르지만 대부분의 사용 사례에는 기본값으로 충분합니다. 기본 읽기 고려를 사용하는 데 연결 string 매개변수는 필요하지 않습니다.
읽기 고려를 지정하면 애플리케이션이 Atlas로부터 수신하는 데이터에 대한 보장을 개선할 수 있습니다.
참고
애플리케이션에서 사용하는 쓰기 및 읽기 고려의 특정 조합은 작업 순서 보장에 영향을 미칩니다. 이를 인과적 일관성이라고 합니다. 인과적 일관성 보장에 대한 자세한 내용은 인과 적 일관성 및 읽기 및 쓰기 고려를 참조하세요.
Error Handling
재시도 가능 쓰기 로 처리되지 않는 잘못된 명령, 네트워크 중단 및 네트워크 오류는 오류를 반환합니다. 오류에 대한 자세한 내용은 드라이버의 API 설명서를 참조하세요.
예를 들어 애플리케이션이 데이터베이스 컬렉션에 이미 사용된 _id
값이 포함된 문서를 삽입하려고 하면 드라이버는 다음을 포함하는 오류를 반환합니다.
Unable to insert due to an error: com.mongodb.MongoWriteException: E11000 duplicate key error collection: <db>.<collection> ...
{ "name": : "MongoError", "message": "E11000 duplicate key error collection on: <db>.<collection> ... ", ... }
pymongo.errors.DuplicateKeyError: E11000 duplicate key error collection: <db>.<collection> ...
적절한 오류 처리가 없으면 오류로 인해 애플리케이션이 다시 시작될 때까지 요청 처리가 차단될 수 있습니다.
애플리케이션은 충돌이나 부작용 없이 오류를 처리해야 합니다. 컬렉션에 중복된 _id
를 삽입하는 애플리케이션의 이전 예에서, 해당 애플리케이션은 다음과 같이 오류를 처리할 수 있습니다.
// Declare a logger instance from java.util.logging.Logger private static final Logger LOGGER = ... ... try { InsertOneResult result = collection.insertOne(new Document() .append("_id", 1) .append("body", "I'm a goofball trying to insert a duplicate _id")); // Everything is OK LOGGER.info("Inserted document id: " + result.getInsertedId()); // Refer to the API documentation for specific exceptions to catch } catch (MongoException me) { // Report the error LOGGER.severe("Failed due to an error: " + me); }
... collection.insertOne({ _id: 1, body: "I'm a goofball trying to insert a duplicate _id" }) .then(result => { response.sendStatus(200) // send "OK" message to the client }, err => { response.sendStatus(400); // send "Bad Request" message to the client });
... try: collection.insert_one({ "_id": 1, "body": "I'm a goofball trying to insert a duplicate _id" }) return {"message": "User successfully added!"} except pymongo.errors.DuplicateKeyError as e: print ("The insert operation failed:", e)
이 예시의 삽입 작업은 _id
필드가 고유해야 하기 때문에 두 번째로 호출할 때 "중복 키" 오류가 발생합니다. 오류가 감지되면 클라이언트에게 알림이 전송되고 앱은 계속 실행됩니다. 그러나 삽입 작업은 실패하므로 사용자에게 메시지를 표시할지, 작업을 다시 시도할지 또는 다른 작업을 수행할지를 결정해야 합니다.
항상 오류를 기록해야 합니다. 추가 처리 오류에 대한 일반적인 전략은 다음과 같습니다.
오류 메시지와 함께 오류를 클라이언트에 반환. 이는 오류를 해결할 수 없어 사용자에게 작업을 완료할 수 없음을 알려야 할 때 좋은 전략입니다.
백업 데이터베이스에 쓰기. 이는 오류를 해결할 수 없지만 요청 데이터가 손실되는 위험을 감수하고 싶지 않을 때 좋은 전략입니다.
1회 기본 재시 도 이후에 작업을 다시 시도합니다. 이는 오류의 원인을 프로그래밍 방식으로 해결한 다음 다시 시도할 수 있는 경우에 좋은 전략입니다.
애플리케이션 컨텍스트에서 가장 적합한 전략을 선택해야 합니다.
예시
중복 키 오류의 경우, 오류를 기록해야 하지만 작업이 실패할 수 있으므로 작업을 다시 시도해서는 안 됩니다. 대신 대체 데이터베이스에 쓰고 나중에 해당 데이터베이스의 내용을 검토하여 정보가 손실되지 않도록 할 수 있습니다. 사용자는 다른 작업을 수행할 필요가 없으며 데이터가 기록되므로 클라이언트에 오류 메시지를 전송하지 않도록 선택할 수 있습니다.
네트워크 오류에 대한 계획
오류를 반환하는 것은 작업이 무기한 중단되어 애플리케이션이 새 작업을 실행하지 못하도록 차단할 때 바람직한 동작일 수 있습니다. maxTimeMS 메서드를 사용하여 개별 작업에 시간 제한을 설정하고, 해당 시간 제한을 초과할 경우 애플리케이션에서 처리할 오류를 반환할 수 있습니다.
각 작업에 설정하는 시간 제한은 해당 작업의 컨텍스트에 따라 다릅니다.
예시
애플리케이션에서 inventory
컬렉션의 간단한 제품 정보를 읽고 표시하는 경우, 이러한 읽기 작업은 오래 걸리지 않는다고 가정할 수 있습니다. 비정상적으로 오래 실행되는 쿼리는 지속적인 네트워크 문제가 있음을 나타내는 지표입니다. 이 작업에서 maxTimeMS
를 5000, 즉 5초로 설정하면 네트워크 문제가 있다고 확신하는 즉시 애플리케이션이 피드백을 받습니다.
페일오버 테스트
카오스 테스트의 정신으로 Atlas는 주기적인 유지 관리 및 특정 구성 변경을 위해 복제본 세트 선택을 자동으로 수행합니다.
애플리케이션이 복제본 세트 투표에 대해 회복 탄력성이 있는지 확인하려면 페일오버이벤트를 시뮬레이션하여 페일오버 프로세스를 테스트하세요.
회복 탄력성 애플리케이션 예시
예시 애플리케이션은 네트워크 장애 및 페일오버 이벤트에 대한 회복 탄력성을 보장하기 위해 다음 사항을 권장합니다.
재시도 가능한 쓰기, 대다수 쓰기 고려 및 기본 읽기 고려와 함께 Atlas에서 제공하는 연결 문자열을 사용합니다.
maxTimeMS 메서드를 사용하여 optime 제한을 지정합니다.
maxTimeMS
설정 방법에 대한 지침은 해당 드라이버 설명서를 참조하세요.키 중복 및 시간 초과에 대한 오류를 처리합니다.
이 애플리케이션은 클라이언트가 사용자 레코드를 생성하거나 나열할 수 있는 HTTP API 입니다. GET 및 POST 요청을 수락하는 엔드포인트 http://localhost:3000 를 노출합니다.
메서드 | 엔드포인트 | 설명 |
---|---|---|
|
|
|
|
| 요청 본문에 |
참고
다음 서버 애플리케이션 은 NanoHTTPD 를 사용합니다. 및 실행 하기 전에 프로젝트 JSON 에 종속성으로 추가해야 합니다.
1 // File: App.java 2 3 import java.util.Map; 4 import java.util.logging.Logger; 5 6 import org.bson.Document; 7 import org.json.JSONArray; 8 9 import com.mongodb.MongoException; 10 import com.mongodb.client.MongoClient; 11 import com.mongodb.client.MongoClients; 12 import com.mongodb.client.MongoCollection; 13 import com.mongodb.client.MongoDatabase; 14 15 import fi.iki.elonen.NanoHTTPD; 16 17 public class App extends NanoHTTPD { 18 private static final Logger LOGGER = Logger.getLogger(App.class.getName()); 19 20 static int port = 3000; 21 static MongoClient client = null; 22 23 public App() throws Exception { 24 super(port); 25 26 // Replace the uri string with your MongoDB deployment's connection string 27 String uri = "<atlas-connection-string>"; 28 client = MongoClients.create(uri); 29 30 start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); 31 LOGGER.info("\nStarted the server: http://localhost:" + port + "/ \n"); 32 } 33 34 public static void main(String[] args) { 35 try { 36 new App(); 37 } catch (Exception e) { 38 LOGGER.severe("Couldn't start server:\n" + e); 39 } 40 } 41 42 43 public Response serve(IHTTPSession session) { 44 StringBuilder msg = new StringBuilder(); 45 Map<String, String> params = session.getParms(); 46 47 Method reqMethod = session.getMethod(); 48 String uri = session.getUri(); 49 50 if (Method.GET == reqMethod) { 51 if (uri.equals("/")) { 52 msg.append("Welcome to my API!"); 53 } else if (uri.equals("/users")) { 54 msg.append(listUsers(client)); 55 } else { 56 msg.append("Unrecognized URI: ").append(uri); 57 } 58 } else if (Method.POST == reqMethod) { 59 try { 60 String name = params.get("name"); 61 if (name == null) { 62 throw new Exception("Unable to process POST request: 'name' parameter required"); 63 } else { 64 insertUser(client, name); 65 msg.append("User successfully added!"); 66 } 67 } catch (Exception e) { 68 msg.append(e); 69 } 70 } 71 72 return newFixedLengthResponse(msg.toString()); 73 } 74 75 static String listUsers(MongoClient client) { 76 MongoDatabase database = client.getDatabase("test"); 77 MongoCollection<Document> collection = database.getCollection("users"); 78 79 final JSONArray jsonResults = new JSONArray(); 80 collection.find().forEach((result) -> jsonResults.put(result.toJson())); 81 82 return jsonResults.toString(); 83 } 84 85 static String insertUser(MongoClient client, String name) throws MongoException { 86 MongoDatabase database = client.getDatabase("test"); 87 MongoCollection<Document> collection = database.getCollection("users"); 88 89 collection.insertOne(new Document().append("name", name)); 90 return "Successfully inserted user: " + name; 91 } 92 }
참고
다음 서버 애플리케이션은 Express를 사용하며, 이를 실행하려면 프로젝트에 종속성으로 추가해야 합니다.
1 const express = require('express'); 2 const bodyParser = require('body-parser'); 3 4 // Use the latest drivers by installing & importing them 5 const MongoClient = require('mongodb').MongoClient; 6 7 const app = express(); 8 app.use(bodyParser.json()); 9 app.use(bodyParser.urlencoded({ extended: true })); 10 11 const uri = "mongodb+srv://<db_username>:<db_password>@cluster0-111xx.mongodb.net/test?retryWrites=true&w=majority"; 12 13 const client = new MongoClient(uri, { 14 useNewUrlParser: true, 15 useUnifiedTopology: true 16 }); 17 18 // ----- API routes ----- // 19 app.get('/', (req, res) => res.send('Welcome to my API!')); 20 21 app.get('/users', (req, res) => { 22 const collection = client.db("test").collection("users"); 23 24 collection 25 .find({}) 26 .maxTimeMS(5000) 27 .toArray((err, data) => { 28 if (err) { 29 res.send("The request has timed out. Please check your connection and try again."); 30 } 31 return res.json(data); 32 }); 33 }); 34 35 app.post('/users', (req, res) => { 36 const collection = client.db("test").collection("users"); 37 collection.insertOne({ name: req.body.name }) 38 .then(result => { 39 res.send("User successfully added!"); 40 }, err => { 41 res.send("An application error has occurred. Please try again."); 42 }) 43 }); 44 // ----- End of API routes ----- // 45 46 app.listen(3000, () => { 47 console.log(`Listening on port 3000.`); 48 client.connect(err => { 49 if (err) { 50 console.log("Not connected: ", err); 51 process.exit(0); 52 } 53 console.log('Connected.'); 54 }); 55 });
참고
다음 웹 애플리케이션 은 FastAPI 를 사용합니다. . 새 애플리케이션 을 만들려면 FastAPI 샘플 파일 을 사용합니다. 구조입니다.
1 # File: main.py 2 3 from fastapi import FastAPI, Body, Request, Response, HTTPException, status 4 from fastapi.encoders import jsonable_encoder 5 6 from typing import List 7 from models import User 8 9 import pymongo 10 from pymongo import MongoClient 11 from pymongo import errors 12 13 # Replace the uri string with your |service| connection string 14 uri = "<atlas-connection-string>" 15 db = "test" 16 17 app = FastAPI() 18 19 20 def startup_db_client(): 21 app.mongodb_client = MongoClient(uri) 22 app.database = app.mongodb_client[db] 23 24 25 def shutdown_db_client(): 26 app.mongodb_client.close() 27 28 ##### API ROUTES ##### 29 30 def list_users(request: Request): 31 try: 32 users = list(request.app.database["users"].find().max_time_ms(5000)) 33 return users 34 except pymongo.errors.ExecutionTimeout: 35 raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="The request has timed out. Please check your connection and try again.") 36 37 38 def new_user(request: Request, user: User = Body(...)): 39 user = jsonable_encoder(user) 40 try: 41 new_user = request.app.database["users"].insert_one(user) 42 return {"message":"User successfully added!"} 43 except pymongo.errors.DuplicateKeyError: 44 raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Could not create user due to existing '_id' value in the collection. Try again with a different '_id' value.")