Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Orientación para la reducción de la latencia de Atlas

Las siguientes secciones enumeran las opciones de configuración que puede realizar para reducir la latencia en su implementación de Atlas.

La distancia física es la principal causa de latencia. La distancia entre los usuarios y tu aplicación, entre tu aplicación y tus datos, y entre los nodos del clúster, impacta en la latencia del sistema y el rendimiento de la aplicación.

Para reducir la latencia en las operaciones de lectura y guardar, es crucial ubicar tanto tu aplicación como tus datos geográficamente más cerca de los usuarios. Los nodos Atlas que contienen datos son nodos de servidor dentro de un clúster de Atlas que almacenan los datos de su base de datos y gestionan las operaciones de lectura y escritura. Para respaldar un acceso a los datos más rápido para los usuarios de tu aplicación, implementa nodos de Atlas con datos en regiones del proveedor de nube que estén geográficamente cerca de la mayoría de los usuarios de tu aplicación.

Si los usuarios de su aplicación están distribuidos en varias zonas geográficas, como EE. UU. y Europa, le recomendamos implementarla en una o más regiones de cada zona geográfica para reducir la latencia de los usuarios en cada ubicación. Para obtener más información sobre las implementaciones multirregionales, consulte Paradigma de implementación multirregional.

Si sus datos están divididos por geografía, de modo que los usuarios de cada geografía acceden a diferentes conjuntos de datos, también puede partición tus datos por región o ubicación geográfica para optimizar el rendimiento de lectura y escritura para los usuarios en cada ubicación geográfica. Este enfoque te permite gestionar grandes conjuntos de datos y un alto rendimiento, garantizando al mismo tiempo la localidad de datos.

Replicación es la copia de datos desde el nodo primario a los nodos secundarios. Las siguientes opciones de configuración de replicación pueden ajustarse para minimizar la latencia de las operaciones de lectura y escritura en un set de réplicas:

  • Niveles de nivel de confirmación de escritura (write concern): Existe una compensación entre la latencia de escritura y la durabilidad de escritura cuando se configura el nivel de confirmación de escritura (write concern). El nivel de confirmación de escritura (write concern) global por defecto de MongoDB se establece en majority, que requiere que cada operación de escritura se replique en la mayoría de los nodos con derecho a voto que contienen datos en su conjunto de réplicas antes de que Atlas la reconozca como completada y exitosa para el cliente. Configurar un nivel de escritura más alto aumenta la latencia de escritura, pero también mejora la durabilidad de la escritura y evita reversiones durante una conmutación por error del conjunto de réplicas.

  • Nivel de consistencia de lectura y Preferencia de lectura: Hay una compensación entre la latencia de consulta, la disponibilidad de datos y la coherencia de las respuestas de las consultas al configurar nivel de consistencia de lectura y preferencia de lectura. El nivel de consistencia de lectura global por defecto de MongoDB es local, que requiere que las operaciones de lectura se realicen únicamente desde un nodo del set de réplicas local sin esperar la confirmación de que los datos se hayan replicado en otros nodos. Si este nodo es el principal o uno secundario se determina según tu preferencia de lectura, que Atlas configura en primary por defecto. Esta combinación **por defecto** de **nivel de consistencia de lectura** y preferencia se optimiza para las lecturas de menor **latencia** desde el **nodo** más actualizado en el **set de réplicas**, pero también conlleva el riesgo de que los datos del **nodo primario** puedan no ser **durables** y potencialmente pueden revertirse durante un cambio de rol, y de que los usuarios no puedan consultar datos si no hay un **nodo primario** disponible.

    Puedes cambiar tu preferencia de lectura a primaryPreferred para permitir que las operaciones de lectura se realicen desde un nodo secundario cuando no haya un nodo primario disponible, o si hay un nodo secundario geográficamente más cercano, pero esto tiene el riesgo de devolver datos obsoletos si el nodo secundario no está actualizado. Este riesgo se puede mitigar aumentando su nivel de confirmación de escritura (write concern) para garantizar que más nodos secundarios estén actualizados, con la desventaja de que esto aumentará su latencia de escritura.

    Importante

    Tenga en cuenta que existe la posibilidad de que un nodo secundario devuelva datos obsoletos debido al retraso de replicación.

  • Límites de tiempo de espera de consultas: Puede establecer límites de tiempo de espera de consultas globales y a nivel de operación en su implementación para reducir el tiempo que su aplicación espera una respuesta antes de agotar el tiempo de espera. Esto puede evitar que las consultas continuas afecten negativamente el rendimiento de la implementación durante largos periodos.

  • Prioridad de Elección del Nodo: Para aumentar la probabilidad de que los nodos de tu centro de datos principal sean elegidos como primarios antes que los nodos de un centro de datos alterno durante una elección de set de réplicas, puedes establecer el members[n].priority de los nodos en el centro de datos alterno para que sea inferior al de los nodos en el centro de datos principal. Por ejemplo, si implementa su clúster en Sisu región de AWS es us-east-1 (Norte de Virginia) y us-west-1 (Norte de California), y la mayoría de sus usuarios se encuentran en California, puede priorizar los nodos en la región de AWS us-west-1 (Norte de California) para garantizar que el nodo principal esté siempre geográficamente cerca de la mayoría de sus usuarios y pueda responder a las operaciones de lectura y escritura con una latencia mínima.

  • Lecturas espejeadas: Las lecturas espejeadas reducen el impacto de las elecciones primarias tras una Interrupción del servicio al calentar previamente las cachés en los nodos secundarios. Para obtener más información, consulta lecturas espejeadas.

