Architetture di database multimaster replicate a livello globale con Cosmos DBMulti-master globally replicated database architectures with Azure Cosmos DB

Cosmos DB di Azure supporta la replica globale chiavi in mano, che consente di distribuire i dati in più aree con accesso a bassa latenza in qualsiasi punto del carico di lavoro.Azure Cosmos DB supports turnkey global replication, which allows you to distribute data to multiple regions with low latency access anywhere in the workload. Questo modello viene usato in genere per carichi di lavoro di pubblicazione/consumer in cui è presente un writer in una singola area geografica e con lettori distribuiti a livello globale in altre aree (lettura).This model is commonly used for publisher/consumer workloads where there is a writer in a single geographic region and globally distributed readers in other (read) regions.

È anche possibile usare il supporto per la replica globale di Azure Cosmos DB per creare applicazioni in cui i writer e i lettori sono distribuiti in modo globale.You can also use Azure Cosmos DB's global replication support to build applications in which writers and readers are globally distributed. Questo documento illustra un modello che consente di ottenere l'accesso in scrittura e lettura locale per i writer distribuiti mediante Azure Cosmos DB.This document outlines a pattern that enables achieving local write and local read access for distributed writers using Azure Cosmos DB.

Pubblicazione del contenuto: scenario di esempioContent Publishing - an example scenario

È possibile esaminare uno scenario concreto per illustrare il modo in cui possono essere usati i modelli di lettura e scrittura in più aree e multimaster distribuiti a livello globale con Cosmos DB.Let's look at a real world scenario to describe how you can use globally distributed multi-region/multi-master read write patterns with Azure Cosmos DB. Esaminare una piattaforma di pubblicazione di contenuti creata in Cosmos DB.Consider a content publishing platform built on Azure Cosmos DB. Ecco alcuni requisiti che devono essere rispettati da questa piattaforma per offrire un'esperienza utente ottimale per server di pubblicazione e consumer.Here are some requirements that this platform must meet for a great user experience for both publishers and consumers.

  • Gli autori e i sottoscrittori sono distribuiti in tutto il mondo.Both authors and subscribers are spread over the world
  • Gli autori devono pubblicare (scrivere) articoli nella rispettiva area locale (più vicina).Authors must publish (write) articles to their local (closest) region
  • Gli autori hanno lettori/sottoscrittori degli articoli distribuiti in tutto il mondo.Authors have readers/subscribers of their articles who are distributed across the globe.
  • I sottoscrittori ricevono una notifica quando vengono pubblicati nuovi articoli.Subscribers should get a notification when new articles are published.
  • I sottoscrittori devono essere in grado di leggere articoli dalla rispettiva area locale.Subscribers must be able to read articles from their local region. Devono anche potere aggiungere revisioni per questi articoli.They should also be able to add reviews to these articles.
  • Qualunque utente, incluso l'autore degli articoli, deve potere visualizzare tutte le revisioni allegate agli articoli da un'area locale.Anyone including the author of the articles should be able view all the reviews attached to articles from a local region.

Supponendo che siano presenti milioni di consumer e server di pubblicazione con miliardi di articoli, sarà presto necessario affrontare i problemi relativi alla scalabilità, oltre a garantire l'accesso locale.Assuming millions of consumers and publishers with billions of articles, soon we have to confront the problems of scale along with guaranteeing locality of access. Analogamente alla maggior parte dei problemi di scalabilità, la soluzione è basata su una strategia di partizionamento ottimale.As with most scalability problems, the solution lies in a good partitioning strategy. Ecco come modellare gli articoli, le revisioni e le notifiche come documenti, configurare gli account Cosmos DB e implementare un livello di accesso ai dati.Next, let's look at how to model articles, review, and notifications as documents, configure Azure Cosmos DB accounts, and implement a data access layer.

Per altre informazioni sul partizionamento e sulle chiavi di partizione, vedere Partizionamento e scalabilità in Azure Cosmos DB.If you would like to learn more about partitioning and partition keys, see Partitioning and Scaling in Azure Cosmos DB.

Modellazione delle notificheModeling notifications

