Blob Depolama'da eşzamanlılığı yönetme

Modern uygulamalarda genellikle verileri aynı anda görüntüleyen ve güncelleştiren birden çok kullanıcı vardır. Uygulama geliştiricilerin, özellikle birden çok kullanıcının aynı verileri güncelleştirebileceği senaryolar için son kullanıcılarına öngörülebilir bir deneyim sağlama konusunda dikkatli düşünmeleri gerekir. Geliştiricilerin genellikle göz önünde bulundurduğunu üç ana veri eşzamanlılık stratejisi vardır:

  • İyimser eşzamanlılık: Güncelleştirme gerçekleştiren bir uygulama, güncelleştirmesinin bir parçası olarak uygulamanın bu verileri son okumasının ardından verilerin değişip değişmediğini belirler. Örneğin, bir wiki sayfasını görüntüleyen iki kullanıcı bu sayfada bir güncelleştirme yaparsa, wiki platformunun ikinci güncelleştirmenin ilk güncelleştirmenin üzerine yazılmadığından emin olması gerekir. Ayrıca her iki kullanıcının da güncelleştirmelerinin başarılı olup olmadığını anlamasını sağlamalıdır. Bu strateji en sık web uygulamalarında kullanılır.

  • Kötümser eşzamanlılık: Güncelleştirme gerçekleştirmek isteyen bir uygulama, kilit yayımlanana kadar diğer kullanıcıların verileri güncelleştirmesini engelleyen bir nesneye kilitlenir. Örneğin, yalnızca birincil güncelleştirmelerin gerçekleştirildiği bir birincil/ikincil veri çoğaltma senaryosunda, birincil genellikle verileri başka kimsenin güncelleştiremediğinden emin olmak için uzun bir süre boyunca veriler üzerinde özel bir kilit tutar.

  • Son yazan kazanır: Güncelleştirme işlemlerinin önce başka bir uygulamanın verileri okunduktan sonra güncelleştirip güncelleştirmediğini belirlemeden devam etmesine olanak tanıyan bir yaklaşımdır. Bu yaklaşım genellikle veriler aynı anda birden çok kullanıcının aynı verilere erişmeyecek şekilde bölümlendiğinde kullanılır. Ayrıca, kısa süreli veri akışlarının işlendiği durumlarda da yararlı olabilir.

Azure Depolama üç stratejiyi de destekler ancak iyimser ve kötümser eşzamanlılık için tam destek sağlama özelliği ayırt edicidir. Azure Depolama, hizmet bir ekleme veya güncelleştirme işlemi gerçekleştirdikten sonra sonraki okuma veya liste işlemlerinin en son güncelleştirmeyi döndürmesini garanti eden güçlü bir tutarlılık modelini benimseyecek şekilde tasarlanmıştır.

Geliştiriciler, uygun bir eşzamanlılık stratejisi seçmeye ek olarak, bir depolama platformunun değişiklikleri, özellikle de işlemler arasında aynı nesnede yapılan değişiklikleri nasıl yalıttiğinin farkında olmalıdır. Azure Depolama, tek bir bölümdeki yazma işlemleriyle eşzamanlı olarak okuma işlemlerine izin vermek için anlık görüntü yalıtımı kullanır. Anlık görüntü yalıtımı, güncelleştirmeler gerçekleşirken bile tüm okuma işlemlerinin verilerin tutarlı bir anlık görüntüsünü döndürmesini garanti eder.

Bloblara ve kapsayıcılara erişimi yönetmek için iyimser veya kötümser eşzamanlılık modellerini kullanmayı tercih edebilirsiniz. Açıkça bir strateji belirtmezseniz, varsayılan olarak son yazan kazanır.

İyimser eşzamanlılık

Azure Depolama depolanan her nesneye bir tanımlayıcı atar. Bu tanımlayıcı, bir nesne üzerinde her yazma işlemi gerçekleştirildiğinde güncelleştirilir. Tanımlayıcı, HTTP protokolü tarafından tanımlanan ETag üst bilgisinde bir HTTP GET yanıtının parçası olarak istemciye döndürülür.

Güncelleştirme gerçekleştiren bir istemci, bir güncelleştirmenin yalnızca belirli bir koşul karşılandığında gerçekleşmesini sağlamak için özgün ETag'i koşullu üst bilgiyle birlikte gönderebilir. Örneğin, If-Match üst bilgisi belirtilirse, Azure Depolama güncelleştirme isteğinde belirtilen ETag değerinin güncelleştirilmekte olan nesnenin ETag değeriyle aynı olduğunu doğrular. Koşullu üst bilgiler hakkında daha fazla bilgi için bkz . Blob hizmeti işlemleri için koşullu üst bilgileri belirtme.

