مدیریت همزمانی در CosmosDB با ETags

هنگام کار با سیستمها و پایگاههای داده توزیعشده مانند Azure CosmosDB، همزمانی میتواند مشکلی دشوار برای رسیدگی موثر باشد. بدون پادمانهای مناسب، بهروزرسانیهای همزمان دادههای مشابه میتواند منجر به درگیری و خرابی دادهها شود. خوشبختانه CosmosDB مکانیزم داخلی برای مدیریت همزمانی از طریق فراهم می کند تگ های ET (برچسب های نهاد).
در این پست، بررسی خواهیم کرد که ETag ها چیست، چگونه در CosmosDB کار می کنند، و چگونه می توانید از آنها برای حل مشکلات همزمانی در برنامه های خود استفاده کنید.
ETag چیست؟
ETag یک مقدار رشته ای است که به طور خودکار توسط CosmosDB برای هر سند نگهداری می شود. این نشان دهنده نسخه سند در یک نقطه زمانی معین است. هر بار که یک سند اصلاح می شود، مقدار ETag آن تغییر می کند.
آن را به عنوان اثر انگشتی از وضعیت فعلی سند در نظر بگیرید:
- قبل از بروز رسانی: ETag وضعیت سند را قبل از اصلاح نشان می دهد.
- پس از یک به روز رسانی: یک ETag جدید تولید می شود که وضعیت به روز شده را منعکس می کند.
چالش همزمانی
در یک سناریوی معمولی، دو یا چند مشتری ممکن است سعی کنند یک سند را به طور همزمان بخوانند و به روز کنند. بدون مکانیزمی برای مدیریت این بهروزرسانیهای همزمان، تغییرات یک کلاینت ممکن است روی دیگری بازنویسی کند که منجر به به روز رسانی های از دست رفته.
در اینجا یک مثال است:
-
مشتری A یک سند را با ETag می خواند
abc123
. -
مشتری B همان سند را با ETag می خواند
abc123
. - هر دو سرویس گیرنده سند را تغییر می دهند و به روز رسانی های خود را به CosmosDB ارسال می کنند.
بدون بررسی ETag، آخرین به روز رسانی (هر کدام که دیرتر برسد) اولی را بازنویسی می کند و هرگونه تغییر میانی را کنار می گذارد.
چگونه ETag ها همزمانی را حل می کنند
برای رفع این مشکل، CosmosDB به شما اجازه پیاده سازی می دهد کنترل همزمانی خوشبینانه با استفاده از ETags هنگام به روز رسانی یک سند، می توانید مقدار ETag مورد انتظار سند را مشخص کنید. اگر ETag فعلی سند با آنچه در درخواست شما ارائه شده مطابقت نداشته باشد، CosmosDB به روز رسانی را با یک شکست پیش شرط.
گردش کار:
- سند را بخوانید: سند را به همراه ETag فعلی آن واکشی کنید.
- سند را اصلاح کنید: تغییرات خود را به صورت محلی انجام دهید.
- با ETag آپدیت کنید: ETag را به عنوان پیش شرط در درخواست به روز رسانی قرار دهید.
-
CosmosDB اعتبار سنجی می کند:
- اگر ETag مطابقت دارد: به روز رسانی با موفقیت انجام می شود.
- اگر ETag مطابقت نداشته باشد: به روز رسانی با شکست مواجه می شود، که نشان دهنده یک تضاد است.
پیاده سازی در کد
بیایید با استفاده از یک مثال عملی نگاه کنیم Azure CosmosDB SDK برای دات نت:
واکشی سند
var container = cosmosClient.GetContainer("databaseId", "containerId");
// Read the document
var response = await container.ReadItemAsync<dynamic>("documentId", new PartitionKey("partitionKeyValue"));
var document = response.Resource;
// Store the ETag
string etag = response.ETag;
به روز رسانی با ETag
// Modify the document
document["propertyToUpdate"] = "newValue";
// Prepare the request options with ETag
var requestOptions = new ItemRequestOptions
{
IfMatchEtag = etag // Specify the expected ETag
};
try
{
// Attempt the update
var updateResponse = await container.ReplaceItemAsync(document, "documentId", new PartitionKey("partitionKeyValue"), requestOptions);
Console.WriteLine("Update succeeded!");
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.PreconditionFailed)
{
Console.WriteLine("Concurrency conflict detected. Update failed.");
}
سناریوهای کلیدی که در آن ETag ها می درخشند
- جلوگیری از گم شدن به روز رسانی: با تأیید اعتبار ETag قبل از اعمال بهروزرسانی، مطمئن میشوید که هیچ تغییر میانی رونویسی نمیشود.
- حل تعارض: در صورت بروز تداخل، می توانید سند را دوباره واکشی کنید، تغییرات را ادغام کنید و دوباره به روز رسانی را امتحان کنید.
- تغییرات حسابرسی: از ETag ها برای تشخیص اینکه چه زمانی اسناد و توسط چه کسی (در کنار سایر ابرداده ها) اصلاح شده اند، استفاده کنید.
بهترین شیوه ها
- از کلیدهای پارتیشن استفاده کنید: هنگام کار با CosmosDB برای بهینه سازی عملکرد، همیشه کلید پارتیشن صحیح را وارد کنید.
- خرابی های پیش شرط را به خوبی مدیریت کنید: برنامه خود را طوری طراحی کنید که بهروزرسانیها را دوباره امتحان کند یا از کاربران بخواهد تضادها را حل کنند.
- ثبت مقادیر ETag: تاریخچه ای از ETag ها را برای اهداف اشکال زدایی و ممیزی نگهداری کنید.
نتیجه گیری
همزمانی یک چالش رایج در پایگاه های داده توزیع شده است، اما مکانیسم ETag CosmosDB یک راه ساده و موثر برای مدیریت آن ارائه می دهد. با اتخاذ کنترل خوشبینانه همزمانی با ETags، می توانید از یکپارچگی داده های خود محافظت کنید و برنامه های کاربردی انعطاف پذیرتری ایجاد کنید.
مثال عملی
using System;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos;
namespace Infrastructure.CosmosDB
{
public static class CosmosDBConcurrencyWrapper
{
public static async Task<string?> GetItemEtagAsync(string? id, PartitionKey partitionKey, Container container)
{
ArgumentNullException.ThrowIfNull(container, nameof(container));
if (string.IsNullOrEmpty(id))
{
return null;
}
try
{
ItemResponse<dynamic> response = await container.ReadItemAsync<dynamic>(id, partitionKey);
return response.ETag;
}
catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
return null;
}
}
public static async Task<Tuple<ItemResponse<T>, bool>> TryUpsertItemAsync<T>(PartitionKey partitionKey, T item, Container container, string? etag)
{
ArgumentNullException.ThrowIfNull(container, nameof(container));
ArgumentNullException.ThrowIfNull(item, nameof(item));
try
{
ItemResponse<T> response = await container.UpsertItemAsync(item, partitionKey, new ItemRequestOptions { IfMatchEtag = etag });
return new(response, response.StatusCode == HttpStatusCode.OK);
}
catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.PreconditionFailed)
{
throw new ConcurrencyException(ex);
}
}
}
public class ConcurrencyException : Exception
{
public ConcurrencyException()
{
}
public ConcurrencyException(string message)
: base(message)
{
}
public ConcurrencyException(string message, Exception inner)
: base(message, inner)
{
}
public ConcurrencyException(Exception inner)
: base("Concurrency problem detected", inner)
{
}
}
}