Le notifiche sono feed di dati specifici per un utente.Notifications are data feeds specific to a user. I modelli di accesso per i documenti di notifica sono quindi sempre nel contesto di un singolo utente.Therefore, the access patterns for notifications documents are always in the context of single user. È ad esempio possibile "inserire una notifica per un utente" o "recuperare tutte le notifiche per un utente specifico".For example, you would "post a notification to a user" or "fetch all notifications for a given user". La scelta ottimale di chiave di partizionamento per questo tipo sarebbe quindi UserId.So, the optimal choice of partitioning key for this type would be UserId.

class Notification 
{ 
    // Unique ID for Notification. 
    public string Id { get; set; }

    // The user Id for which notification is addressed to. 
    public string UserId { get; set; }

    // The partition Key for the resource. 
    public string PartitionKey 
    { 
        get 
        { 
            return this.UserId; 
        }
    }

    // Subscription for which this notification is raised. 
    public string SubscriptionFilter { get; set; }

    // Subject of the notification. 
    public string ArticleId { get; set; } 
}

Modellazione delle sottoscrizioniModeling subscriptions

Le sottoscrizioni possono essere create per diversi criteri, ad esempio per una categoria di articoli rilevanti o un server di pubblicazione specifico.Subscriptions can be created for various criteria like a specific category of articles of interest, or a specific publisher. SubscriptionFilter è quindi una scelta appropriata per la chiave di partizione.Hence the SubscriptionFilter is a good choice for partition key.

class Subscriptions 
{ 
    // Unique ID for Subscription 
    public string Id { get; set; }

    // Subscription source. Could be Author | Category etc. 
    public string SubscriptionFilter { get; set; }

    // subscribing User. 
    public string UserId { get; set; }

    public string PartitionKey 
    { 
        get 
        { 
            return this.SubscriptionFilter; 
        } 
    } 
}

Modellazione degli articoliModeling articles

Dopo l'identificazione di un articolo tramite le notifiche, le query successive sono in genere basate su Article.Id.Once an article is identified through notifications, subsequent queries are typically based on the Article.Id. Scegliendo Article.Id come chiave di partizione si ottiene quindi la distribuzione ottimale per l'archiviazione di articoli all'interno di una raccolta di Cosmos DB.Choosing Article.Id as partition the key thus provides the best distribution for storing articles inside an Azure Cosmos DB collection.

class Article 
{ 
    // Unique ID for Article 
    public string Id { get; set; }

    public string PartitionKey 
    { 
        get 
        { 
            return this.Id; 
        } 
    }

    // Author of the article
    public string Author { get; set; }

    // Category/genre of the article
    public string Category { get; set; }

    // Tags associated with the article
    public string[] Tags { get; set; }

    // Title of the article
    public string Title { get; set; }

    //... 
}

Modellazione delle revisioniModeling reviews

Analogamente agli articoli, le revisioni vengono in genere scritte e lette nel contesto dell'articolo.Like articles, reviews are mostly written and read in the context of article. Scegliendo ArticleId come chiave di partizione si ottiene quindi la distribuzione ottimale e l'accesso più efficiente per le revisioni associate all'articolo.Choosing ArticleId as a partition key provides best distribution and efficient access of reviews associated with article.

class Review 
{ 
    // Unique ID for Review 
    public string Id { get; set; }

    // Article Id of the review 
    public string ArticleId { get; set; }

    public string PartitionKey 
    { 
        get 
        { 
            return this.ArticleId; 
        } 
    }

    //Reviewer Id 
    public string UserId { get; set; }
    public string ReviewText { get; set; }

    public int Rating { get; set; } }
}

Metodi per i livelli di accesso ai datiData access layer methods

È possibile esaminare i metodi di accesso ai dati principali da implementare.Now let's look at the main data access methods we need to implement. Ecco l'elenco di metodi necessari per ContentPublishDatabase:Here's the list of methods that the ContentPublishDatabase needs:

class ContentPublishDatabase 
{ 
    public async Task CreateSubscriptionAsync(string userId, string category);

    public async Task<IEnumerable<Notification>> ReadNotificationFeedAsync(string userId);

    public async Task<Article> ReadArticleAsync(string articleId);

    public async Task WriteReviewAsync(string articleId, string userId, string reviewText, int rating);

    public async Task<IEnumerable<Review>> ReadReviewsAsync(string articleId); 
}

Configurazione dell'account Azure Cosmos DBAzure Cosmos DB account configuration

