Gerçek dünyadan bir örnek kullanarak Azure Cosmos DB'de verileri modelleme ve bölümleme

UYGULANANLAR: NOSQL

Bu makale, gerçek dünya veri tasarımı alıştırmasını gerçekleştirmeyi göstermek için veri modelleme, bölümleme ve sağlanan aktarım hızı gibi çeşitli Azure Cosmos DB kavramlarını temel alır.

Genellikle ilişkisel veritabanlarıyla çalışıyorsanız, büyük olasılıkla veri modelini tasarlamaya yönelik alışkanlıklar ve sezgiler oluşturmüstür. Belirli kısıtlamalar ve Azure Cosmos DB'nin benzersiz güçlü yönleri nedeniyle, bu en iyi uygulamaların çoğu iyi çevrilmediğinden sizi en iyi olmayan çözümlere sürükleyebilir. Bu makalenin amacı, öğe modellemeden varlık birlikte bulundurma ve kapsayıcı bölümlemeye kadar Azure Cosmos DB'de gerçek dünya kullanım örneğini modelleme sürecinde size yol göstermektir.

Bu makaledeki kavramları gösteren topluluk tarafından oluşturulan bir kaynak kodunu indirin veya görüntüleyin.

Önemli

Bir topluluk katkıda bulunanı bu kod örneğine katkıda bulundu ve Azure Cosmos DB ekibi bu kodun bakımını desteklemiyor.

Senaryo

Bu alıştırmada kullanıcılarıngönderi oluşturabileceği bir blog platformunun etki alanını göz önünde bulunduracağız. Kullanıcılar ayrıca bu gönderileri beğenebilir ve bu gönderilere yorum ekleyebilir.

İpucu

Bazı sözcükleri italik olarak vurguladık; bu sözcükler, modelimizin manipüle etmek zorunda olacağı "şeylerin" türünü tanımlar.

Belirtimimize daha fazla gereksinim ekleme:

  • Ön sayfada son oluşturulan gönderilerin bir akışı görüntülenir,
  • Bir kullanıcının tüm gönderilerini, gönderinin tüm yorumlarını ve gönderinin tüm beğenilerini getirebiliriz.
  • Gönderiler, yazarlarının kullanıcı adı ve sahip oldukları yorum ve beğenilerin sayısıyla birlikte döndürülür,
  • Açıklamalar ve beğeniler, bunları oluşturan kullanıcıların kullanıcı adıyla da döndürülür,
  • Liste olarak görüntülendiğinde, gönderilerin yalnızca içeriklerinin kesilmiş bir özetini sunmaları gerekir.

Ana erişim desenlerini tanımlama

Başlangıç olarak, çözümümüzün erişim desenlerini tanımlayarak ilk belirtimimize bir yapı vereceğiz. Azure Cosmos DB için bir veri modeli tasarlarken, modelin bu isteklere verimli bir şekilde hizmet ettiğinden emin olmak için modelimizin hangi isteklere hizmet ettiğini anlamak önemlidir.

Sürecin genel olarak daha kolay izlenmesi için, bu farklı istekleri komut veya sorgu olarak kategorilere ayırarak CQRS'den biraz sözcük dağarcığını ödünç alıyoruz. CQRS'de komutlar yazma istekleri (sistemi güncelleştirme amaçları) ve sorgular salt okunur isteklerdir.

Platformumuzun kullanıma sunduğumuz isteklerin listesi aşağıdadır:

  • [C1] Kullanıcı oluşturma/düzenleme
  • [Ç1] Kullanıcı alma
  • [C2] Gönderi oluşturma/düzenleme
  • [Ç2] Gönderi alma
  • [Q3] Kullanıcının gönderilerini kısa formda listeleme
  • [C3] Açıklama oluşturma
  • [Q4] Gönderinin açıklamalarını listeleme
  • [C4] Gönderiyi beğenme
  • [Ç5] Gönderinin beğenilerini listeleme
  • [Q6] Kısa formda (akış) oluşturulan en son x gönderiyi listeleme

