Blob depolamada 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ştiricilerinin, ö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, 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 yazmadığı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 çok web uygulamalarında kullanılır.

  • Kötümser eşzamanlılık: Güncelleştirme gerçekleştirmek isteyen bir uygulama, kilit serbest bırakılana kadar diğer kullanıcıların verileri güncelleştirmesini engelleyen bir nesneye kilitlenir. Örneğin, yalnızca birincilin güncelleştirmeleri gerçekleştirdiği bir birincil/ikincil veri çoğaltma senaryosunda, başka kimsenin güncelleştiremediğinden emin olmak için birincil genellikle 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şım. Bu yaklaşım genellikle veriler birden çok kullanıcının aynı verilere aynı anda erişmeyecek şekilde bölümlendiğinde kullanılır. 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 listeleme 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ı nesneye yapılan değişiklikleri nasıl yalıttiğini de bilmeli. 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 yazar 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 http GET yanıtının bir 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 blob alma. 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 blobu ilk kez aldıktan sonra 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 örnekleri, bir blob için ETag değerini denetleen yazma isteğinde If-Match koşulunun nasıl oluşturıldığını gösterir. Azure Depolama, blob'un geçerli ETag değerinin istekte sağlanan ETag ile aynı olup olmadığını değerlendirir ve yazma işlemini yalnızca iki ETag değeri eşleşirse gerçekleştirir. Aradaki blob başka bir işlem tarafından güncelleştirildiyse, 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

Özel kullanım için bir blobu kilitlemek için bu blob üzerinde bir kira alabilirsiniz. Kiralamayı aldığınızda, kiralamanın süresini belirtirsiniz. Sınırlı kiralama 15 ila 60 saniye arasında geçerli olabilir. Kiralama sonsuz da olabilir ve bu da özel bir kilide neden olur. 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.

Kiralar, ö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. Kira mevcut olduğunda, Azure Depolama kira 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 blob 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 hata koduyla başarısız olur (Önkoşul Başarısız oldu).

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 kullanım kilidi yalnızca silme işlemlerinde zorunlu kılınır. Etkin kiralaması olan bir kapsayıcıyı silmek için, istemcinin silme isteğiyle birlikte etkin kira kimliğini içermesi gerekir. Diğer tüm kapsayıcı işlemleri kira kimliği olmadan kiralanmış bir kapsayıcıda başarılı olur.

Sonraki adımlar

Kaynaklar

Kullanım dışı .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.