Per assicurare operazioni di lettura e scrittura locali, è necessario partizionare i dati non solo nella chiave di partizione, ma anche in base al modello di accesso geografico nelle aree.To guarantee local reads and writes, we must partition data not just on partition key, but also based on the geographical access pattern into regions. Il modello si basa sulla presenza di un account di database di Azure Cosmos DB con replica geografica per ogni area.The model relies on having a geo-replicated Azure Cosmos DB database account for each region. Ad esempio, con due aree si può ottenere uno scenario come il seguente per le operazioni di scrittura in più aree:For example, with two regions, here's a setup for multi-region writes:

Nome accountAccount Name Area di scritturaWrite Region Area di letturaRead Region
contentpubdatabase-usa.documents.azure.com West US North Europe
contentpubdatabase-europe.documents.azure.com North Europe West US

Il diagramma seguente mostra il modo in cui le operazioni di lettura e scrittura vengono eseguite in un'applicazione tipica con questa configurazione:The following diagram shows how reads and writes are performed in a typical application with this setup:

Architettura multimaster di Azure Cosmos DB

Ecco un frammento di codice che illustra come inizializzare i client in un livello di accesso ai dati in esecuzione nell'area West US.Here is a code snippet showing how to initialize the clients in a DAL running in the West US region.

ConnectionPolicy writeClientPolicy = new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp };
writeClientPolicy.PreferredLocations.Add(LocationNames.WestUS);
writeClientPolicy.PreferredLocations.Add(LocationNames.NorthEurope);

DocumentClient writeClient = new DocumentClient(
    new Uri("https://contentpubdatabase-usa.documents.azure.com"), 
    writeRegionAuthKey,
    writeClientPolicy);

ConnectionPolicy readClientPolicy = new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp };
readClientPolicy.PreferredLocations.Add(LocationNames.NorthEurope);
readClientPolicy.PreferredLocations.Add(LocationNames.WestUS);

DocumentClient readClient = new DocumentClient(
    new Uri("https://contentpubdatabase-europe.documents.azure.com"),
    readRegionAuthKey,
    readClientPolicy);

Con la configurazione precedente, il livello di accesso ai dati può inoltrare tutte le operazioni di scrittura all'account locale in base alla posizione in cui è distribuito.With the preceding setup, the data access layer can forward all writes to the local account based on where it is deployed. Le operazioni di lettura vengono eseguite leggendo da entrambi gli account per ottenere la visualizzazione globale dei dati.Reads are performed by reading from both accounts to get the global view of data. Questo approccio può essere esteso a tutte le aree necessarie.This approach can be extended to as many regions as required. Ad esempio, ecco una configurazione con tre aree geografiche:For example, here's a setup with three geographic regions:

Nome accountAccount Name Area di scritturaWrite Region Area di lettura 1Read Region 1 Area di lettura 2Read Region 2
contentpubdatabase-usa.documents.azure.com West US North Europe Southeast Asia
contentpubdatabase-europe.documents.azure.com North Europe West US Southeast Asia
contentpubdatabase-asia.documents.azure.com Southeast Asia North Europe West US

Implementazione del livello di accesso ai datiData access layer implementation

È ora possibile esaminare l'implementazione del livello di accesso ai dati per un'applicazione con due aree scrivibili.Now let's look at the implementation of the data access layer (DAL) for an application with two writable regions. Il livello di accesso ai dati deve implementare i passaggi seguenti:The DAL must implement the following steps:

  • Creare più istanze di DocumentClient per ogni account.Create multiple instances of DocumentClient for each account. Con due aree, ogni istanza del livello di accesso ai dati ha un valore writeClient e un valore readClient.With two regions, each DAL instance has one writeClient and one readClient.
  • In base all'area di distribuzione dell'applicazione, configurare gli endpoint per writeclient e readClient.Based on the deployed region of the application, configure the endpoints for writeclient and readClient. Ad esempio, il livello di accesso ai dati distribuito in West US usa contentpubdatabase-usa.documents.azure.com per l'esecuzione di operazioni di scrittura.For example, the DAL deployed in West US uses contentpubdatabase-usa.documents.azure.com for performing writes. Il livello di accesso ai dati distribuito in NorthEurope usa contentpubdatabase-europ.documents.azure.com per l'esecuzione di operazioni di scrittura.The DAL deployed in NorthEurope uses contentpubdatabase-europ.documents.azure.com for writes.