Bu aşamada, her varlığın (kullanıcı, gönderi vb.) neler içerdiğinin ayrıntılarını düşünmedik. Bu adım genellikle ilişkisel bir mağazaya karşı tasarım yaparken ilk ele alınanlar arasındadır. Öncelikle bu adımla başlayacağız çünkü bu varlıkların tablolar, sütunlar, yabancı anahtarlar vb. açısından nasıl çevrildiği hakkında bilgi edinmeliyiz. Yazma sırasında herhangi bir şemayı zorlamayan bir belge veritabanıyla ilgili daha az endişeye neden olur.

Erişim desenlerimizi en baştan tanımlamanın önemli olmasının temel nedeni, bu istek listesinin test paketimiz olmasıdır. Veri modelimiz üzerinde her yineleme yaptığımızda isteklerin her birini gözden geçiriyor ve performans ile ölçeklenebilirliğini kontrol ediyoruz. Her modelde kullanılan istek birimlerini hesaplayıp iyileştiriyoruz. Tüm bu modeller varsayılan dizin oluşturma ilkesini kullanır ve ru tüketimini ve gecikme süresini daha da geliştirebilecek belirli özellikleri dizinleyerek bu ilkeyi geçersiz kılabilirsiniz.

V1: İlk sürüm

İki kapsayıcıyla başlayacağız: users ve posts.

Kullanıcılar kapsayıcısı

Bu kapsayıcı yalnızca kullanıcı öğelerini depolar:

{
    "id": "<user-id>",
    "username": "<username>"
}

Bu kapsayıcıyı idile bölümleyeceğiz, bu da kapsayıcı içindeki her mantıksal bölümün yalnızca bir öğe içerdiği anlamına gelir.

Gönderiler kapsayıcısı

Bu kapsayıcı gönderiler, açıklamalar ve beğeniler gibi varlıkları barındırır:

{
    "id": "<post-id>",
    "type": "post",
    "postId": "<post-id>",
    "userId": "<post-author-id>",
    "title": "<post-title>",
    "content": "<post-content>",
    "creationDate": "<post-creation-date>"
}

{
    "id": "<comment-id>",
    "type": "comment",
    "postId": "<post-id>",
    "userId": "<comment-author-id>",
    "content": "<comment-content>",
    "creationDate": "<comment-creation-date>"
}

{
    "id": "<like-id>",
    "type": "like",
    "postId": "<post-id>",
    "userId": "<liker-id>",
    "creationDate": "<like-creation-date>"
}

Bu kapsayıcıyı postIdile bölümleyeceğiz. Bu, kapsayıcıdaki her mantıksal bölümün bir gönderi, o gönderinin tüm açıklamalarını ve bu gönderinin tüm beğenilerini içerdiği anlamına gelir.

Bu kapsayıcının barındırmış olduğu üç varlık türünü ayırt etmek için bu kapsayıcıda depolanan öğelerde bir type özellik kullanıma sunulmuştur.

Ayrıca, ekleme yerine ilgili verilere başvurmayı seçtik (bu kavramlarla ilgili ayrıntılar için bu bölüme bakın):

  • kullanıcının oluşturabileceği gönderilerin üst sınırı yoktur.
  • gönderiler rastgele uzun olabilir,
  • bir gönderinin kaç yorum ve beğeniye sahip olabileceği konusunda üst sınır yoktur.
  • gönderinin kendisini güncelleştirmek zorunda kalmadan gönderiye yorum veya beğeni ekleyebilmek istiyoruz.

Modelimiz ne kadar iyi performans gösterir?

Şimdi ilk sürümümüzün performansını ve ölçeklenebilirliğini değerlendirme zamanı geldi. Daha önce tanımlanan isteklerin her biri için gecikme süresini ve kaç istek birimi tükettiği ölçüyoruz. Bu ölçüm, kullanıcı başına 5 ila 50 gönderi ve gönderi başına 25 yorum ve 100 beğeni içeren 100.000 kullanıcı içeren sahte bir veri kümesinde gerçekleştirilir.

[C1] Kullanıcı oluşturma/düzenleme

