다음 섹션에는 Atlas 배포서버 에서 지연 시간 줄이기 위해 선택할 수 있는 구성 옵션이 나열되어 있습니다.
물리적 거리
물리적 거리는 지연 시간의 주요 원인입니다. 사용자와 애플리케이션 간 거리, 애플리케이션과 데이터 간 거리, 클러스터 노드 간 거리는 모두 시스템 지연 시간과 애플리케이션 성능에 영향을 미칩니다.
읽기 및 쓰기 (write) 작업의 지연 시간 줄이려면 애플리케이션 과 데이터를 지리적으로 사용자에게 더 가깝게 배치하는 것이 중요합니다. 데이터 보유 Atlas 노드는 데이터베이스의 데이터를 저장 하고 읽기 및 쓰기 (write) 작업을 처리하다 Atlas cluster 내의 서버 노드입니다. 애플리케이션 사용자의 더 빠른 데이터 액세스 지원 하려면 데이터를 포함하는 Atlas 노드를 대다수의 애플리케이션 사용자와 지리적으로 가까운 cloud 제공자 리전에 배포 .
애플리케이션 사용자가 여러 지역(예: 미국과 유럽)에 분산된 있는 경우, 각 지역에서 하나 이상의 리전에 배포 각 위치 의 사용자 지연 시간 줄이는 것이 좋습니다. 멀티 리전 배포에 대해 자세히 학습 멀티 리전 배포 패러다임을 참조하세요.
데이터가 지역별로 나누어져 각 지역의 사용자가 서로 다른 데이터 세트에 액세스 경우 각 지역의 사용자의 읽기 및 쓰기 (write) 성능을 최적화하기 위해 리전 또는 지역별로 데이터를샤드 할 수도 있습니다. 이 접근 방식을 사용하면 데이터 지역성을 보장하면서 대규모 데이터 세트와 높은 처리량 처리하다 할 수 있습니다.
복제 구성
복제는 프라이머리 노드 에서 세컨더리 노드로 데이터를 복사하는 것입니다. 다음 복제 구성 옵션을 조정하여 복제본 세트 에서 읽기 및 쓰기 (write) 작업의 지연 시간 최소화할 수 있습니다.
쓰기 고려 수준: 쓰기 쓰기 고려 (write concern) 구성할 때 쓰기 (write) 지연 시간 과 쓰기 (write) 내구성 간에는 장단점이 있습니다. MongoDB의 기본값 전역 쓰기 고려 (write concern) 로 설정하다
majority있으며, 각 쓰기 (write) 작업은 Atlas 작업이 완료되고 성공적인 클라이언트 확인하기 전에 복제본 세트 의 데이터 보유 투표 노드 과반수에 복제되어야 합니다. 쓰기 고려 (write concern) 높게 설정하면 쓰기 (write) 지연 시간 늘어나지만 쓰기 (write) 내구성이 향상되고 복제본 세트 페일오버 중 롤백이 방지됩니다.읽기 고려 및 읽기 설정: 읽기 고려 (read concern) 및 읽기 설정 (read preference) 구성할 때 쿼리 지연 시간 , 데이터 가용성, 쿼리 응답의 일관성 간에는 장단점이 있습니다. MongoDB의 기본값 글로벌 읽기 고려 (read concern) 이며, 읽기 작업은
local데이터가 다른 노드 간에 복제되는지 확인하기 위해 기다리지 않고 로컬 복제본 세트 의 하나의 노드 에서만 읽습니다. 이 노드 프라이머리 노드인지 세컨더리 노드 인지는 Atlas 기본값 으로(으)로 설정하는 읽기 설정 (read preference)primary에 따라 결정됩니다. 이 기본값 읽기 고려 (read concern) 와 기본 설정 조합은 복제본 세트 의 최신 노드 에서 지연 지연 시간 이 가장 짧은 읽기에 최적화되지만, 프라이머리 노드의 데이터가 지속형 없고 작업이 진행되는 동안 잠재적으로 롤백될 수 있는 위험도 있습니다. 사용 가능한 프라이머리 노드 없는 경우 사용자는 페일오버 를 쿼리 할 수 없습니다.사용 가능한
primaryPreferred프라이머리 노드 없거나 지리적으로 더 가까운 세컨더리 노드 가 있는 경우 읽기 작업이 세컨더리 노드 에서 읽을 수 있도록 읽기 읽기 설정 (read preference)(으)로 변경하면 세컨더리 노드가 다음과 같은 경우 오래된 데이터를 반환할 위험이 있습니다. 노드 최신 상태가 아닙니다. 쓰기 고려 (write concern) 늘려 더 많은 세컨더리 노드를 최신 상태로 유지하면 이러한 위험을 완화할 수 있지만, 이렇게 하면 쓰기 (write) 지연 시간 늘어나는 단점이 있습니다.중요
복제 지연 으로 인해 세컨더리 노드 오래된 데이터를 반환할 가능성이 있다는 점에 유의하세요.
쿼리 시간 제한: 배포서버 에 글로벌 및 작업 수준 쿼리 시간 제한을 설정하다 애플리케이션 이 시간이 초과되기 전에 응답을 기다리는 시간을 줄일 수 있습니다. 이렇게 하면 진행 중인 쿼리가 장기간 배포서버 성능에 부정적인 영향을 미치는 것을 방지할 수 있습니다.
노드 투표 우선 순위: 복제본 세트 투표 중에 기본
members[n].priority데이터 센터 의 노드가 대체 데이터 센터 의 노드보다 먼저 프라이머리 선출될 가능성을 높이려면 대체 데이터 센터 의 노드us-east-1중 를 다음과 같이 설정하다 수 있습니다. 프라이머리 데이터 센터 의us-west-1노드보다 낮습니다. 예시 를 들어 AWS 리전(버지니아 북부) 및(캘리포니아us-west-1북부)에 클러스터 배포 사용자의 대부분이 캘리포니아에 있는 경우, AWS 리전에서 노드의 우선 순위를 지정할 수 있습니다. } (캘리포니아 북부) 리전 사용하여 프라이머리 노드 가 지리적으로 항상 대다수의 사용자와 가깝고 최소한 지연 시간 으로 읽기 및 쓰기 (write) 작업에 응답할 수 있도록 보장합니다.미러링된 읽기: 미러링된 읽기는 장애 후 프라이머리 투표의 영향을 줄이기 위해 세컨더리 노드의 캐시를 사전 예열합니다. 자세한 내용은 미러링된 읽기를 참조하세요.
요구 사항에 가장 적합한 복제 구성을 구현하는 방법에 대한 자세한 지침 MongoDB의 전문 서비스 문의 .
네트워크 구성
다음 네트워크 연결 옵션을 사용하여 보안을 강화하고 지연 시간 더욱 줄일 수 있습니다.
비공개 엔드포인트: 비공개 엔드포인트는 애플리케이션의 가상 네트워크와 Atlas cluster 간에 직접적이고 안전한 연결을 설정하여 잠재적으로 네트워크 홉을 줄이고 지연 시간 개선합니다.
VPC 피어링 : 애플리케이션이 피어링된 리전에 연결할 수 있도록 복제본 세트에서 VPC 피어링을 구성합니다. 페일오버 발생하는 이벤트 , VPC 피어링은 애플리케이션 서버 새로운 프라이머리 노드 감지하고 그에 따라 트래픽을 라우팅할 수 있는 방법을 제공합니다.
데이터 모델링 및 쿼리 최적화
애플리케이션 이 데이터에 액세스하는 속도가 지연 시간 에 영향을 미칩니다. 우수한 데이터 모델링 및 쿼리 최적화는 데이터 액세스 속도를 향상시킬 수 있습니다. 예시 를 들어 다음을 수행할 수 있습니다.
문서 크기 줄이기: 네트워크를 통해 전송되는 데이터의 양을 줄이기 위해 필드 이름과 값 길이를 줄이는 것이 좋습니다.
쿼리 패턴 최적화: 인덱스를 효과적으로 사용하여 여러 리전에서 읽어야 하는 데이터의 양을 최소화합니다.
지연 시간 모니터링 및 테스트
Atlas 다양한 리전의 지연 시간 지표 관찰할 수 있는 실시간 성능 패널 (실시간 성능 패널) 을 제공합니다. 애플리케이션 수준 모니터링 구현 애플리케이션 과 주고받는 엔드 투 엔드 지연 시간 추적 수도 있습니다. 최종 프로덕션 배포서버 전에 지연 시간 병목 현상을 식별하고 주소 위해 다양한 멀티 리전 시나리오 에서 성능 테스트를 수행하는 것이 좋습니다.
배포서버 모니터링 에대해 자세히 학습 Atlas 모니터링 및 경고에 대한 지침을 참조하세요.
연결 구성
가능하면 애플리케이션의 프로그래밍 언어 에 맞는 최신 운전자 버전을 기반으로 구축된 연결 방법을 사용하는 것이 좋습니다. Atlas 애플리케이션 제공하는 기본값 연결 문자열 연결 문자열 연결 문자열 것이 배포서버 .
엔터프라이즈 수준 애플리케이션 배포의 경우 운영 지연 시간 최소화하면서 사용자 수요를 충족하도록 연결 풀 설정을 조정하는 것이 특히 중요합니다. 예시 들어 및 옵션을 사용하여 대부분의 minPoolSize maxPoolSize 데이터베이스 클라이언트 연결이 열리는 방법과 시기를 조정하여 관련 네트워크 오버헤드 와 함께 발생하는 지연 시간 급증을 방지하거나 계획할 수 있습니다.
이러한 설정을 구성할 수 있는 범위는 배포서버 아키텍처에 따라 다릅니다. 예시 들어, 애플리케이션 배포서버 AWS Lambda 와 같은 단일 스레드 리소스를 활용하는 경우, 애플리케이션 하나의 클라이언트 연결만 열고 사용할 수 있습니다. 연결 풀 만들고 사용하는 방법과 위치, 연결 풀 설정을 지정하는 위치에 대한 자세한 학습 은 연결 풀 개요를 참조하세요.
지연 시간이 짧은 애플리케이션 예시
다음 샘플 애플리케이션 데이터 작업 지연 시간 줄이기 위해 이 페이지에 주요 권장 사항을 제공합니다.
재시도 가능한 쓰기, 대다수 쓰기 고려 및 기본 읽기 고려와 함께 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.")