As seções a seguir listam as opções de configuração que você pode fazer para reduzir a latência em seu sistema do Atlas .
Distância física
A distância física é a principal causa de latência. A distância entre os usuários e o seu aplicativo, entre o seu aplicativo e os seus dados, e entre os nós do cluster impacta a latência do sistema e o desempenho do aplicativo.
Para reduzir a latência para operações de leitura e escrita, é crucial colocar seu aplicação e seus dados geograficamente mais próximos dos usuários. Os nós do Atlas portadores de dados são nós do servidor dentro de um Atlas cluster que armazenam os dados do seu banco de dados e gerenciam operações de leitura e gravação. Para oferecer suporte ao acesso mais rápido a dados para os usuários do aplicação , implemente nós do Atlas com dados em regiões de provedor de nuvem geograficamente próximas à maioria dos usuários do aplicação .
Se os usuários do seu aplicativo estiverem distribuídos em várias regiões, como entre os EUA e a Europa, recomendamos que você implante em uma ou mais regiões em cada região para reduzir a latência para usuários em cada localidade. Para saber mais sobre sistemas de multirregional , consulte Paradigma de sistema de várias regiões do.
Se seus dados estiverem divididos por região, de modo que os usuários em cada região acessem diferentes conjuntos de dados, você também poderá fragmentar seus dados por região ou região para otimizar o desempenho de leitura e gravação para usuários em cada região. Essa abordagem permite que você lide com grandes conjuntos de dados e alta taxa de transferência, garantindo a localidade dos dados.
Configuração de replicação
Replicação é a cópia de dados do nó primário para nós secundários. As seguintes opções de configuração de replicação podem ser ajustadas para minimizar a latência para operações de leitura e gravação em um conjunto de réplicas:
Níveis de write concern: Há uma troca entre latência de escrita e durabilidade de escrita quando você configura o preocupação de gravação. A preocupação de gravação global padrão do MongoDB é definida
majoritycomo, o que exige que cada operação de gravação seja replicada na maioria dos nós votantes e portadores de dados em seu conjunto de réplicas antes que o Atlas reconheça que a operação foi concluída e bem-sucedida para o cliente. A definição de uma preocupação de gravação mais alta aumenta a latência de gravação, mas também melhora a durabilidade da gravação e evita reversões durante um failover de conjunto de réplicas.Read Concern e Read Preference: Há uma compensação entre a latência da query, a disponibilidade de dados e a consistência de suas respostas de query quando você configura a preocupação de leitura e a preferência de leitura. A preocupação de leitura global padrão do MongoDB
localé, que requer operações de leitura para ler de apenas um nó no conjunto de réplicas local sem esperar para confirmar que os dados são replicados em outros nós. Se esse nó é o primary ou um nó secundário é determinado pela sua preferência de leitura, que o Atlas defineprimarycomo por padrão. Essa combinação padrão de preocupação de leitura e preferência otimiza as leituras de menor latência do nó mais atualizado do conjunto de réplicas, mas também corre o risco de que os dados do nó primário não sejam duráveis e possam ser revertidos durante um failover e que os usuários não poderão consultar dados se não houver nenhum nó primário disponível.Você pode alterar sua preferência de leitura para
primaryPreferredpara permitir que as operações de leitura leiam de um nó secundário quando não houver nenhum nó primário disponível ou se houver um nó secundário geograficamente mais próximo, mas isso corre o risco de retornar dados obsoletos se um secundário nó não está atualizado. Esse risco pode ser mitigado aumentando a preocupação de gravação para garantir que mais nós secundários estejam atualizados, com a compensação de que isso aumenta a latência de escrita.Importante
Lembre-se de que existe a possibilidade de um nó secundário retornar dados obsoletos devido ao atraso de replicação.
Limites de tempo limite de query: Você pode definir limites de tempo limite de query globais e em nível de operação em seu sistema para reduzir o tempo que seu aplicação aguarda uma resposta antes de atingir o tempo limite. Isso pode impedir que queries contínuas afetem negativamente o desempenho da implantação por longos períodos de tempo.
Prioridade de eleição do nó: para aumentar a probabilidade de que os membros em seu centro de dados principal sejam eleitos como primários antes dos membros em um centro de dados alternativo durante uma eleição de conjunto de réplicas, você pode definir o
members[n].prioritydos membros no centro de dados alternativo como menor do que a dos membros no centro de dados primário. Por exemplo, se você implantar seu cluster nas regiõesda AWSus-east-1(Norte da Virgínia) eus-west-1(Norte da Califórnia), e a maioria dos usuários estiver na Califórnia, você pode priorizar nós naus-west-1região (Norte da Califórnia) para garantir que o nó primário esteja sempre geograficamente próximo à maioria dos usuários e possa responder a operações de leitura e gravação com latência mínima.Leituras espelhadas: as leituras espelhadas reduzem o impacto das eleições primárias após uma interrupção, pré-aquecendo os caches nos nós secundários. Para mais informações, consulte Leituras espelhadas.
Para obter mais orientações sobre como implementar a melhor configuração de replicação para suas necessidades, entre em contato com os Serviços profissionais do MongoDB.
Configuração de Rede
Você pode aumentar a segurança e reduzir ainda mais a latência usando as seguintes opções de conectividade de rede:
Endpoints privados: Os endpoints privados estabelecem conexões diretas e seguras entre a rede virtual do seu aplicativo e o seu Atlas cluster, potencialmente reduzindo os saltos de rede e melhorando a latência.
Emparelhamento de VPC: configure o emparelhamento de VPC em seus conjuntos de réplicas para permitir que os aplicativos se conectem a regiões emparelhadas. No evento de um failover, o emparelhamento da VPC fornece uma maneira de um servidor de aplicação detectar um novo nó primário e direcionar o tráfego adequadamente.
Modelagem de dados e otimização de queries
A velocidade com que seu aplicação acessa os dados contribui para a latência. Uma boa modelagem de dados e otimização de queries podem melhorar as velocidades de acesso aos dados. Por exemplo, você pode:
Reduzir o tamanho do documento: considere reduzir os nomes dos campo e os comprimentos dos valores para diminuir a quantidade de dados transferidos pela rede.
Otimização de padrões de query: use índices de forma eficaz para minimizar a quantidade de dados que precisam ser lidos entre regiões.
Monitoramento e testes de latência
O Atlas fornece o Painel de Desempenho em Tempo Real (Real-Time Performance Panel) para observar métricas de latência para diferentes regiões. Você também pode implementar o monitoramento em nível de aplicativo para acompanhar a latência de ponta a ponta de e para o aplicação. Antes da implantação na produção final, sugerimos realizar testes de desempenho nos vários cenários de multirregional para identificar e resolver gargalos de latência.
Para saber mais sobre como monitorar sua implantação,consulte Orientação para Monitoramento e Alertas do Atlas .
Configuração da conexão
Recomendamos que você use um método de conexão criado na versão do driver mais atual para a linguagem de programação do seu aplicativo sempre que possível. Embora a string de conexão padrão fornecida Atlas seja um bom ponto de partida, você pode adicionar opções de string de conexão à sua string de conexão para melhorar o desempenho no contexto do seu aplicação específico e da arquitetura de implantação.
Para sistemas de aplicação de nível empresarial, é especialmente importante ajustar as configurações do pool de conexões para atender à demanda do usuário e, ao mesmo tempo, minimizar a latência operacional. Por exemplo , você pode usar as opções minPoolSize e maxPoolSize para ajustar como e quando a maioria das conexões de cliente de banco de dados é aberta, permitindo evitar ou planejar os picos de latência que acompanham a sobrecarga de rede associada.
A extensão em que você pode definir essas configurações depende da arquitetura de seu sistema. Por exemplo, se o sistema de aplicação estiver aproveitando recursos de thread único, como o AWS Lambda, seu aplicação só poderá abrir e usar uma conexão de cliente . Para saber mais sobre como e onde criar e usar um pool de conexões e onde especificar as configurações do pool de conexões , consulte Visão geral do pool de conexões.
Exemplo de aplicativo de baixa latência
O seguinte aplicação de amostra reúne as principais recomendações nesta página para reduzir a latência da operação de dados:
Use a cadeia de conexão fornecida pelo Atlas com gravações repetíveis, preocupação de gravação majoritária e preocupação de leitura padrão.
Especifique um limite de optime com o método maxTimeMS . Para obter instruções sobre como configurar o
maxTimeMS, consulte sua Documentação do Driverespecífica.Lidar com erros de chaves duplicadas e tempos-limite.
O aplicação é uma API HTTP que permite aos clientes criar ou listar registros de usuário. Ele expõe um endpoint que aceita solicitações GET e POST http://localhost::3000
Método | Endpoint | Descrição |
|---|---|---|
|
| Obtém uma lista de nomes de usuário de uma coleção do |
|
| Exige um |
Observação
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 }
Observação
O aplicativo de servidor a seguir usa o Express, que você precisa adicionar ao seu projeto como uma dependência antes de executá-lo.
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 });
Observação
O seguinte aplicação da web usa FastAPI. Para criar um novo aplicação, use a estrutura de arquivo de amostra 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.")