Menu Docs
Página inicial do Docs
/ /

Orientação para redução da latência do Atlas

As seções a seguir listam as opções de configuração que você pode fazer para reduzir a latência em sua implantação do Atlas.

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 gravação, é crucial colocar seu aplicativo 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 cluster Atlas que armazenam os dados do seu banco de dados e lidam com operações de leitura e gravação. Para oferecer suporte ao acesso aos dados mais rápido para os usuários do aplicativo, implante nós do Atlas em regiões de provedor de nuvem geograficamente próximas à maioria dos usuários do aplicativo.

Se os usuários do seu aplicativo estiverem distribuídos em várias áreas geográficas, como entre os EUA e a Europa, recomendamos que você implante em uma ou mais regiões em cada área geográfica para reduzir a latência para usuários em cada localização. Para saber mais sobre implantações multirregionais, consulte Paradigma de implantação multirregional.

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á dividir seus dados em fragmentos por região ou geografia 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.

Replicação é o processo de copiar dados do nó primário para os nós secundários. As seguintes opções de configuração de replicação podem ser ajustadas para minimizar a latência nas operações de leitura e para gravar em um conjunto de réplicas:

  • Níveis de preocupação de gravação: Há uma troca entre latência de escrita e durabilidade de escrita quando você configura preocupação de gravação. A preocupação de gravação global padrão do MongoDB é definida como majority, 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 rollback durante um failover de conjunto de réplicas.

  • Preocupação de Leitura e Preferência de Leitura: 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 preocupação de leitura e 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 primário ou um nó secundário é determinado pela sua preferência de leitura, que o Atlas define como primary 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 query dados se não houver nenhum nó primário disponível.

    Você pode alterar sua preferência de leitura para primaryPreferred para que operações de leitura sejam realizadas a partir de um secundário quando não houver nó primário disponível, ou se houver um secundário geograficamente mais próximo, mas isso corre o risco de retornar dados desatualizados se um secundário não estiver atualizado. Esse risco pode ser mitigado aumentando sua preocupação de gravação para que mais nós secundários estejam atualizados, com a desvantagem de que isso aumenta sua latência de gravação.

    Importante

    Observe que existe a possibilidade de um nó secundário retornar dados desatualizados devido ao atraso de replicação.

  • Limites de tempo limite de query: Você pode definir limites globais e em nível de operação de tempo limite de query em sua implantação para reduzir o tempo que seu aplicativo aguarda uma resposta antes de atingir o tempo limite. Isso pode impedir que queries contínuas impactem negativamente o desempenho da implantação por longos períodos de tempo.

  • Prioridade de eleição de nó: Para aumentar a probabilidade de que os membros no seu data center principal sejam eleitos primários antes dos membros em um data center alternativo durante uma eleição de conjunto de réplicas, você pode definir a members[n].priority prioridade dos membros no data center alternativo para ser menor do que a dos membros no data center primário. Por exemplo, se você implantar seu cluster nas regiões AWS us-east-1 (Norte da Virgínia) e us-west-1 (Norte da Califórnia), e a maioria dos seus usuários estiver na Califórnia, você pode priorizar os nós na região AWS us-west-1 (Norte da Califórnia) para que o nó primário esteja sempre geograficamente próximo à maioria dos seus 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 mais orientação sobre como implementar a melhor configuração de replicação para suas necessidades, entre em contato com a equipe de Professional Services do MongoDB.

Você pode aumentar a segurança e reduzir ainda mais a latência usando as seguintes opções de conectividade de rede:

  • Pontos de extremidade privados: pontos de extremidade privados estabelecem conexões diretas e seguras entre a rede virtual do seu aplicativo e o seu cluster Atlas, 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 que os aplicativos se conectem a regiões emparelhadas. No caso de failover, o emparelhamento VPC fornece uma maneira de um servidor de aplicativo detectar um novo nó primário e rotear o tráfego de acordo.

A velocidade com que seu aplicativo acessa os dados contribui para a latência. Boa modelagem de dados e otimização de queries podem acelerar o acesso aos dados. Por exemplo, você pode:

  • Reduzir o tamanho do documento: considere reduzir os nomes dos campos e os comprimentos dos valores para diminuir a quantidade de transferência de dados 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.

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 monitoramento da sua implantação, consulte orientação para monitoramento e alertas do Atlas.

Recomendamos que, sempre que possível, utilize um método de conexão baseado na versão mais recente do driver para a linguagem de programação do seu aplicativo. Embora a string de conexão padrão fornecida pelo Atlas seja um bom ponto de partida, você pode adicionar opções à sua string de conexão para melhorar o desempenho no contexto específico do seu aplicativo e arquitetura de implantação.

Para implantações de aplicativos 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 sua implantação. Por exemplo, se a implantação do seu aplicativo estiver aproveitando recursos de thread único, como AWS Lambda, seu aplicativo 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.

O seguinte aplicativo 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 aplicativo é uma HTTP API que permite aos clientes criar ou listar registros de usuário. Ele expõe um ponto de extremidade que aceita solicitações GET e publicações http://localhost:3000:

Método
Endpoint
Descrição

GET

/users

Obtém uma lista de nomes de usuário de uma coleção do users.

POST

/users

Exige um name no corpo da solicitação. Adiciona um novo usuário a uma coleção users.

Observação

A aplicação de servidor a seguir usa NanoHTTPD e JSON, que você precisa adicionar ao seu projeto como dependências antes de executá-lo.

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}

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.

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});

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
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.")

Voltar

Escalabilidade

Nesta página