다음 섹션에는 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.")