Docs Menu
Docs Home
/ /

Atlas 지연 시간 감소 지침

다음 섹션에서는 Atlas 배포에서 지연 시간을 단축하기 위해 선택할 수 있는 구성 옵션을 설명합니다.

물리적 거리는 지연 시간의 주요 원인입니다. 사용자와 애플리케이션 간 거리, 애플리케이션과 데이터 간 거리, 클러스터 노드 간 거리는 모두 시스템 지연 시간과 애플리케이션 성능에 영향을 미칩니다.

읽기 및 쓰기 (write) 작업의 지연 시간 줄이려면 애플리케이션 과 데이터를 지리적으로 사용자에게 더 가깝게 배치하는 것이 중요합니다. 데이터 보유 Atlas 노드는 데이터베이스의 데이터를 저장하고 읽기 및 쓰기 (write) 작업을 처리하는 Atlas 클러스터 내의 서버 노드입니다. 애플리케이션 사용자의 더 빠른 데이터 액세스 지원 하려면 데이터를 포함하는 Atlas 노드를 대다수의 애플리케이션 사용자와 지리적으로 가까운 cloud 제공자 리전에 배포 .

애플리케이션 사용자가 미국과 유럽 등 여러 지역에 분산되어 있는 경우, 각 지역마다 하나 이상의 리전에 배포해 각 위치에서 사용자의 지연 시간을 줄이는 것이 좋습니다. 멀티 리전 배포서버에 대해 자세히 알아보려면멀티 리전 배포서버 패러다임을 참조하세요.

데이터가 지역별로 나누어져 각 지역의 사용자가 서로 다른 데이터 세트에 액세스 경우 각 지역의 사용자의 읽기 및 쓰기 (write) 성능을 최적화하기 위해 리전 또는 지역별로 데이터를 샤드 할 수도 있습니다. 이 접근 방식을 사용하면 데이터 지역성을 보장하면서 대규모 데이터 세트와 높은 처리량 처리하다 할 수 있습니다.

복제란 프라이머리 노드에서 세컨더리 노드로 데이터를 복사하는 것입니다. 다음 복제 구성 옵션을 조정하여 복제본 세트에서 읽기 및 쓰기 작업의 지연 시간을 최소화할 수 있습니다.

  • 쓰기 고려 (write concern) 수준: 쓰기 고려 (write concern)를 구성할 때 쓰기 (write) 지연 시간과 쓰기 (write) 내구성 간에는 장단점이 있습니다. MongoDB의 기본값 전역 쓰기 고려 (write concern) majority로 설정하다 있으며, 각 쓰기 (write) 작업은 Atlas 작업이 완료되고 성공적인 것으로 클라이언트 하기 전에 복제본 세트 의 데이터 보유 투표 노드 과반수에 복제되어야 합니다. 쓰기 고려 (write concern)를 높게 설정하면 쓰기 (write) 지연 시간이 늘어나지만 쓰기 (write) 내구성이 향상되고 복제본 세트 페일오버 중 롤백 이 방지됩니다.

  • 읽기 고려 (read concern) 및 읽기 설정 (read preference): 읽기 고려 (read concern)읽기 설정 (read preference) 구성할 때 쿼리 지연 시간, 데이터 가용성, 쿼리 응답의 일관성 간에는 장단점이 있습니다. MongoDB의 기본값 글로벌 읽기 고려 (read concern) local이며, 읽기 작업은 데이터가 다른 노드 간에 복제되는지 확인하기 위해 기다리지 않고 로컬 복제본 세트 의 하나의 노드 에서만 읽습니다. 이 노드 가 프라이머리 머리 노드인지 세컨더리 노드 인지는 Atlas 기본값 으로 primary (으)로 설정하는 읽기 설정 (read preference) 에 따라 결정됩니다. 이 기본값 읽기 고려 (read concern) 와 기본 설정 조합은 복제본 세트 의 최신 노드 에서 지연 시간 이 가장 짧은 읽기에 최적화되지만, 프라이머리 노드의 데이터가 지속형 없고 작업이 진행되는 동안 잠재적으로 롤백될 수 있는 위험도 있습니다. 페일오버 가능한 프라이머리 노드 없는 경우 사용자는 데이터를 쿼리 할 수 없습니다.

    읽기 설정을 primaryPreferred로 변경하면 사용 가능한 프라이머리 노드가 없거나 지리적으로 더 가까운 세컨더리 노드가 있을 때 읽기 작업이 세컨더리 노드에서 수행될 수 있습니다. 그러나 세컨더리 노드가 최신 상태가 아닐 경우 오래된 데이터를 반환할 위험이 있습니다. 쓰기 고려를 증가시켜 더 많은 세컨더리 노드를 최신 상태로 유지함으로써 이러한 위험을 완화할 수 있지만, 이 경우 쓰기 지연 시간이 증가하는 단점이 있습니다.

    중요

    복제 지연으로 인해 세컨더리 노드가 오래된 데이터를 반환할 가능성이 있다는 점을 염두에 두시기 바랍니다.

  • 쿼리 시간 제한: 배포서버에 글로벌 및 작업 수준 쿼리 시간 제한 을 설정하다 애플리케이션 시간이 초과되기 전에 응답을 기다리는 시간을 줄일 수 있습니다. 이렇게 하면 진행 중인 쿼리가 장기간 배포서버 성능에 부정적인 영향이 미치는 것을 방지할 수 있습니다.

  • 노드 투표 우선 순위: 복제본 세트 투표 동안 기본 데이터 센터의 멤버가 대체 데이터 센터의 멤버보다 먼저 프라이머리로 선출되도록 하려면 대체 데이터 센터의 멤버의 members[n].priority를 프라이머리 데이터 센터의 멤버보다 낮게 설정할 수 있습니다. 예를 들어, AWS us-east-1(버지니아 북부) 리전과 us-west-1(캘리포니아 북부) 리전에 클러스터를 배포하고, 사용자의 과반수가 캘리포니아에 있는 경우, AWS us-west-1 (캘리포니아 북부) 리전의 노드를 우선적으로 배치하여 프라이머리 노드를 항상 과반수의 사용자와 지리적으로 가까운 곳에 위치시키고, 최소한의 지연 시간으로 읽기 및 쓰기 작업에 응답할 수 있도록 합니다.

  • 미러링된 읽기: 미러링된 읽기는 장애 후 프라이머리 투표의 영향을 줄이기 위해 세컨더리 노드의 캐시를 사전 예열합니다. 자세한 내용은 미러링된 읽기를 참조하세요.