Kapsayıcıda users yalnızca bir öğe oluşturduğumuz veya güncelleştirdiğimiz için bu isteğin uygulanması kolaydır. İstekler, bölüm anahtarı sayesinde tüm bölümlere id düzgün bir şekilde yayılır.

Kullanıcıların kapsayıcısına tek bir öğe yazma diyagramı.

Gecikme süresi RU ücreti Performans
7 Bayan 5.71 RU

[Ç1] Kullanıcı alma

Kullanıcı alma işlemi, kapsayıcıdan users ilgili öğeyi okuyarak yapılır.

Kullanıcıların kapsayıcısından tek bir öğeyi alma diyagramı.

Gecikme süresi RU ücreti Performans
2 Bayan 1 RU

[C2] Gönderi oluşturma/düzenleme

[C1] ile benzer şekilde kapsayıcıya posts yazmamız gerekir.

Post kapsayıcısına tek bir gönderi öğesi yazma diyagramı.

Gecikme süresi RU ücreti Performans
9 Bayan 8.76 RU

[Ç2] Gönderi alma

Kapsayıcıdan posts ilgili belgeyi alarak başlayacağız. Ancak bu yeterli değildir, belirtimimize göre gönderinin yazarının kullanıcı adını, yorum sayısını ve gönderinin beğeni sayılarını da toplamamız gerekir. Listelenen toplamalar için 3 SQL sorgusunun daha verilmesi gerekir.

Gönderi alma ve ek verileri toplama diyagramı.

Daha fazla sorgunun her biri ilgili kapsayıcısının bölüm anahtarına filtre ekler. Bu da tam olarak performansı ve ölçeklenebilirliği en üst düzeye çıkarmak istediğimiz durumdur. Ancak sonunda tek bir gönderi döndürmek için dört işlem yapmamız gerekir, bu nedenle bunu bir sonraki yinelemede iyileştireceğiz.

Gecikme süresi RU ücreti Performans
9 Bayan 19.54 RU

[Q3] Kullanıcının gönderilerini kısa formda listeleme

İlk olarak, istenen gönderileri belirli bir kullanıcıya karşılık gelen gönderileri getiren bir SQL sorgusuyla amalıyız. Ancak yazarın kullanıcı adını ve açıklama ve beğeni sayısını toplamak için daha fazla sorgu yayınlamamız gerekir.

Bir kullanıcı için tüm gönderileri alma ve ek verilerini toplama diyagramı.

Bu uygulama birçok dezavantaj sunar:

  • açıklama ve beğeni sayılarını toplayarak sorguların ilk sorgu tarafından döndürülen her gönderi için verilmesi gerekir.
  • ana sorgu kapsayıcının bölüm anahtarına posts göre filtre uygulamaz ve kapsayıcıda bir yayma ve bölüm taramasına yol açar.
Gecikme süresi RU ücreti Performans
130 Bayan 619.41 RU

[C3] Açıklama oluşturma

Kapsayıcıya karşılık gelen öğe posts yazılarak bir açıklama oluşturulur.

Gönderiler kapsayıcısına tek bir açıklama öğesi yazma diyagramı.

Gecikme süresi RU ücreti Performans
7 Bayan 8.57 RU

[Q4] Gönderinin açıklamalarını listeleme

Bu gönderinin tüm açıklamalarını getiren bir sorguyla başlayacağız ve bir kez daha her açıklama için kullanıcı adlarını ayrı olarak toplamamız gerekiyor.

Bir gönderi için tüm açıklamaları alma ve ek verilerini toplama diyagramı.

Ana sorgu kapsayıcının bölüm anahtarına göre filtre uygulasa da, kullanıcı adlarının ayrı olarak toplanıyor olması genel performansı kötüleştirir. Bunu daha sonra geliştireceğiz.

Gecikme süresi RU ücreti Performans
23 Bayan 27.72 RU

[C4] Gönderiyi beğenme

[C3] gibi kapsayıcıda ilgili öğeyi posts de oluştururuz.