Bu işlemin ana hattı aşağıdaki gibidir:

  1. Azure Depolama'dan bir blob alın. Yanıt, nesnenin geçerli sürümünü tanımlayan bir HTTP ETag Üst Bilgisi değeri içerir.
  2. Blobu güncelleştirdiğinizde, 1. adımda aldığınız ETag değerini yazma isteğinin If-Match koşullu üst bilgisine ekleyin. Azure Depolama, istekteki ETag değerini blobun geçerli ETag değeriyle karşılaştırır.
  3. Blob'un geçerli ETag değeri, istekte sağlanan If-Match koşullu üst bilgisinde belirtilen ETag değerinden farklıysa, Azure Depolama HTTP durum kodu 412'yi döndürür (Önkoşul Başarısız oldu). Bu hata istemciye, istemci blobu ilk aldığından bu yana başka bir işlemin blobu güncelleştirdiğini gösterir. İstemcinin güncelleştirilmiş içeriği ve özellikleri almak için blobu yeniden getirmesi gerekir.
  4. Blobun geçerli ETag değeri, istekteki If-Match koşullu üst bilgisindeki ETag ile aynı sürümdeyse, Azure Depolama istenen işlemi gerçekleştirir ve blobun geçerli ETag değerini güncelleştirir.

Aşağıdaki kod örneklerinde, bir blob için ETag değerini denetleen yazma isteğinde If-Match koşulu oluşturma işlemi gösterilmektedir. Azure Depolama, blob'un geçerli ETag değerinin istekte sağlanan ETag ile aynı olup olmadığını değerlendirir ve yalnızca iki ETag değeri eşleşirse yazma işlemini gerçekleştirir. Başka bir işlem arada blobu güncelleştirdiyse Azure Depolama bir HTTP 412 (Önkoşul Başarısız) durum iletisi döndürür.

private static async Task DemonstrateOptimisticConcurrencyBlob(BlobClient blobClient)
{
    Console.WriteLine("Demonstrate optimistic concurrency");

    try
    {
        // Download a blob
        Response<BlobDownloadResult> response = await blobClient.DownloadContentAsync();
        BlobDownloadResult downloadResult = response.Value;
        string blobContents = downloadResult.Content.ToString();

        ETag originalETag = downloadResult.Details.ETag;
        Console.WriteLine("Blob ETag = {0}", originalETag);

        // This function simulates an external change to the blob after we've fetched it
        // The external change updates the contents of the blob and the ETag value
        await SimulateExternalBlobChangesAsync(blobClient);

        // Now try to update the blob using the original ETag value
        string blobContentsUpdate2 = $"{blobContents} Update 2. If-Match condition set to original ETag.";

        // Set the If-Match condition to the original ETag
        BlobUploadOptions blobUploadOptions = new()
        {
            Conditions = new BlobRequestConditions()
            {
                IfMatch = originalETag
            }
        };

        // This call should fail with error code 412 (Precondition Failed)
        BlobContentInfo blobContentInfo =
            await blobClient.UploadAsync(BinaryData.FromString(blobContentsUpdate2), blobUploadOptions);
    }
    catch (RequestFailedException e) when (e.Status == (int)HttpStatusCode.PreconditionFailed)
    {
        Console.WriteLine(
            @"Blob's ETag does not match ETag provided. Fetch the blob to get updated contents and properties.");
    }
}

private static async Task SimulateExternalBlobChangesAsync(BlobClient blobClient)
{
    // Simulates an external change to the blob for this example

    // Download a blob
    Response<BlobDownloadResult> response = await blobClient.DownloadContentAsync();
    BlobDownloadResult downloadResult = response.Value;
    string blobContents = downloadResult.Content.ToString();

    // Update the existing block blob contents
    // No ETag condition is provided, so original blob is overwritten and ETag is updated
    string blobContentsUpdate1 = $"{blobContents} Update 1";
    BlobContentInfo blobContentInfo =
        await blobClient.UploadAsync(BinaryData.FromString(blobContentsUpdate1), overwrite: true);
    Console.WriteLine("Blob update. Updated ETag = {0}", blobContentInfo.ETag);
}

Azure Depolama, If-Modified-Since, If-Unmodified-Since ve If-None-Match gibi diğer koşullu üst bilgileri de destekler. Daha fazla bilgi için bkz . Blob Hizmeti İşlemleri için Koşullu Üst Bilgileri Belirtme.

Bloblar için kötümser eşzamanlılık

Blobu özel kullanım için kilitlemek için bu blob üzerinde kiralama alabilirsiniz. Kiralamayı aldığınızda, kiralamanın süresini belirtirsiniz. Sonlu kiralama 15 ila 60 saniye arasında geçerli olabilir. Kiralama da sonsuz olabilir ve bu da özel bir kilittir. Sınırlı bir kirayı uzatmak için yenileyebilir ve bitirdiğinizde kirayı serbest bırakabilirsiniz. Azure Depolama süresi dolduğunda sınırlı kiralamaları otomatik olarak serbest bırakır.

