СУБД - Замиокрытие: Понимание и предотвращение узких мест в базе данных

Здравствуйте, ambitные энтузиасты баз данных! Я рад помочь вам окунуться в fascинирующий мир систем управления базами данных (СУБД) и один из его trickiest концепций: замиокрытие. Не волнуйтесь, если вы новички в программировании; мы начнем с основ и постепенно продвинемся. К концу этого руководства вы станете детективом замиокрытия, способным обнаружить и предотвратить эти надоедливые узкие места в базе данных!

DBMS - Deadlock

Что такое замиокрытие?

Представьте, что вы и ваш друг сидите за столом с одним fork и одним ножом. Вам нужно оба инструмента, чтобы есть, но вы держите по одному и отказываетесь его отпускать, пока не получите другой. Это в основном то, что такое замиокрытие в мире баз данных!

На языках СУБД, замиокрытие возникает, когда две или более транзакции ждут друг друга, чтобы освободить ресурсы, которые они держат. Это как цифровая mexican standoff, где никто не может двигаться вперед.

Давайте рассмотрим простой пример:

-- Транзакция 1
BEGIN TRANSACTION;
UPDATE Accounts SET Balance = Balance - 100 WHERE AccountID = 1;
UPDATE Accounts SET Balance = Balance + 100 WHERE AccountID = 2;
COMMIT;

-- Транзакция 2
BEGIN TRANSACTION;
UPDATE Accounts SET Balance = Balance - 50 WHERE AccountID = 2;
UPDATE Accounts SET Balance = Balance + 50 WHERE AccountID = 1;
COMMIT;

В этой ситуации, если Транзакция 1 обновляет Счет 1 и Транзакция 2 обновляет Счет 2 одновременно, они могут оказаться в ожидании друг друга indefinately, создавая замиокрытие.

Профилактика замиокрытия

Теперь, когда мы понимаем, что такое замиокрытие, давайте рассмотрим, как его предотвратить. Профилактика замиокрытия involves структурирование системы таким образом, чтобы eliminate возможность возникновения замиокрытий.

1. Порядок запроса ресурсов

Одним из эффективных методов является всегда запрашивать ресурсы в определенном порядке. Это как tell нашим посетителям всегда сначала поднимать вилку, а затем нож. Таким образом, они никогда не окажутся в ситуации, когда они держат needed tool друг друга.

Вот как мы могли бы переписать наш предыдущий пример, чтобы предотвратить замиокрытия:

-- Транзакция 1
BEGIN TRANSACTION;
UPDATE Accounts SET Balance = Balance - 100 WHERE AccountID = 1;
UPDATE Accounts SET Balance = Balance + 100 WHERE AccountID = 2;
COMMIT;

-- Транзакция 2
BEGIN TRANSACTION;
UPDATE Accounts SET Balance = Balance - 50 WHERE AccountID = 1;
UPDATE Accounts SET Balance = Balance + 50 WHERE AccountID = 2;
COMMIT;

Always обновляя Счет 1 перед Счетом 2, мы ensure, что транзакции не замикнутся.

2. Таймауты блокировок

Другой метод профилактики - использовать таймауты блокировок. Это как tell нашим посетителям: "Если вы не можете получить оба инструмента за 5 минут, просто откажитесь и попробуйте еще раз позже."

В SQL Server вы можете установить таймаут блокировки следующим образом:

SET LOCK_TIMEOUT 5000; -- Установить таймаут на 5 секунд

Таким образом, если транзакция не может получить блокировку в течение 5 секунд, она автоматически откатится, предотвращая возможное замиокрытие.

3. Уменьшение продолжительности блокировки

Чем меньше время блокировки, тем меньше вероятность замиокрытия. Это как tell нашим посетителям есть быстрее! В терминах базы данных это означает поддержание транзакций как можно короче.

Вот пример, как уменьшить продолжительность блокировки:

-- Вместо этого:
BEGIN TRANSACTION;
-- Провести некоторые длительные обработки
UPDATE Accounts SET Balance = Balance - 100 WHERE AccountID = 1;
COMMIT;

-- Делайте это:
-- Провести некоторые длительные обработки
BEGIN TRANSACTION;
UPDATE Accounts SET Balance = Balance - 100 WHERE AccountID = 1;
COMMIT;

Перенося длительные обработки вне транзакции, мы уменьшаем время, в течение которого блокировка удерживается.

Избежание замиокрытия

While профилактика aims к тому, чтобы сделать замиокрытия невозможными, избежание заключается в принятии intelligent решений в реальном времени, чтобы избежать возможных замиокрытий.

1. Схема Wait-Die

В этой схеме приоритет предоставляется старшим транзакциям. Если молодая транзакция запрашивает ресурс, удерживаемый старшей, она "умирает" (откатывается) и перезапускается. Если старшая транзакция запрашивает ресурс, удерживаемый молодой, она ждет.

Вот pseudocode representation:

def request_resource(transaction, resource):
if resource.is_held_by_younger_transaction(transaction):
wait(transaction, resource)
else:
die_and_restart(transaction)

2. Схема Wound-Wait

Это相反 Wait-Die. Старшие транзакции "ранят" (откатывают) молодые, а молодые ждут старших.

def request_resource(transaction, resource):
if resource.is_held_by_younger_transaction(transaction):
wound(resource.holder)
else:
wait(transaction, resource)

3. Алгоритм банкира

Этот умный алгоритм, названный в честь bank loan practices, решает, может ли удовлетворение запроса ресурса привести к замиокрытию. Если да, запрос отклоняется.

Вот упрощенная версия Алгоритма банкира:

def is_safe_state(available, max_need, allocation):
work = available.copy()
finish = [False] * len(allocation)

while True:
found = False
for i in range(len(allocation)):
if not finish[i] and (max_need[i] - allocation[i] <= work).all():
work += allocation[i]
finish[i] = True
found = True

if not found:
break

return all(finish)

def request_resources(process_id, request):
if request > max_need[process_id] - allocation[process_id]:
return False  # Запрос превышает максимальное требование

if request > available:
return False  # Ресурсы недоступны

# Временно allocate ресурсы
available -= request
allocation[process_id] += request

if is_safe_state(available, max_need, allocation):
return True  # Удовлетворить запрос
else:
# Вернуть изменения и отклонить запрос
available += request
allocation[process_id] -= request
return False

Этот алгоритм проверяет, приведет ли удовлетворение запроса к безопасному состоянию системы (где все процессы могут завершиться). Если нет, запрос отклоняется.

Заключение

Поздравляю! Вы только что сделали свои первые шаги в мир профилактики и избежания замиокрытий. Помните, работа с замиокрытиями похожа на работу traffic cop на оживленном перекрестке. Иногда вам нужно предотвратить проблемы до их возникновения (например, install traffic lights), а иногда вам нужно принимать быстрые решения, чтобы избежать аварий (например, manual traffic control).

Пока вы продолжаете свое путешествие в управление базами данных, вы столкнетесь с более сложными сценариями, но принципы, которые мы обсуждали здесь, будут служить solid foundation. Продолжайте практиковаться, stay curious, и не бойтесь экспериментировать. В конце концов, каждый великолепный администратор баз данных начал exactly где вы находитесь сейчас!

Счастливого кодирования, и пусть ваши транзакции всегда будут свободны от замиокрытий!

Credits: Image by storyset