Mengelola kebijakan resolusi konflik di Azure Cosmos DB
BERLAKU UNTUK: NoSQL
Dengan penulisan multi-wilayah, ketika beberapa klien menulis ke item yang sama, konflik bisa saja terjadi. Anda dapat menyelesaikan konflik dengan menggunakan kebijakan penyelesaian konflik yang berbeda saat konflik terjadi. Artikel ini menjelaskan cara mengelola kebijakan resolusi konflik.
Tip
Kebijakan penyelesaian konflik hanya dapat ditentukan pada waktu pembuatan kontainer dan tidak dapat diubah setelah pembuatan kontainer.
Membuat kebijakan resolusi konflik dengan metode penulis-terakhir-menang
Sampel ini menunjukkan cara menyiapkan kontainer dengan kebijakan resolusi konflik penulis-terakhir-menang. Jalur default untuk lpenulis-terakhir-menang adalah bidang tanda waktu atau properti _ts
. Untuk API untuk NoSQL, ini juga dapat diatur ke jalur yang ditentukan pengguna dengan jenis numerik. Dalam konflik, nilai tertinggi menang. Jika jalur tidak diatur atau tidak valid, jalur tersebut default ke_ts
. Konflik yang diselesaikan dengan kebijakan ini tidak muncul di umpan konflik. Kebijakan ini dapat digunakan oleh semua API.
.NET SDK
DocumentCollection lwwCollection = await createClient.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(this.databaseName), new DocumentCollection
{
Id = this.lwwCollectionName,
ConflictResolutionPolicy = new ConflictResolutionPolicy
{
Mode = ConflictResolutionMode.LastWriterWins,
ConflictResolutionPath = "/myCustomId",
},
});
Java V4 SDK
Java SDK V4 (Maven com.azure::azure-cosmos) API Asinkron
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createLastWriterWinsPolicy("/myCustomId");
CosmosContainerProperties containerProperties = new CosmosContainerProperties(container_id, partition_key);
containerProperties.setConflictResolutionPolicy(policy);
/* ...other container config... */
database.createContainerIfNotExists(containerProperties).block();
Java V2 SDK
Async Java V2 SDK (Maven com.microsoft.azure::azure-cosmosdb)
DocumentCollection collection = new DocumentCollection();
collection.setId(id);
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createLastWriterWinsPolicy("/myCustomId");
collection.setConflictResolutionPolicy(policy);
DocumentCollection createdCollection = client.createCollection(databaseUri, collection, null).toBlocking().value();
Node.js/JavaScript/TypeScript SDK
const database = client.database(this.databaseName);
const { container: lwwContainer } = await database.containers.createIfNotExists(
{
id: this.lwwContainerName,
conflictResolutionPolicy: {
mode: "LastWriterWins",
conflictResolutionPath: "/myCustomId"
}
}
);
Python SDK
database = client.get_database_client(database=database_id)
lww_conflict_resolution_policy = {'mode': 'LastWriterWins', 'conflictResolutionPath': '/regionId'}
lww_container = database.create_container(id=lww_container_id, partition_key=PartitionKey(path="/id"),
conflict_resolution_policy=lww_conflict_resolution_policy)
Membuat kebijakan resolusi konflik kustom menggunakan prosedur tersimpan
Sampel ini menunjukkan cara menyiapkan kontainer dengan kebijakan resolusi konflik penulis-terakhir-menang. Kebijakan ini menggunakan logika dalam prosedur tersimpan untuk mengatasi konflik. Jika prosedur tersimpan ditunjuk untuk mengatasi konflik, konflik tidak akan muncul di umpan konflik kecuali ada kesalahan dalam prosedur tersimpan yang ditunjuk.
Setelah kebijakan dibuat dengan kontainer, Anda perlu membuat prosedur tersimpan. Sampel .NET SDK di bawah ini menunjukkan contoh alur kerja ini. Kebijakan ini hanya didukung di API untuk NoSQL.
Contoh prosedur tersimpan untuk resolusi konflik kustom
Resolusi konflik kustom dengan prosedur tersimpan harus diimplementasikan menggunakan tanda tangan fungsi yang ditunjukkan di bawah ini. Nama fungsi tidak perlu cocok dengan nama yang digunakan saat mendaftarkan prosedur tersimpan dengan kontainer, tetapi memang menyederhanakan penamaan. Berikut adalah deskripsi parameter yang harus diimplementasikan untuk prosedur tersimpan ini.
- incomingItem: Item yang dimasukkan atau diperbarui dalam penerapan yang menghasilkan konflik. Null untuk menghapus operasi.
- existingItem: Item yang saat ini diterapkan. Nilai ini non-null dalam pembaruan dan null untuk sisipan atau menghapus.
- isTombstone: Boolean menunjukkan apakah incomingItem bertentangan dengan item yang dihapus sebelumnya. Jika benar, existingItem juga null.
- conflictingItems: Array versi penerapan dari semua item dalam kontainer yang bertentangan dengan incomingItem pada ID atau properti indeks unik lainnya.
Penting
Sama seperti prosedur tersimpan, prosedur penyelesaian konflik kustom dapat mengakses data apa pun dengan kunci partisi yang sama dan dapat melakukan operasi sisipkan, perbarui, atau hapus untuk mengatasi konflik.
Contoh prosedur tersimpan ini menyelesaikan konflik dengan memilih nilai terendah dari jalur /myCustomId
.
function resolver(incomingItem, existingItem, isTombstone, conflictingItems) {
var collection = getContext().getCollection();
if (!incomingItem) {
if (existingItem) {
collection.deleteDocument(existingItem._self, {}, function (err, responseOptions) {
if (err) throw err;
});
}
} else if (isTombstone) {
// delete always wins.
} else {
if (existingItem) {
if (incomingItem.myCustomId > existingItem.myCustomId) {
return; // existing item wins
}
}
var i;
for (i = 0; i < conflictingItems.length; i++) {
if (incomingItem.myCustomId > conflictingItems[i].myCustomId) {
return; // existing conflict item wins
}
}
// incoming item wins - clear conflicts and replace existing with incoming.
tryDelete(conflictingItems, incomingItem, existingItem);
}
function tryDelete(documents, incoming, existing) {
if (documents.length > 0) {
collection.deleteDocument(documents[0]._self, {}, function (err, responseOptions) {
if (err) throw err;
documents.shift();
tryDelete(documents, incoming, existing);
});
} else if (existing) {
collection.replaceDocument(existing._self, incoming,
function (err, documentCreated) {
if (err) throw err;
});
} else {
collection.createDocument(collection.getSelfLink(), incoming,
function (err, documentCreated) {
if (err) throw err;
});
}
}
}
.NET SDK
DocumentCollection udpCollection = await createClient.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(this.databaseName), new DocumentCollection
{
Id = this.udpCollectionName,
ConflictResolutionPolicy = new ConflictResolutionPolicy
{
Mode = ConflictResolutionMode.Custom,
ConflictResolutionProcedure = string.Format("dbs/{0}/colls/{1}/sprocs/{2}", this.databaseName, this.udpCollectionName, "resolver"),
},
});
//Create the stored procedure
await clients[0].CreateStoredProcedureAsync(
UriFactory.CreateStoredProcedureUri(this.databaseName, this.udpCollectionName, "resolver"), new StoredProcedure
{
Id = "resolver",
Body = File.ReadAllText(@"resolver.js")
});
Java V4 SDK
Java SDK V4 (Maven com.azure::azure-cosmos) API Asinkron
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy("resolver");
CosmosContainerProperties containerProperties = new CosmosContainerProperties(container_id, partition_key);
containerProperties.setConflictResolutionPolicy(policy);
/* ...other container config... */
database.createContainerIfNotExists(containerProperties).block();
Java V2 SDK
Async Java V2 SDK (Maven com.microsoft.azure::azure-cosmosdb)
DocumentCollection collection = new DocumentCollection();
collection.setId(id);
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy("resolver");
collection.setConflictResolutionPolicy(policy);
DocumentCollection createdCollection = client.createCollection(databaseUri, collection, null).toBlocking().value();
Setelah kontainer Anda dibuat, Anda harus membuat prosedur tersimpan resolver
.
Node.js/JavaScript/TypeScript SDK
const database = client.database(this.databaseName);
const { container: udpContainer } = await database.containers.createIfNotExists(
{
id: this.udpContainerName,
conflictResolutionPolicy: {
mode: "Custom",
conflictResolutionProcedure: `dbs/${this.databaseName}/colls/${
this.udpContainerName
}/sprocs/resolver`
}
}
);
Setelah kontainer Anda dibuat, Anda harus membuat prosedur tersimpan resolver
.
Python SDK
database = client.get_database_client(database=database_id)
udp_custom_resolution_policy = {'mode': 'Custom' }
udp_container = database.create_container(id=udp_container_id, partition_key=PartitionKey(path="/id"),
conflict_resolution_policy=udp_custom_resolution_policy)
Setelah kontainer Anda dibuat, Anda harus membuat prosedur tersimpan resolver
.
Membuat kebijakan resolusi konflik kustom
Sampel ini menunjukkan cara menyiapkan kontainer dengan kebijakan resolusi konflik penulis-terakhir-menang. Dengan implementasi ini, setiap konflik akan muncul di umpan konflik. Terserah Anda untuk menangani konflik satu per satu dari umpan konflik.
.NET SDK
DocumentCollection manualCollection = await createClient.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(this.databaseName), new DocumentCollection
{
Id = this.manualCollectionName,
ConflictResolutionPolicy = new ConflictResolutionPolicy
{
Mode = ConflictResolutionMode.Custom,
},
});
Java V4 SDK
Java SDK V4 (Maven com.azure::azure-cosmos) API Asinkron
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy();
CosmosContainerProperties containerProperties = new CosmosContainerProperties(container_id, partition_key);
containerProperties.setConflictResolutionPolicy(policy);
/* ...other container config... */
database.createContainerIfNotExists(containerProperties).block();
Java V2 SDK
Async Java V2 SDK (Maven com.microsoft.azure::azure-cosmosdb)
DocumentCollection collection = new DocumentCollection();
collection.setId(id);
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy();
collection.setConflictResolutionPolicy(policy);
DocumentCollection createdCollection = client.createCollection(databaseUri, collection, null).toBlocking().value();
Node.js/JavaScript/TypeScript SDK
const database = client.database(this.databaseName);
const {
container: manualContainer
} = await database.containers.createIfNotExists({
id: this.manualContainerName,
conflictResolutionPolicy: {
mode: "Custom"
}
});
Python SDK
database = client.get_database_client(database=database_id)
manual_resolution_policy = {'mode': 'Custom'}
manual_container = database.create_container(id=manual_container_id, partition_key=PartitionKey(path="/id"),
conflict_resolution_policy=manual_resolution_policy)
Baca dari umpan konflik
Sampel ini menunjukkan cara membaca dari umpan konflik kontainer. Konflik mungkin muncul di umpan konflik hanya karena beberapa alasan:
- Konflik tidak diselesaikan secara otomatis
- Konflik menyebabkan kesalahan dengan prosedur tersimpan yang ditunjuk
- Kebijakan resolusi konflik diatur ke kustom dan tidak menunjuk prosedur tersimpan untuk menangani konflik
.NET SDK
FeedResponse<Conflict> conflicts = await delClient.ReadConflictFeedAsync(this.collectionUri);
Java SDK
Java V4 SDK (Maven com.azure::azure-cosmos)
int requestPageSize = 3;
CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
CosmosPagedFlux<CosmosConflictProperties> conflictReadFeedFlux = container.readAllConflicts(options);
conflictReadFeedFlux.byPage(requestPageSize).toIterable().forEach(page -> {
int expectedNumberOfConflicts = 0;
int numberOfResults = 0;
Iterator<CosmosConflictProperties> pageIt = page.getElements().iterator();
while (pageIt.hasNext()) {
CosmosConflictProperties conflictProperties = pageIt.next();
// Read the conflict and committed item
CosmosAsyncConflict conflict = container.getConflict(conflictProperties.getId());
CosmosConflictResponse response = conflict.read(new CosmosConflictRequestOptions()).block();
// response.
}
});
Node.js/JavaScript/TypeScript SDK
const container = client
.database(this.databaseName)
.container(this.lwwContainerName);
const { result: conflicts } = await container.conflicts.readAll().toArray();
Python
conflicts_iterator = iter(container.list_conflicts())
conflict = next(conflicts_iterator, None)
while conflict:
# Do something with conflict
conflict = next(conflicts_iterator, None)
Langkah berikutnya
Mempelajari tentang konsep Azure Cosmos DB berikut ini:
- Distribusi global - di bawah naungan
- Cara mengonfigurasi penulisan multiwilayah di aplikasi Anda
- Mengonfigurasi klien untuk multihoming
- Menambahkan atau menghapus wilayah dari akun Microsoft Azure Cosmos DB Anda
- Cara mengonfigurasi penulisan multi-wilayah di aplikasi Anda.
- Pemartisian dan distribusi data
- Pengindeksan di Azure Cosmos DB