Kiralamalar, özel yazma/paylaşılan okuma işlemleri, özel yazma/özel okuma işlemleri ve paylaşılan yazma/özel okuma işlemleri dahil olmak üzere farklı eşitleme stratejilerinin desteklenmesini sağlar. Kiralama mevcut olduğunda Azure Depolama, kiralama sahibi için yazma işlemlerine özel erişim uygular. Ancak, okuma işlemleri için münhasırlığı sağlamak için geliştiricinin tüm istemci uygulamalarının kira kimliği kullandığından ve aynı anda yalnızca bir istemcinin geçerli bir kira kimliğine sahip olduğundan emin olması gerekir. Paylaşılan okumalarda kira kimliği sonucu içermeyen okuma işlemleri.

Aşağıdaki kod örneklerinde blob üzerinde özel kira alma, kira kimliğini sağlayarak blobun içeriğini güncelleştirme ve ardından kirayı serbest bırakma işlemi gösterilmektedir. Kiralama etkinse ve kiralama kimliği bir yazma isteğinde sağlanmamışsa, yazma işlemi 412 (Önkoşul Başarısız Oldu) hata koduyla başarısız olur.

public static async Task DemonstratePessimisticConcurrencyBlob(BlobClient blobClient)
{
    Console.WriteLine("Demonstrate pessimistic concurrency");

    BlobContainerClient containerClient = blobClient.GetParentBlobContainerClient();
    BlobLeaseClient blobLeaseClient = blobClient.GetBlobLeaseClient();

    try
    {
        // Create the container if it does not exist.
        await containerClient.CreateIfNotExistsAsync();

        // Upload text to a blob.
        string blobContents1 = "First update. Overwrite blob if it exists.";
        byte[] byteArray = Encoding.ASCII.GetBytes(blobContents1);
        using (MemoryStream stream = new MemoryStream(byteArray))
        {
            BlobContentInfo blobContentInfo = await blobClient.UploadAsync(stream, overwrite: true);
        }

        // Acquire a lease on the blob.
        BlobLease blobLease = await blobLeaseClient.AcquireAsync(TimeSpan.FromSeconds(15));
        Console.WriteLine("Blob lease acquired. LeaseId = {0}", blobLease.LeaseId);

        // Set the request condition to include the lease ID.
        BlobUploadOptions blobUploadOptions = new BlobUploadOptions()
        {
            Conditions = new BlobRequestConditions()
            {
                LeaseId = blobLease.LeaseId
            }
        };

        // Write to the blob again, providing the lease ID on the request.
        // The lease ID was provided, so this call should succeed.
        string blobContents2 = "Second update. Lease ID provided on request.";
        byteArray = Encoding.ASCII.GetBytes(blobContents2);

        using (MemoryStream stream = new MemoryStream(byteArray))
        {
            BlobContentInfo blobContentInfo = await blobClient.UploadAsync(stream, blobUploadOptions);
        }

        // This code simulates an update by another client.
        // The lease ID is not provided, so this call fails.
        string blobContents3 = "Third update. No lease ID provided.";
        byteArray = Encoding.ASCII.GetBytes(blobContents3);

        using (MemoryStream stream = new MemoryStream(byteArray))
        {
            // This call should fail with error code 412 (Precondition Failed).
            BlobContentInfo blobContentInfo = await blobClient.UploadAsync(stream);
        }
    }
    catch (RequestFailedException e)
    {
        if (e.Status == (int)HttpStatusCode.PreconditionFailed)
        {
            Console.WriteLine(
                @"Precondition failure as expected. The lease ID was not provided.");
        }
        else
        {
            Console.WriteLine(e.Message);
            throw;
        }
    }
    finally
    {
        await blobLeaseClient.ReleaseAsync();
    }
}

Kapsayıcılar için kötümser eşzamanlılık

Kapsayıcılardaki kiralamalar, özel yazma/paylaşılan okuma, özel yazma/özel okuma ve paylaşılan yazma/özel okuma gibi bloblar için desteklenen eşitleme stratejilerini etkinleştirir. Ancak kapsayıcılar için özel kilit yalnızca silme işlemlerinde zorlanır. Etkin kiralaması olan bir kapsayıcıyı silmek için, istemcinin silme isteğiyle birlikte etkin kira kimliğini içermesi gerekir. Kira kimliği olmadan kiralanan bir kapsayıcıda diğer tüm kapsayıcı işlemleri başarılı olur.

Sonraki adımlar

Kaynaklar

Kullanım dışı bırakılan .NET sürüm 11.x SDK'larını kullanan ilgili kod örnekleri için bkz . .NET sürüm 11.x kullanan kod örnekleri.