다음 섹션에서는 Atlas 배포에서 지연 시간을 단축하기 위해 선택할 수 있는 구성 옵션을 설명합니다.
물리적 거리
물리적 거리는 지연 시간의 주요 원인입니다. 사용자와 애플리케이션 간 거리, 애플리케이션과 데이터 간 거리, 클러스터 노드 간 거리는 모두 시스템 지연 시간과 애플리케이션 성능에 영향을 미칩니다.
읽기 및 쓰기 (write) 작업의 지연 시간 줄이려면 애플리케이션 과 데이터를 지리적으로 사용자에게 더 가깝게 배치하는 것이 중요합니다. 데이터 보유 Atlas 노드는 데이터베이스의 데이터를 저장하고 읽기 및 쓰기 (write) 작업을 처리하는 Atlas 클러스터 내의 서버 노드입니다. 애플리케이션 사용자의 더 빠른 데이터 액세스 지원 하려면 데이터를 포함하는 Atlas 노드를 대다수의 애플리케이션 사용자와 지리적으로 가까운 cloud 제공자 리전에 배포 .
애플리케이션 사용자가 미국과 유럽 등 여러 지역에 분산되어 있는 경우, 각 지역마다 하나 이상의 리전에 배포해 각 위치에서 사용자의 지연 시간을 줄이는 것이 좋습니다. 멀티 리전 배포서버에 대해 자세히 알아보려면 멀티 리전 배포서버 패러다임을 참조하세요.
데이터가 지역별로 나누어져 각 지역의 사용자가 서로 다른 데이터 세트에 액세스 경우, 각 지역의 사용자의 읽기 및 쓰기 (write) 성능을 최적화하기 위해 리전 또는 지역별로 데이터를 샤드 할 수도 있습니다. 이 접근 방식을 사용하면 데이터 지역성을 보장하면서 대규모 데이터 세트와 높은 처리량 처리하다 할 수 있습니다.
복제 구성
복제란 프라이머리 노드에서 세컨더리 노드로 데이터를 복사하는 것입니다. 다음 복제 구성 옵션을 조정하여 복제본 세트에서 읽기 및 쓰기 작업의 지연 시간을 최소화할 수 있습니다.
Write Concern Levels: There is a trade-off between write latency and write durability when you configure write concern. MongoDB's default global write concern is set to
majority, which requires each write operation to be replicated across the majority of voting, data-bearing nodes in your replica set before Atlas acknowledges the operation as complete and successful to the client. Setting a higher write concern increases write latency, but also improves write durability and prevents rollbacks during a replica set failover.Read Concern and Read Preference: There is a trade-off between query latency, data availability, and the consistency of your query responses when you configure read concern and read preference. MongoDB's default global read concern is
local, which requires read operations to read from only one node in the local replica set without waiting to confirm that data is replicated across other nodes. Whether this node is the primary or a secondary node is determined by your read preference, which Atlas sets toprimaryby default. This default read concern and preference combination optimizes for the lowest latency reads from the most up-to-date node in the replica set, but it also runs the risk that the primary node's data may not be durable and can potentially be rolled back during a failover, and that users will not be able to query data if there is no available primary node.읽기 설정을
primaryPreferred로 변경하면 사용 가능한 프라이머리 노드가 없거나 지리적으로 더 가까운 세컨더리 노드가 있을 때 읽기 작업이 세컨더리 노드에서 수행될 수 있습니다. 그러나 세컨더리 노드가 최신 상태가 아닐 경우 오래된 데이터를 반환할 위험이 있습니다. 쓰기 고려를 증가시켜 더 많은 세컨더리 노드를 최신 상태로 유지함으로써 이러한 위험을 완화할 수 있지만, 이 경우 쓰기 지연 시간이 증가하는 단점이 있습니다.중요
복제 지연으로 인해 세컨더리 노드가 오래된 데이터를 반환할 가능성이 있다는 점을 염두에 두시기 바랍니다.
쿼리 시간 제한: 배포서버에 글로벌 및 작업 수준 쿼리 시간 제한 을 설정하다 애플리케이션 시간이 초과되기 전에 응답을 기다리는 시간을 줄일 수 있습니다. 이렇게 하면 진행 중인 쿼리가 장기간 배포서버 성능에 부정적인 영향이 미치는 것을 방지할 수 있습니다.
Node Election Priority: To increase the likelihood that the members in your main data center be elected primary before the members in an alternate data center during a replica set election, you can set the
members[n].priorityof the members in the alternate data center to be lower than that of the members in the primary data center. For example, if you deploy your cluster across the AWS regionsus-east-1(Northern Virginia) andus-west-1(Northern California), and the majority of your users are in California, you can prioritize nodes in the AWSus-west-1(Northern California) region to ensure that the primary node is always geographically close to the majority of your users and can respond to read and write operations with minimal latency.미러링된 읽기: 미러링된 읽기는 장애 후 프라이머리 투표의 영향을 줄이기 위해 세컨더리 노드의 캐시를 사전 예열합니다. 자세한 내용은 미러링된 읽기를 참조하세요.
요구 사항에 가장 적합한 복제 구성을 구현하는 방법에 대한 지침을 알아보려면 MongoDB의 Professional Services에 문의하세요.
네트워크 구성
다음 네트워크 연결 옵션을 사용하여 보안을 강화하고 지연 시간을 추가로 줄일 수 있습니다.
데이터 모델링 및 쿼리 최적화
애플리케이션이 데이터에 액세스하는 속도가 지연 시간에 영향을 미칩니다. 데이터 모델링과 쿼리 최적화를 잘 수행하면 데이터 액세스 속도를 개선할 수 있습니다. 예를 들어 다음과 같은 작업을 수행할 수 있습니다.
문서 크기 줄이기: 네트워크를 통한 데이터 전송량을 줄이기 위해 필드 이름과 값 길이를 줄이는 것이 좋습니다.
쿼리 패턴 최적화: 인덱스를 효과적으로 사용하여 여러 리전에서 읽어야 하는 데이터의 양을 최소화합니다.
지연 시간 모니터링 및 테스트
Atlas 다양한 리전의 지연 시간 지표 관찰할 수 있는 실시간 성능 패널 (실시간 성능 패널) 을 제공합니다. 애플리케이션 수준 모니터링 구현 애플리케이션 과 주고받는 엔드 투 엔드 지연 시간 추적 수도 있습니다. 최종 프로덕션 배포서버 전에 지연 시간 병목 현상을 식별하고 주소 위해 다양한 멀티 리전 시나리오 에서 성능 테스트를 수행하는 것이 좋습니다.
배포서버 모니터링 에 대해 자세히 학습하려면 Atlas 모니터링 및 경고에 대한 지침을 참조하세요.
연결 구성
가능한 경우 애플리케이션의 프로그래밍 언어에 가장 적합한 최신 드라이버 버전으로 빌드된 연결 방법을 사용하는 것이 좋습니다. Atlas가 제공하는 기본값 연결 문자열로 시작하는 것이 가능하지만, 연결 문자열에 연결 문자열 옵션을 추가하여 특정 애플리케이션 및 배포서버 아키텍처의 컨텍스트에서 성능을 개선할 수 있습니다.
엔터프라이즈 수준 애플리케이션 배포의 경우 운영 지연 시간 최소화하면서 사용자 수요를 충족하도록 연결 풀 설정을 조정하는 것이 특히 중요합니다. 예시 를 들어 및 옵션을 사용하여 대부분의 minPoolSize maxPoolSize 데이터베이스 클라이언트 연결이 열리는 방법과 시기를 조정하여 관련 네트워크 오버헤드 와 함께 발생하는 지연 시간 시간 급증을 방지하거나 계획할 수 있습니다.
이러한 설정을 구성할 수 있는 정도는 배포 아키텍처에 따라 다릅니다. 예를 들어, 애플리케이션 배포서버가 AWS Lambda와 같은 단일 스레드 리소스를 활용하는 경우, 애플리케이션은 하나의 클라이언트 연결만 열고 사용할 수 있습니다. 연결 풀을 생성하고 사용하는 방법과 위치, 연결 풀 설정을 지정하는 위치에 대한 자세한 내용은 연결 풀 개요를 참조하세요.
지연 시간이 짧은 애플리케이션 예시
다음 샘플 애플리케이션 데이터 작업 지연 시간 줄이기 위해 이 페이지에 주요 권장 사항을 제공합니다.
재시도 가능한 쓰기, 대다수 쓰기 고려 및 기본 읽기 고려와 함께 Atlas에서 제공하는 연결 문자열을 사용합니다.
Specify an operation time limit with the maxTimeMS method. For instructions on how to set
maxTimeMS, refer to your specific Driver Documentation.키 중복 및 시간 초과에 대한 오류를 처리합니다.
이 애플리케이션 클라이언트가 사용자 레코드를 생성하거나 나열할 수 있는 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 client libraries 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.")