Post kapsayıcısına tek bir (beğen) öğe yazma diyagramı.

Gecikme süresi RU ücreti Performans
6 Bayan 7.05 RU

[Ç5] Gönderinin beğenilerini listeleme

[Q4] gibi bu gönderinin beğenilerini sorgular ve kullanıcı adlarını toplarız.

Bir gönderi için tüm beğenileri alma ve ek verilerini toplama diyagramı.

Gecikme süresi RU ücreti Performans
59 Bayan 58.92 RU

[Q6] Kısa formda (akış) oluşturulan en son x gönderiyi listeleme

Kapsayıcıyı azalan oluşturma tarihine göre sıralayarak posts en son gönderileri getiriyoruz, ardından gönderilerin her biri için kullanıcı adlarını ve açıklama ve beğeni sayılarını bir araya getiriyoruz.

En son gönderileri alma ve ek verilerini toplama diyagramı.

Bir kez daha, ilk sorgumuz kapsayıcının bölüm anahtarına posts göre filtre uygulamaz ve bu da yüksek maliyetli bir yayma tetikler. Daha büyük bir sonuç kümesini hedeflediğimiz ve sonuçları istek birimleri açısından daha pahalı hale getiren bir ORDER BY yan tümcesiyle sıraladığımız için bu daha da kötüdür.

Gecikme süresi RU ücreti Performans
306 Bayan 2063.54 RU

V1'in performansını yansıtma

Önceki bölümde karşılaştığımız performans sorunlarına baktığımızda iki ana sorun sınıfını belirleyebiliriz:

  • bazı istekler, döndürmemiz gereken tüm verileri toplamak için birden çok sorgunun verilmesini gerektirir,
  • bazı sorgular hedefledikleri kapsayıcıların bölüm anahtarına göre filtre uygulamaz ve bu da ölçeklenebilirliğimizi engelleyen bir yaymaya neden olur.

İlk sorundan başlayarak bu sorunların her birini çözelim.

V2: Okuma sorgularını iyileştirmek için normalleştirmeyi kaldırmaya giriş

Bazı durumlarda daha fazla istek göndermemizin nedeni, ilk isteğin sonuçlarının döndürmemiz gereken tüm verileri içermemesidir. Verileri normalden çıkarma, Azure Cosmos DB gibi ilişkisel olmayan bir veri deposuyla çalışırken veri kümemiz genelinde bu tür bir sorunu çözer.

Örneğimizde, gönderi öğelerini gönderinin yazarının kullanıcı adını, açıklama sayısını ve beğeni sayısını eklemek için değiştiriyoruz:

{
    "id": "<post-id>",
    "type": "post",
    "postId": "<post-id>",
    "userId": "<post-author-id>",
    "userUsername": "<post-author-username>",
    "title": "<post-title>",
    "content": "<post-content>",
    "commentCount": <count-of-comments>,
    "likeCount": <count-of-likes>,
    "creationDate": "<post-creation-date>"
}

Ayrıca açıklamayı ve beğen öğelerini değiştirerek bunları oluşturan kullanıcının kullanıcı adını ekleriz:

{
    "id": "<comment-id>",
    "type": "comment",
    "postId": "<post-id>",
    "userId": "<comment-author-id>",
    "userUsername": "<comment-author-username>",
    "content": "<comment-content>",
    "creationDate": "<comment-creation-date>"
}

{
    "id": "<like-id>",
    "type": "like",
    "postId": "<post-id>",
    "userId": "<liker-id>",
    "userUsername": "<liker-username>",
    "creationDate": "<like-creation-date>"
}

Açıklamayı ve beğenme sayılarını normalleştirme

Elde etmek istediğimiz şey, her açıklama veya benzerini eklediğimizde, ilgili gönderideki veya likeCount değerini de artırmamızdırcommentCount. Kapsayıcımızı posts bölümledikçepostId, yeni öğe (açıklama veya beğenme) ve karşılık gelen gönderi aynı mantıksal bölümde yer alır. Sonuç olarak, bu işlemi gerçekleştirmek için bir saklı yordam kullanabiliriz.