요구 사항에 가장 적합한 복제 구성을 구현하는 방법에 대한 지침을 알아보려면 MongoDB의 Professional Services에 문의하세요.

다음 네트워크 연결 옵션을 사용하여 보안을 강화하고 지연 시간을 추가로 줄일 수 있습니다.

  • 비공개 엔드포인트: 비공개 엔드포인트 는 애플리케이션의 가상 네트워크와 Atlas 클러스터 간에 직접적이고 안전한 연결을 설정하여 잠재적으로 네트워크 홉을 줄이고 지연 시간을 개선합니다.

  • VPC 피어링: 애플리케이션이 피어링된 리전에 연결할 수 있도록 복제본 세트에서 VPC 피어링을 구성합니다. 페일오버가 발생할 경우, VPC 피어링은 애플리케이션 서버가 새로운 프라이머리 노드를 감지하고 그에 따라 트래픽을 라우팅할 수 있는 방법을 제공합니다.

애플리케이션이 데이터에 액세스하는 속도가 지연 시간에 영향을 미칩니다. 데이터 모델링쿼리 최적화를 잘 수행하면 데이터 액세스 속도를 개선할 수 있습니다. 예를 들어 다음과 같은 작업을 수행할 수 있습니다.

  • 문서 크기 줄이기: 네트워크를 통한 데이터 전송량을 줄이기 위해 필드 이름과 값 길이를 줄이는 것이 좋습니다.

  • 쿼리 패턴 최적화: 인덱스를 효과적으로 사용하여 여러 리전에서 읽어야 하는 데이터의 양을 최소화합니다.

Atlas 다양한 리전의 지연 시간 지표 관찰할 수 있는 실시간 성능 패널 (실시간 성능 패널) 을 제공합니다. 애플리케이션 수준 모니터링 구현 애플리케이션 과 주고받는 엔드 투 엔드 지연 시간 추적 수도 있습니다. 최종 프로덕션 배포서버 전에 지연 시간 병목 현상을 식별하고 주소 위해 다양한 멀티 리전 시나리오 에서 성능 테스트를 수행하는 것이 좋습니다.

배포서버 모니터링 에 대해 자세히 학습하려면 Atlas 모니터링 및 경고에 대한 지침을 참조하세요.

가능한 경우 애플리케이션의 프로그래밍 언어에 가장 적합한 최신 드라이버 버전으로 빌드된 연결 방법을 사용하는 것이 좋습니다. Atlas가 제공하는 기본값 연결 문자열로 시작하는 것이 가능하지만, 연결 문자열에 연결 문자열 옵션을 추가하여 특정 애플리케이션 및 배포서버 아키텍처의 컨텍스트에서 성능을 개선할 수 있습니다.