Para obtener más orientación sobre cómo implementar la mejor configuración de replicación para tus necesidades, comunícate con los Professional Services de MongoDB.

Puede aumentar la seguridad y reducir aún más la latencia utilizando las siguientes opciones de conectividad de red:

  • nodos privados: Los puntos finales privados establecen conexiones directas y seguras entre la red virtual de su aplicación y su clúster Atlas, lo que reduce potencialmente los saltos de red y mejora la latencia.

  • VPC emparejamiento: Configura el VPC emparejamiento en tus sets de réplicas para permitir que las aplicaciones se conecten a las regiones asociadas. En caso de un failover, el VPC emparejamiento ofrece una forma para que un servidor de aplicaciones detecte un nuevo nodo primario y enrute el tráfico en consecuencia.

La velocidad a la que tu aplicación accede a los datos contribuye a la latencia. Un buen modelado de datos y una optimización de query pueden mejorar la velocidad de acceso a los datos. Por ejemplo, se puede:

  • Reducir el tamaño del documento: Considera acortar los nombres de campos y las longitudes de los valores para disminuir la cantidad de transferencia de datos a través de la red.

  • Optimice los patrones de query: Utilice los índices de manera eficaz para minimizar la cantidad de datos que deben leerse entre regiones.

Atlas proporciona el Panel de Rendimiento en Tiempo Real (RTPP) para observar métricas de latencia en diferentes regiones. También puedes implementar supervisión a nivel de aplicación para rastrear la latencia de extremo a extremo hacia y desde la aplicación. Antes de la implementación final en producción, recomendamos realizar pruebas de rendimiento bajo los diversos escenarios multiregión para identificar y abordar los cuellos de botella de latencia.

Para obtener más información sobre cómo supervisar tu implementación, consulta Orientación para la supervisión y alertas de Atlas.

Recomendamos que utilices un método de conexión basado en la versión más actual del controlador para el lenguaje de programación de tu aplicación siempre que sea posible. Aunque la cadena de conexión por defecto que Atlas proporciona es un buen punto de partida, puedes agregar opciones de cadenas de conexión a tu cadena de conexión para mejorar el rendimiento en el contexto de tu aplicación específica y arquitectura de implementación.

Para implementaciones de aplicaciones a nivel empresarial, es especialmente importante ajustar la configuración del pool de conexiones para satisfacer la demanda de los usuarios y al mismo tiempo minimizar la latencia operativa. Por ejemplo, puedes utilizar las opciones minPoolSize y maxPoolSize para ajustar cómo y cuándo se abren la mayoría de las conexiones de clientes de tu base de datos, lo que te permite prevenir o planificar los picos de latencia que vienen con la sobrecarga de red asociada.

El grado en que puedes configurar estas opciones depende de tu arquitectura de implementación. Por ejemplo, si la implementación de tu aplicación utiliza recursos de un solo hilo, como AWS Lambda, tu aplicación solo podrá abrir y usar una conexión de cliente a la vez. Para aprender más acerca de cómo y dónde crear y usar un pool de conexiones, y dónde especificar la configuración del pool de conexiones, consulte Descripción general del pool de conexiones.

La siguiente aplicación de muestra reúne recomendaciones clave de esta página para reducir la latencia de la operación de datos:

  • Utilice la cadena de conexión proporcionada por Atlas con escrituras reintentables, nivel de confirmación de escritura de mayoría y nivel de consistencia de lectura por defecto.

  • Especificar un límite de operation time con el método maxTimeMS. Para obtener instrucciones sobre cómo configurar maxTimeMS, consulta tu documentación del driver.

  • Gestione errores por claves duplicadas y "timeouts".

La aplicación es una API HTTP que permite a los clientes crear o listar registros de usuario. Expone un endpoint que acepta solicitudes GET y POST http://localhost:3000:

Método
Endpoint
Descripción

GET

/users

Obtiene una lista de nombres de usuario de una colección users.

POST

/users

Requiere un name en el cuerpo de la solicitud. Agrega un nuevo usuario a una colección users.

Nota

La siguiente aplicación de servidor utiliza NanoHTTPD y json que debes añadir a tu proyecto como dependencias antes de poder ejecutarla.

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}

Nota

La siguiente aplicación de servidor utiliza Express, que debe agregar a su proyecto como dependencia antes de poder ejecutarlo.

1const express = require('express');
2const bodyParser = require('body-parser');
3
4// Use the latest client libraries 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});

Nota

La siguiente aplicación web utiliza FastAPI. Para crear una nueva aplicación, se debe usar la estructura del archivo de muestra de 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.")

Volver

Escalabilidad

En esta página