Bir açıklama oluşturduğunuzda ([C3]), kapsayıcıya posts yeni bir öğe eklemek yerine bu kapsayıcıda aşağıdaki saklı yordamı çağırırız:

function createComment(postId, comment) {
  var collection = getContext().getCollection();

  collection.readDocument(
    `${collection.getAltLink()}/docs/${postId}`,
    function (err, post) {
      if (err) throw err;

      post.commentCount++;
      collection.replaceDocument(
        post._self,
        post,
        function (err) {
          if (err) throw err;

          comment.postId = postId;
          collection.createDocument(
            collection.getSelfLink(),
            comment
          );
        }
      );
    })
}

Bu saklı yordam, gönderinin kimliğini ve yeni açıklamanın gövdesini parametre olarak alır ve ardından:

  • gönderiyi alır
  • commentCount
  • gönderinin yerini alır
  • yeni açıklamayı ekler

Saklı yordamlar atomik işlemler olarak yürütüldükçe, değeri commentCount ve gerçek açıklama sayısı her zaman eşitlenmiş durumda kalır.

Değerini artırmak likeCountiçin yeni beğeniler eklerken benzer bir saklı yordam çağırdığımız açıktır.

Kullanıcı adlarını normalleştirme

Kullanıcılar yalnızca farklı bölümlerde değil, farklı bir kapsayıcıda da durduğu için kullanıcı adları farklı bir yaklaşım gerektirir. Bölümler ve kapsayıcılar arasında verileri normalleştirmemiz gerektiğinde kaynak kapsayıcının değişiklik akışını kullanabiliriz.

Örneğimizde, kullanıcılar kullanıcı adlarını güncelleştirdiğinde tepki vermek için kapsayıcının users değişiklik akışını kullanırız. Bu durumda, kapsayıcıda posts başka bir saklı yordamı çağırarak değişikliği yayacağız:

Kullanıcı adlarını post kapsayıcısına normalleştirme diyagramı.

function updateUsernames(userId, username) {
  var collection = getContext().getCollection();
  
  collection.queryDocuments(
    collection.getSelfLink(),
    `SELECT * FROM p WHERE p.userId = '${userId}'`,
    function (err, results) {
      if (err) throw err;

      for (var i in results) {
        var doc = results[i];
        doc.userUsername = username;

        collection.upsertDocument(
          collection.getSelfLink(),
          doc);
      }
    });
}

Bu saklı yordam, kullanıcının kimliğini ve kullanıcının yeni kullanıcı adını parametre olarak alır, ardından:

  • ile eşleşen userId tüm öğeleri getirir (gönderiler, açıklamalar veya beğeniler olabilir)
  • bu öğelerin her biri için
    • şunun yerini alır: userUsername
    • öğeyi değiştirir

Önemli

Bu saklı yordamın kapsayıcının her bölümünde posts yürütülmesini gerektirdiğinden bu işlem maliyetlidir. Kullanıcıların çoğunun kayıt sırasında uygun bir kullanıcı adı seçtiğini ve bunu asla değiştirmeyeceğini varsayarız, bu nedenle bu güncelleştirme çok nadir çalışır.

V2'nin performans kazanımları nelerdir?

V2'nin bazı performans kazançlarından bahsedelim.

[Ç2] Gönderi alma

Artık normalleştirmemiz uygulandığına göre, bu isteği işlemek için yalnızca tek bir öğe getirmemiz gerekir.

Normalleştirilmiş gönderiler kapsayıcısından tek bir öğeyi alma diyagramı.

Gecikme süresi RU ücreti Performans
2 Bayan 1 RU

[Q4] Gönderinin açıklamalarını listeleme

Burada da kullanıcı adlarını getiren ek istekleri yedekleyebilir ve bölüm anahtarına filtre ekleyen tek bir sorguyla sonuçlanabilir.

Normalleştirilmiş bir gönderi için tüm açıklamaları alma diyagramı.

Gecikme süresi RU ücreti Performans
4 Bayan 7.72 RU

[Ç5] Gönderinin beğenilerini listeleme

