[erlang-questions] Modelling question - concurrency and scalability

Rudolph van Graan rvg@REDACTED
Fri Aug 10 11:31:29 CEST 2007

Hi Guys,

Suppose you write an accounting system (like in an ordinary set of T  
accounts). Now you have a lot of transactions running concurrently,  
each one debiting one account and crediting another.

An account may look like this:  {account, ID, Debits, Credits}

When we start the set of accounts look like this: (The debits and  
credits add up to 0)

{account, 1, 0, 0}
{account, 2, 0, 0}
{account, 3, 0, 0}

We define a transaction so: {transaction, ID, Amount, DebitAccount,  

So we run these transactions against the accounts:

{transaction,  1, 10 , 1, 2}
{transaction,  2, 20 , 2, 3}
{transaction,  3, 40 , 3, 1}
{transaction,  4, 20 , 2, 1}

The accounts should look like this at the end:

{account, 1, 10, 60}  (Balance = Credit 50)
{account, 2, 40, 10}  (Balance = Debit 30)
{account, 3, 40, 20}  (Balance = Debit 20)

The Debits == Credits == 90 --> This means the system is in balance  
as it should be.

Each transaction does the following:

1. Check if an account has sufficient credits to continue
2. Credit this account, Debit the other

The problem here is that you need to modify two accounts for each  
transaction, but before you do that you need to know atomically what  
it's current balance is.  In essence, if you have a small number of  
accounts and a large number of transactions you will have a large  
contention ratio on a single account. If you use mnesia (or any  
database for that matter), your system will only scale to the maximum  
rate at which the DBMS process transactions atomically. And then it  
seems as though you cannot scale anymore. Concurrency will not solve  
this problem. If you use SQL you have exactly the same problem:

- start transaction
- select the current balance of the account
- if sufficient
  -- debit account 1
  -- credit account 2
- commit transaction

The key property here seems to be the fact that you always ADD to the  
values, never SUBTRACT. If you never had to know in a transaction  
what the "current" balance is, you can fix the problem. But IMO not  
when you need to check values atomically.

Does anyone have suggestions on how one can solve the scalability  
problem here taking into account that you must know the current  
balance of the account before modifying it? A scheme where you split  
each account into smaller ones won't work, as you will have to sum  
all the smaller accounts to get the balance of the larger one. The  
more accounts you have and the more even the transactions are spread  
over the different accounts the easier it is to scale. But what do  
you do if this is not true?


More information about the erlang-questions mailing list