Docs Menu
Docs Home
/ /

Guía para la reducción de 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 la aplicación, entre la aplicación y los datos, y entre los nodos del clúster, afecta la latencia del sistema y el rendimiento de la aplicación.

Para reducir la latencia de las operaciones de lectura y escritura, es fundamental ubicar tanto la aplicación como los datos geográficamente más cerca de los usuarios. Los nodos Atlas con datos son nodos de servidor dentro de un clúster Atlas que almacenan los datos de la base de datos y gestionan las operaciones de lectura y escritura. Para que los usuarios de la aplicación puedan acceder a los datos más rápidamente, implemente los nodos Atlas con datos en las regiones de los proveedores de nube que estén geográficamente cerca de la mayoría de los usuarios de la 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 Parta sus datos por región o geografía para optimizar el rendimiento de lectura y escritura para los usuarios en cada zona. Este enfoque le permite gestionar grandes conjuntos de datos y un alto rendimiento, a la vez que garantiza la localización de los 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 preocupación de escritura: Existe un equilibrio entre la latencia y la durabilidad de la escritura al configurar la preocupación de escritura. La preocupación de escritura global predeterminada de MongoDB está establecida 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.

  • Preocupación de lectura y preferencia de lectura:Al configurar la preocupación de lectura y la preferencia de lectura, existe un equilibrio entre la latencia de las consultas, la disponibilidad de los datos y la consistencia de las respuestas. La preocupación de lectura global predeterminada de MongoDB local es, lo que requiere que las operaciones de lectura lean solo desde un nodo del conjunto de réplicas local sin esperar a confirmar que los datos se replican en otros nodos. La preferencia de lectura, que Atlas establece en por defecto, determina si este nodo es el principal o el primary secundario. Esta combinación predeterminada de preocupación de lectura y preferencia optimiza las lecturas con la menor latencia desde el nodo más actualizado del conjunto de réplicas, pero también conlleva el riesgo de que los datos del nodo principal no sean duraderos y se reviertan durante una conmutación por error, y de que los usuarios no puedan consultar los datos si no hay un nodo principal disponible.

    Puede cambiar su preferencia de lectura a primaryPreferred para permitir que las operaciones de lectura se realicen desde un nodo secundario cuando no haya un nodo principal disponible o si hay un nodo secundario geográficamente más cercano. Sin embargo, esto conlleva el riesgo de devolver datos obsoletos si un nodo secundario no está actualizado. Este riesgo se puede mitigar aumentando la prioridad de escritura para garantizar que más nodos secundarios estén actualizados, con la desventaja de que esto aumenta la 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 de nodo: Para aumentar la probabilidad de que los miembros de su centro de datos principal sean elegidos como principales antes que los miembros de un centro de datos alternativo durante una elección de conjunto de réplicas, puede establecer el members[n].priority de los miembros del centro de datos alternativo para que sea menor que el de los miembros del 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 duplicadas: Las lecturas duplicadas reducen el impacto de las elecciones primarias tras una interrupción del servicio al precalentar las cachés en los nodos secundarios. Para más información, consulte Lecturas duplicadas.

Para obtener más orientación sobre cómo implementar la mejor configuración de replicación para sus necesidades, comuníquese con los Servicios profesionales de MongoDB.

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

  • Puntos finales 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.

  • Emparejamiento de VPC: Configure el emparejamiento de VPC en sus conjuntos de réplicas para permitir que las aplicaciones se conecten a las regiones emparejadas. En caso de conmutación por error, el emparejamiento de VPC permite que un servidor de aplicaciones detecte un nuevo nodo principal y enrute el tráfico en consecuencia.

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

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

  • Optimizar patrones de consulta: utilice índices de manera eficaz para minimizar la cantidad de datos que deben leerse en las regiones.

Atlas proporciona el Panel de Rendimiento en Tiempo Real (RTPP) para observar las métricas de latencia en diferentes regiones. También puede implementar la monitorizació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, le sugerimos realizar pruebas de rendimiento en los diversos escenarios multirregionales para identificar y abordar los cuellos de botella de latencia.

Para obtener más información sobre cómo supervisar su implementación, consulte Guía para el monitoreo y las alertas de Atlas.

Le recomendamos que utilice un método de conexión basado en la versión más reciente del controlador para el lenguaje de programación de su aplicación siempre que sea posible. Si bien la cadena de conexión predeterminada que proporciona Atlas es un buen punto de partida, puede agregar opciones de cadena de conexión para mejorar el rendimiento en el contexto de su aplicación y arquitectura de implementación específicas.

Para implementaciones de aplicaciones empresariales, es fundamental ajustar la configuración del grupo de conexiones para satisfacer la demanda de los usuarios y minimizar la latencia operativa. Por ejemplo, puede usar las minPoolSize opciones y maxPoolSize para ajustar cómo y cuándo se abren la mayoría de las conexiones de los clientes de base de datos, lo que le permite prevenir o planificar los picos de latencia que conlleva la sobrecarga de red.

La medida en que puede configurar estos ajustes depende de la arquitectura de su implementación. Por ejemplo, si la implementación de su aplicación utiliza recursos de un solo subproceso,como AWS Lambda, su aplicación solo podrá abrir y usar una conexión de cliente. Para obtener más información sobre cómo y dónde crear y usar un grupo de conexiones, y dónde especificar la configuración del grupo de conexiones, consulte Descripción general del grupo 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:

La aplicación es una API HTTP que permite a los clientes crear o listar registros de usuarios. Expone un punto final 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 debe agregar a su proyecto como dependencias antes de poder ejecutarlo.

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, utilice la estructura de archivo de ejemplo 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