Beğenileri listelerken de aynı durum.

Normalleştirilmiş bir gönderi için tüm beğenileri alma diyagramı.

Gecikme süresi RU ücreti Performans
4 Bayan 8.92 RU

V3: Tüm isteklerin ölçeklenebilir olduğundan emin olun

Genel performans geliştirmelerimize bakarken henüz tam olarak iyileştirilmemiş iki istek var. Bu istekler [Q3] ve [Q6] istekleridir. Bunlar, hedefledikleri kapsayıcıların bölüm anahtarına göre filtrelemeyen sorgular içeren isteklerdir.

[Q3] Kullanıcının gönderilerini kısa formda listeleme

Bu istek, V2'de sunulan ve daha fazla sorguyu yedekleyen geliştirmelerden zaten yararlanır.

Kullanıcının normalleştirilmiş olmayan gönderilerini kısa biçimde listeleme sorgusunu gösteren diyagram.

Ancak kalan sorgu yine de kapsayıcının bölüm anahtarına posts filtre uygulamaz.

Bu durumu düşünmenin yolu basittir:

  1. Belirli bir kullanıcı için tüm gönderileri getirmek istediğimiz için bu isteğin userId filtrelemesi gerekir.
  2. Kapsayıcıda yürütülür posts ve bölümleme özelliği olmadığından userId iyi performans göstermez.
  3. Açıkça belirterek, ile userIdbölümlenmiş bir kapsayıcıda bu isteği yürüterek performans sorunumuzu çözebiliriz.
  4. Zaten böyle bir kapsayıcımız olduğu ortaya çıktı: users kapsayıcı!

Bu nedenle, tüm gönderileri kapsayıcıya çoğaltarak ikinci bir normalleştirme düzeyi getiririz users . Bunu yaparak, gönderilerimizin yalnızca farklı bir boyut boyunca bölümlenmiş bir kopyasını etkili bir şekilde elde ederiz ve bu da onların userIdtarafından alınması için daha verimli olmasını sağlar.

Kapsayıcı users artık iki tür öğe içeriyor:

{
    "id": "<user-id>",
    "type": "user",
    "userId": "<user-id>",
    "username": "<username>"
}

{
    "id": "<post-id>",
    "type": "post",
    "postId": "<post-id>",
    "userId": "<post-author-id>",
    "userUsername": "<post-author-username>",
    "title": "<post-title>",
    "content": "<post-content>",
    "commentCount": <count-of-comments>,
    "likeCount": <count-of-likes>,
    "creationDate": "<post-creation-date>"
}

Bu örnekte:

  • Kullanıcı öğesinde kullanıcıları gönderilerden ayırmak için bir type alan kullanıma sunulmuştur.
  • Ayrıca kullanıcı öğesinde, alanıyla id yedekli olan ancak kapsayıcı artık ile bölümlendiğinden userIdusers (daha önce olduğu gibi değilid) gerekli olan bir userId alan ekledik

Bu normalleştirmeyi gerçekleştirmek için değişiklik akışını bir kez daha kullanırız. Bu kez kapsayıcıya yeni veya güncelleştirilmiş herhangi bir gönderi göndermek için kapsayıcının değişiklik akışına postsusers tepki gösteriyoruz. Gönderileri listelemek için içeriklerinin tamamının döndürülmesi gerekmediğinden, bu süreçte bunları kesebiliriz.

Kullanıcıların kapsayıcısına gönderileri normalden çıkarma diyagramı.

Artık sorgumuzu kapsayıcının users bölüm anahtarına göre filtreleyerek kapsayıcıya yönlendirebiliriz.

Normalleştirilmiş olmayan bir kullanıcının tüm gönderilerini alma diyagramı.

Gecikme süresi RU ücreti Performans
4 Bayan 6.46 RU

[Q6] Kısa formda (akış) oluşturulan en son x gönderiyi listeleme

Burada benzer bir durumla ilgilenmemiz gerekiyor: V2'de tanıtılan normal dışı bırakma işlemiyle gereksiz bırakılan sorguların sayısı azalsa bile, kalan sorgu kapsayıcının bölüm anahtarına filtre uygulamaz:

