Оновлення запитів одночасно
Консистентність даних є критично важливою в динамічному середовищі додатків, особливо коли кілька користувачів або системи намагаються одночасно отримувати доступ і змінювати одні й ті ж записи. Ви коли-небудь потрапляли в незручну ситуацію, коли хтось інший змінював документ, який ви оновлювали в той самий час? Якщо ви стикалися з несумісними даними в системі, атомарні оновлення — це те, що вас врятує!
У цьому блозі ми розглянемо, що таке атомарні оновлення та чому вони важливі. Також ми надамо приклад коду з використанням MongoDB та JavaScript. Наприкінці ви матимете чітке розуміння того, як зберегти консистентність даних під час кількох операцій оновлення.
Чому атомарні оновлення?
Уявіть, що ви в переповненому кафе, і два баристи обробляють ваше замовлення. Один відповідає за приготування напою, а інший додає додаткові порції еспресо. Якщо баристи не синхронізовані, ви можете отримати два абсолютно різних напої — один без еспресо, а інший з надмірною кількістю! Саме так виникають умови гонки і несумісні дані в програмних системах. Атомарні оновлення гарантують, що ваші дані залишаються консистентними, навіть коли кілька операцій відбуваються одночасно.
Атомарні оновлення важливі для:
-
Консистентності: Атомарні операції гарантують, що оновлення відбудеться як єдина, неподільна одиниця роботи, уникаючи часткових оновлень.
-
Конкуренції: Коли кілька користувачів намагаються оновити один і той самий документ одночасно, атомарні оновлення запобігають виникненню умов гонки.
-
Ефективності: Замість того щоб блокувати цілу базу даних, атомарні оновлення дозволяють більш точно контролювати процес, роблячи вашу систему швидшою та більш чутливою.
Що таке атомарна операція?
Простими словами, атомарна операція — це така, яка або завершується повністю, або не відбувається взагалі. У MongoDB атомарне оновлення гарантує, що жодна інша операція не зможе перервати або вплинути на оновлення, поки воно не завершиться.
Приклад коду для атомарних оновлень за допомогою MongoDB та JS
Давайте подивимося, як реалізувати атомарні оновлення в MongoDB з JavaScript.
Цей приклад продемонструє, як оновити статус документа атомарно за допомогою методу findOneAndUpdate MongoDB.
const { MongoClient, ObjectId } = require("mongodb");
// URI з'єднання та ім'я бази даних
const uri = 'mongodb://localhost:27017';
const dbName = 'myDatabase';
// Створення нового MongoClient
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
// Функція для вставки документа в колекцію
async function insertDocument(db) {
const collection = db.collection('documents');
const result = await collection.insertOne({ name: 'John', age: 30, status: 'pending' });
console.log('Вставлено документ з _id:', result.insertedId);
return result.insertedId;
}
// Функція для атомарного оновлення документа за допомогою findOneAndUpdate
async function updateDocumentAtomically(db, id, currentStatus, newStatus) {
const collection = db.collection('documents');
// Створення запиту для пошуку документа з вказаним id та поточним статусом
const query = { _id: new ObjectId(id), status: currentStatus };
// Створення операції оновлення для зміни статусу
const update = { $set: { status: newStatus } };
// Параметри для операції findOneAndUpdate
const options = {
returnOriginal: false,
upsert: false,
};
// Виконання атомарної операції оновлення
const result = await collection.findOneAndUpdate(query, update, options);
if (result.value) {
console.log('Оновлений документ:', result.value);
} else {
console.log('Документ з вказаним статусом для оновлення не знайдений.');
}
return result;
}
// Функція для імітації одночасних оновлень одного документа
async function simulateConcurrentUpdates(db, id) {
const tasks = Array.from({ length: 5 }, (_, index) => async () => {
const updatedDoc = await updateDocumentAtomically(db, id, 'pending', 'processing');
console.log(`Спроба оновлення ${index + 1}:`, updatedDoc.value);
});
// Виконання завдань одночасно
await Promise.all(tasks.map(task => task()));
}
// Основна функція для виконання операцій MongoDB
async function main() {
try {
// Підключення клієнта до сервера MongoDB
await client.connect();
console.log('Підключено до сервера MongoDB');
// Отримання бази даних
const db = client.db(dbName);
// Вставка документа
const insertedId = await insertDocument(db);
// Імітація одночасних оновлень вставленого документа
await simulateConcurrentUpdates(db, insertedId);
} catch (err) {
console.error('Помилка:', err);
} finally {
// Закриття з'єднання з клієнтом
await client.close();
console.log('Відключено від сервера MongoDB');
}
}
// Виклик основної функції
main();
Розбір
• findOneAndUpdate(): Це магічна функція, яка гарантує атомарність операції. Вона дозволяє шукати документ за його поточним статусом і оновлювати його на новий, але тільки якщо ніяка інша операція не змінила його в цей час.
• Імітація конкурентних оновлень: У функції simulateConcurrentUpdates ми імітуємо п'ять одночасних завдань, які намагаються оновити один і той самий документ. Завдяки атомарним оновленням система гарантує, що ці операції не конфліктують між собою.
Аналогія з реального життя: Атомарність в дії
Давайте подумаємо про атомарні оновлення в контексті того, що ми всі можемо зрозуміти — замовлення піци! Уявіть, що ви і чотири ваших друзі вирішили замовити піцу. У вас усіх різні вподобання щодо начинок, і всі намагаються одночасно змінити замовлення. Без координації ви можете отримати піцу з грибами, ананасами, анчоусами і шоколадом одночасно! Ужас!
З атомарними оновленнями це як якщо б піца-шеф обробляв кожне замовлення по черзі. Кожне запит на зміну начинки піци повністю обробляється перед тим, як прийняти наступний.
Це гарантує, що піца буде саме такою, якою ви хочете, і ніхто не отримає кулінарної катастрофи!
Коли використовувати атомарні оновлення
-
Оновлення статусу: Як показано в прикладі коду, якщо ваш додаток обробляє зміни статусів, атомарні оновлення є обов'язковими. Це дозволяє уникнути ситуацій, коли кілька користувачів намагаються одночасно змінити один і той самий статус.
-
Управління запасами: Коли кілька користувачів купують продукти, потрібно гарантувати правильне оновлення рівнів запасів, щоб уникнути ситуацій, коли один товар купують двоє.
-
Банківські операції: Якщо ви обробляєте фінансові дані, атомарні оновлення критично важливі для того, щоб дебети та кредити правильно застосовувались, не залишаючи жодних незавершених транзакцій.
Підсумок
Атомарні оновлення є важливою технікою для підтримки цілісності даних, особливо в системах, де часто виникає одночасний доступ. Вони гарантують, що операції будуть завершені повністю перед тим, як дозволити іншим вносити зміни, захищаючи ваші дані від гонок даних і часткових оновлень.
Незалежно від того, чи оновлюєте ви замовлення піци, чи обробляєте транзакції в масштабному додатку, розуміння та впровадження атомарних оновлень допоможе вам уникнути проблем і забезпечить цілісність і надійність ваших даних.
Якщо вас цікавлять такі теми, не забудьте підписатись на Insider Engineering.
До зустрічі!
Якщо вас цікавлять підписки GraphQL, перегляньте наступну публікацію в блозі
https://medium.com/insiderengineering/stay-connected-how-to-implement-apollo-graphql-subscriptions-with-websockets-5c390e5d32f3
Посилання:
https://www.mongodb.com/docs/manual/core/write-operations-atomicity/
Перекладено з: Atomic Updates: Keeping Your Data Consistent in a Changing World