Высокораспределенная архитектура OLTP

Есть ли известное архитектурное решение для высокораспределенных OLTP-ситуаций, где применяются предварительные условия? Например, давайте использовать пример банковского дела. Лицо A хочет перевести $N лицу B. Предварительные условия для этого состоят в том, что лицо A должно иметь более $N на своем счете.

С точки зрения человека А они входят в какое-то веб-приложение. Они создают перевод от себя Человеку B за N $. Имейте в виду, что в фоновом режиме деньги снимаются и зачисляются на счет Лица А в режиме реального времени, когда применяется этот перевод и когда он создается. Деньги могут существовать до создания, но после применения перевода их может не быть. Другими словами, это не может быть проверка на стороне клиента. Человек А хотел бы знать, что эта передача была успешной или не удалась синхронно. Человек А не хотел бы передавать передачу асинхронно, а затем позже возвращаться в очередь или какое-либо уведомление о том, что передача не удалась.

Есть ли известная архитектура, которая решает эту проблему в больших масштабах? Если все учетные записи находятся в одной СУБД, то вы можете сделать что-то подобное с помощью встроенных транзакционных возможностей. Но если вы используете в конечном итоге непротиворечивое хранилище данных в стиле NoSQL или инфраструктуру на основе журналов / сообщений, такую ​​как Kafka, есть ли известное решение таких проблем?

2 ответа

Вы смотрели на Splice Machine? Это СУБД, полностью совместимая с ACID, которая работает поверх стека hadoop (hbase, spark, hdfs, zookeeper). Они имеют двойную архитектуру, которая использует hbase для быстрых OLTP-запросов и искры для OLAP-запросов, и имеет встроенные транзакционные возможности, которые не требуют какой-либо блокировки.

ClustrixDB - еще одно решение, которое стоит попробовать. Он использует Paxos для разрешения распределенных транзакций (встроенный в распределенную, ACID, SQL-совместимую СУБД), а также имеет встроенную отказоустойчивость.

По сути, вам нужен механизм распределенной блокировки. Многие из распределенных серверных приложений предоставляют такую ​​возможность.

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

// BANK WITHDRAWAL APPLICATION

// Fetch BankAccount object from NCache
BankAccount account = cache.Get("Key") as BankAccount; // balance = 30,000
Money withdrawAmount = 15000;

if (account != null && account.IsActive)
{
    // Withdraw money and reduce the balance
    account.Balance -= withdrawAmount;

    // Update cache with new balance = 15,000
    cache.Insert("Key", account);
}

=========================

// BANK DEPOSIT APPLICATION

// Fetch BankAccount object from NCache
BankAccount account = cache.Get("Key") as BankAccount; // balance = 30,000
Money depositAmount = 5000;

if (account != null && account.IsActive)
{
    // Deposit money and increment the balance
    account.Balance += depositAmount;

    // Update cache with new balance = 35,000
    cache.Insert("Key", account); 
}

Это в основном пример состояния гонки

Условие состязания - это когда два или более пользователей пытаются получить доступ к одним и тем же общим данным и изменить их одновременно, но в конечном итоге делают это в неправильном порядке.

Ответ на приведенный выше код в распределенной блокировке будет

LockHandle lockHandle = new LockHandle();

// Specify time span of 10 sec for which the item remains locked
// NCache will auto release the lock after 10 seconds.
TimeSpan lockSpan = new TimeSpan(0, 0, 10); 

try
{
    // If item fetch is successful, lockHandle object will be populated
    // The lockHandle object will be used to unlock the cache item
    // acquireLock should be true if you want to acquire to the lock.
    // If item does not exists, account will be null
    BankAccount account = cache.Get(key, lockSpan, 
    ref lockHandle, acquireLock) as BankAccount;
    // Lock acquired otherwise it will throw LockingException exception

    if(account != null && account.IsActive)
    {
        // Withdraw money or Deposit
        account.Balance += withdrawAmount;
        // account.Balance -= depositAmount;

        // Insert the data in the cache and release the lock simultaneously 
        // LockHandle initially used to lock the item must be provided
        // releaseLock should be true to release the lock, otherwise false
        cache.Insert("Key", account, lockHandle, releaseLock); 
    }
    else
    {
        // Either does not exist or unable to cast
        // Explicitly release the lock in case of errors
        cache.Unlock("Key", lockHandle);
    } 
}
catch(LockingException lockException)
{
    // Lock couldn't be acquired
    // Wait and try again
}

Этот ответ очень специфичен для NCache (распределенный кэш). Я уверен, что вы найдете больше решений под ключевым словом "Распределенная блокировка"

Источник

Другие вопросы по тегам