Kısa formda oluşturulan en son x gönderiyi listeleme sorgusunu gösteren diyagram.

Aynı yaklaşımı izleyerek bu isteğin performansını ve ölçeklenebilirliğini en üst düzeye çıkarmak yalnızca bir bölüme isabet eder. Yalnızca tek bir bölüme isabet etmek mümkündür çünkü yalnızca sınırlı sayıda öğe döndürmemiz gerekir. Blog platformumuzun giriş sayfasını doldurmak için veri kümesinin tamamında sayfalandırmaya gerek kalmadan en son 100 gönderiyi almalıyız.

Bu nedenle, bu son isteği iyileştirmek için tasarımımıza tamamen bu isteğe hizmet etmeye adanmış üçüncü bir kapsayıcı tanıtıyoruz. Bu yeni feed kapsayıcıya gönderilerimizi normalden çıkarıyoruz:

{
    "id": "<post-id>",
    "type": "post",
    "postId": "<post-id>",
    "userId": "<post-author-id>",
    "userUsername": "<post-author-username>",
    "title": "<post-title>",
    "content": "<post-content>",
    "commentCount": <count-of-comments>,
    "likeCount": <count-of-likes>,
    "creationDate": "<post-creation-date>"
}

alanı type , her zaman post öğelerimizde olan bu kapsayıcıyı bölümler. Bunu yapmak, bu kapsayıcıdaki tüm öğelerin aynı bölümde yer almalarını sağlar.

Normalleştirmeyi azaltmak için, gönderileri bu yeni kapsayıcıya göndermek için daha önce sunduğumuz değişiklik akışı işlem hattına bağlanmamız gerekir. Aklınızda bulundurmanız gereken önemli noktalardan biri, yalnızca en son 100 gönderiyi depolamamız gerektiğidir; aksi takdirde, kapsayıcının içeriği bir bölümün maksimum boyutunu aşabilir. Bu sınırlama, kapsayıcıya her belge eklendiğinde bir son tetikleyici çağrılarak uygulanabilir:

Gönderileri akış kapsayıcısına normalden çıkarma diyagramı.

Koleksiyonu kesen son tetikleyicinin gövdesi aşağıdadır:

function truncateFeed() {
  const maxDocs = 100;
  var context = getContext();
  var collection = context.getCollection();

  collection.queryDocuments(
    collection.getSelfLink(),
    "SELECT VALUE COUNT(1) FROM f",
    function (err, results) {
      if (err) throw err;

      processCountResults(results);
    });

  function processCountResults(results) {
    // + 1 because the query didn't count the newly inserted doc
    if ((results[0] + 1) > maxDocs) {
      var docsToRemove = results[0] + 1 - maxDocs;
      collection.queryDocuments(
        collection.getSelfLink(),
        `SELECT TOP ${docsToRemove} * FROM f ORDER BY f.creationDate`,
        function (err, results) {
          if (err) throw err;

          processDocsToRemove(results, 0);
        });
    }
  }

  function processDocsToRemove(results, index) {
    var doc = results[index];
    if (doc) {
      collection.deleteDocument(
        doc._self,
        function (err) {
          if (err) throw err;

          processDocsToRemove(results, index + 1);
        });
    }
  }
}

Son adım sorgumuzu yeni feed kapsayıcımıza yeniden yönlendirmektir:

En son gönderileri alma diyagramı.

Gecikme süresi RU ücreti Performans
9 Bayan 16.97 RU

Sonuç

Şimdi tasarımımızın farklı sürümleri üzerinde sunduğumuz genel performans ve ölçeklenebilirlik iyileştirmelerine göz atalım.