Con la configurazione precedente, i metodi di accesso ai dati possono essere implementati.With the preceding setup, the data access methods can be implemented. Le operazioni di scrittura inoltrano la scrittura al writeClient corrispondente.Write operations forward the write to the corresponding writeClient.

public async Task CreateSubscriptionAsync(string userId, string category)
{
    await this.writeClient.CreateDocumentAsync(this.contentCollection, new Subscriptions
    {
        UserId = userId,
        SubscriptionFilter = category
    });
}

public async Task WriteReviewAsync(string articleId, string userId, string reviewText, int rating)
{
    await this.writeClient.CreateDocumentAsync(this.contentCollection, new Review
    {
        UserId = userId,
        ArticleId = articleId,
        ReviewText = reviewText,
        Rating = rating
    });
}

Per le notifiche e le revisioni di lettura, è necessario leggere da entrambe le aree e unire i risultati, come illustrato nel frammento di codice seguente:For reading notifications and reviews, you must read from both regions and union the results as shown in the following snippet:

public async Task<IEnumerable<Notification>> ReadNotificationFeedAsync(string userId)
{
    IDocumentQuery<Notification> writeAccountNotification = (
        from notification in this.writeClient.CreateDocumentQuery<Notification>(this.contentCollection) 
        where notification.UserId == userId 
        select notification).AsDocumentQuery();

    IDocumentQuery<Notification> readAccountNotification = (
        from notification in this.readClient.CreateDocumentQuery<Notification>(this.contentCollection) 
        where notification.UserId == userId 
        select notification).AsDocumentQuery();

    List<Notification> notifications = new List<Notification>();

    while (writeAccountNotification.HasMoreResults || readAccountNotification.HasMoreResults)
    {
        IList<Task<FeedResponse<Notification>>> results = new List<Task<FeedResponse<Notification>>>();

        if (writeAccountNotification.HasMoreResults)
        {
            results.Add(writeAccountNotification.ExecuteNextAsync<Notification>());
        }

        if (readAccountNotification.HasMoreResults)
        {
            results.Add(readAccountNotification.ExecuteNextAsync<Notification>());
        }

        IList<FeedResponse<Notification>> notificationFeedResult = await Task.WhenAll(results);

        foreach (FeedResponse<Notification> feed in notificationFeedResult)
        {
            notifications.AddRange(feed);
        }
    }
    return notifications;
}

public async Task<IEnumerable<Review>> ReadReviewsAsync(string articleId)
{
    IDocumentQuery<Review> writeAccountReviews = (
        from review in this.writeClient.CreateDocumentQuery<Review>(this.contentCollection) 
        where review.ArticleId == articleId 
        select review).AsDocumentQuery();

    IDocumentQuery<Review> readAccountReviews = (
        from review in this.readClient.CreateDocumentQuery<Review>(this.contentCollection) 
        where review.ArticleId == articleId 
        select review).AsDocumentQuery();

    List<Review> reviews = new List<Review>();

    while (writeAccountReviews.HasMoreResults || readAccountReviews.HasMoreResults)
    {
        IList<Task<FeedResponse<Review>>> results = new List<Task<FeedResponse<Review>>>();

        if (writeAccountReviews.HasMoreResults)
        {
            results.Add(writeAccountReviews.ExecuteNextAsync<Review>());
        }

        if (readAccountReviews.HasMoreResults)
        {
            results.Add(readAccountReviews.ExecuteNextAsync<Review>());
        }

        IList<FeedResponse<Review>> notificationFeedResult = await Task.WhenAll(results);

        foreach (FeedResponse<Review> feed in notificationFeedResult)
        {
            reviews.AddRange(feed);
        }
    }

    return reviews;
}

Se si sceglie una chiave di partizione ottimale e un partizionamento basato su account statici, è possibile ottenere operazioni di scrittura e lettura locali in più aree usando Azure Cosmos DB.Thus, by choosing a good partitioning key and static account-based partitioning, you can achieve multi-region local writes and reads using Azure Cosmos DB.

Passaggi successiviNext steps

In questo articolo è stato illustrato come è possibile usare modelli di lettura e scrittura in più aree con distribuzione globale con Cosmos DB usando la pubblicazione di contenuti come scenario di esempio.In this article, we described how you can use globally distributed multi-region read write patterns with Azure Cosmos DB using content publishing as a sample scenario.