엔터프라이즈 수준 애플리케이션 배포서버의 경우 운영 지연 시간 최소화하면서 사용자 수요를 충족하도록 연결 풀 설정을 조정하는 것이 특히 중요합니다. 예시 를 들어 minPoolSizemaxPoolSize 옵션을 사용하여 과반수 데이터베이스 클라이언트 연결이 열리는 방법과 시기를 조정하여 관련 네트워크 오버헤드 와 함께 발생하는 지연 시간 급증을 방지하거나 계획할 수 있습니다.

이러한 설정을 구성할 수 있는 범위는 배포서버 아키텍처에 따라 다릅니다. 예시 들어, 애플리케이션 배포서버 AWS Lambda 와 같은 단일 스레드 리소스를 활용하는 경우, 애플리케이션 하나의 클라이언트 연결만 열고 사용할 수 있습니다. 연결 풀 만들고 사용하는 방법과 위치, 연결 풀 설정을 지정하는 위치에 대한 자세한 학습 은 연결 풀 개요를 참조하세요.

다음 샘플 애플리케이션 데이터 작업 지연 시간 줄이기 위해 이 페이지에 주요 권장 사항을 제공합니다.

  • 재시도 가능한 쓰기, 대다수 쓰기 고려 및 기본 읽기 고려와 함께 Atlas에서 제공하는 연결 문자열을 사용합니다.

  • maxTimeMS 메서드를 사용하여 optime 제한을 지정합니다. maxTimeMS 설정 방법에 대한 지침은 해당 드라이버 설명서를 참조하세요.

  • 키 중복 및 시간 초과에 대한 오류를 처리합니다.

이 애플리케이션 클라이언트가 사용자 레코드를 생성하거나 나열할 수 있는 HTTP API 입니다. GET 및 게시 요청을 수락하는 엔드포인트 http://localhost:: 를 노출합니다.3000

메서드
엔드포인트
설명

GET

/users

users 컬렉션에서 사용자 이름 목록을 가져옵니다.

POST

/users

요청 본문에 name이 필요합니다. users 컬렉션에 새 사용자를 추가합니다.

참고

다음 서버 애플리케이션 프로젝트를 실행 하기 전에 프로젝트 에 종속성으로 추가해야 하는 NanoHTTPDJSON 사용합니다.

1// File: App.java
2
3import java.util.Map;
4import java.util.logging.Logger;
5
6import org.bson.Document;
7import org.json.JSONArray;
8
9import com.mongodb.MongoException;
10import com.mongodb.client.MongoClient;
11import com.mongodb.client.MongoClients;
12import com.mongodb.client.MongoCollection;
13import com.mongodb.client.MongoDatabase;
14
15import fi.iki.elonen.NanoHTTPD;
16
17public 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 @Override
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를 사용하며, 이를 실행하려면 프로젝트에 종속성으로 추가해야 합니다.

1const express = require('express');
2const bodyParser = require('body-parser');
3
4// Use the latest drivers by installing & importing them
5const MongoClient = require('mongodb').MongoClient;
6
7const app = express();
8app.use(bodyParser.json());
9app.use(bodyParser.urlencoded({ extended: true }));
10
11const uri = "mongodb+srv://<db_username>:<db_password>@cluster0-111xx.mongodb.net/test?retryWrites=true&w=majority";
12
13const client = new MongoClient(uri, {
14 useNewUrlParser: true,
15 useUnifiedTopology: true
16});
17
18// ----- API routes ----- //
19app.get('/', (req, res) => res.send('Welcome to my API!'));
20
21app.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
35app.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
46app.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
3from fastapi import FastAPI, Body, Request, Response, HTTPException, status
4from fastapi.encoders import jsonable_encoder
5
6from typing import List
7from models import User
8
9import pymongo
10from pymongo import MongoClient
11from pymongo import errors
12
13# Replace the uri string with your |service| connection string
14uri = "<atlas-connection-string>"
15db = "test"
16
17app = FastAPI()
18
19@app.on_event("startup")
20def startup_db_client():
21 app.mongodb_client = MongoClient(uri)
22 app.database = app.mongodb_client[db]
23
24@app.on_event("shutdown")
25def shutdown_db_client():
26 app.mongodb_client.close()
27
28##### API ROUTES #####
29@app.get("/users", response_description="List all users", response_model=List[User])
30def 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@app.post("/users", response_description="Create a new user", status_code=status.HTTP_201_CREATED)
38def 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.")

돌아가기

확장성

이 페이지의 내용