V1 V2 V3
[C1] 7 ms / 5.71 RU 7 ms / 5.71 RU 7 ms / 5.71 RU
[Ç1] 2 ms / 1 RU 2 ms / 1 RU 2 ms / 1 RU
[C2] 9 ms / 8.76 RU 9 ms / 8.76 RU 9 ms / 8.76 RU
[Ç2] 9 ms / 19.54 RU 2 ms / 1 RU 2 ms / 1 RU
[Q3] 130 ms / 619.41 RU 28 ms / 201.54 RU 4 ms / 6.46 RU
[C3] 7 ms / 8.57 RU 7 ms / 15.27 RU 7 ms / 15.27 RU
[Q4] 23 ms / 27.72 RU 4 ms / 7.72 RU 4 ms / 7.72 RU
[C4] 6 ms / 7.05 RU 7 ms / 14.67 RU 7 ms / 14.67 RU
[Q5] 59 ms / 58.92 RU 4 ms / 8.92 RU 4 ms / 8.92 RU
[Q6] 306 ms / 2063.54 RU 83 ms / 532.33 RU 9 ms / 16.97 RU

Yoğun okuma içeren senaryoları iyileştirdik

Yazma istekleri (komutlar) pahasına okuma isteklerinin (sorguların) performansını artırmaya odaklanmış olduğumuzu fark etmiş olabilirsiniz. Çoğu durumda, yazma işlemleri artık değişiklik akışları aracılığıyla sonraki normalleştirmeyi tetikler ve bu da işlem açısından daha pahalı ve gerçekleştirilmesi daha uzun sürer.

Bir bloglama platformunun (çoğu sosyal uygulama gibi) okuma performansına odaklanmasını haklı çıkarıyoruz. Yoğun okuma içeren bir iş yükü, hizmet vermesi gereken okuma isteği miktarının genellikle yazma isteği sayısından daha yüksek siparişler olduğunu gösterir. Bu nedenle, okuma isteklerinin daha ucuz ve daha iyi performans göstermesini sağlamak için yazma isteklerinin yürütülmesini daha pahalı hale getirmek mantıklıdır.

Yaptığımız en aşırı iyileştirmeye bakarsak [Q6] 2000'den fazla RU'dan yalnızca 17 RU'ya geçti; Bunu, gönderileri öğe başına yaklaşık 10 RU'lık bir maliyetle normalleştirerek başardık. Gönderilerin oluşturulmasından veya güncelleştirilmesinden çok daha fazla akış isteğinde bulunacağımızdan, genel tasarruf dikkate alındığında bu normal dışılaştırmanın maliyeti göz ardı edilebilir.

Normalleştirme artımlı olarak uygulanabilir

Bu makalede incelediğimiz ölçeklenebilirlik geliştirmeleri, verilerin veri kümesi genelinde normal dışılaştırılmasını ve çoğaltılmasını içerir. Bu iyileştirmelerin 1. günde yapılması gerekmediği belirtilmelidir. Bölüm anahtarlarına filtre uygulayan sorgular büyük ölçekte daha iyi performans gösterir, ancak nadiren veya sınırlı bir veri kümesine karşı çağrılırlarsa bölümler arası sorgular kabul edilebilir. Yalnızca bir prototip oluşturuyorsanız veya küçük ve denetimli bir kullanıcı tabanına sahip bir ürün piyasaya sürülüyorsanız, büyük olasılıkla bu iyileştirmeleri daha sonra kullanıma sunabilirsiniz. O zaman önemli olan modelinizin performansını izlemektir . Böylece bunları ne zaman ve ne zaman getirebileceğinize karar verebilirsiniz.

Güncelleştirmeleri diğer kapsayıcılara dağıtmak için kullandığımız değişiklik akışı, tüm bu güncelleştirmeleri kalıcı olarak depolar. Bu kalıcılık, sisteminizde zaten çok fazla veri olsa bile kapsayıcı ve bootstrap normalleştirilmiş görünümler tek seferlik bir yakalama işlemi olarak oluşturulduktan sonra tüm güncelleştirmelerin istenmesini mümkün kılar.

Sonraki adımlar

Pratik veri modellemeye ve bölümlemeye giriş yaptıktan sonra, ele aldığımız kavramları gözden geçirmek için aşağıdaki makaleleri gözden geçirmek isteyebilirsiniz: