3

We are working to build an exchange using Go. Following components are there in the system of now:

  • Frontend
  • Backend
  • Matching Engine.

Here is how the system works:

  • User creates an order which goes to Backend.
  • Backend processes the new order in following manner :
    • It validates the order request data & then a db transaction is created for updating users account balance in account table & new order is inserted in the order table.
    • After db interaction is completed; backend produces a new order message in queue.
  • Matching Engine processes the new order from the queue and pushes the engine response(i.e updated orders & trades) in another queue
  • Backend consumes the engine response as below:

    • Multiple goroutines run in parallel to process engine response &store the updates received in engine response.
    • For storing the the updates, a database transaction is created within each goroutine to update the users account balance, orders & store new trades.
  • Problem occurs during this stage when concurrent (parallel) transactions try to update the same users account at a time, a deadlock is created in DB as multiple transaction try to lock the same record. Also while a users previously placed orders are being matched and processed user can create new order as mentioned in step 2, so transaction created in step 2 also tries to update the same users account in database which is being accessed by backend to store Matching Engine response. This also adds to the chances of deadlock.

  • How to properly manage and prevent the database deadlock generated in above mentioned flow.

  • We have tried a solution to retry transaction by following code but the deadlock issue can still be reproduced

    // Update accounts, orders, trades with max retry of 5
    for i := 0; i < 5; i++ {
        err = nil
        time.Sleep(10 * time.Second)
        if err = manager.saveEngineResponse(newEngineResponse, accountUpdatesToDoRef, &updatedOrders); err == nil {
            break
        }
        logger.Debug("Error saving engine response", err)
    }
    if err != nil {
        logger.Fatal(err)
        return
    }

Error : Error 1213: Deadlock found when trying to get lock; try restarting transaction

I have refered the link : How to avoid mysql 'Deadlock found when trying to get lock; try restarting transaction' which states that by keeping the operations in a specific order deadlocks can be avoided. And in the above scenario all transaction will first update account, then order & then trades if any. So the order of operations is consistent in different transactions

Mukund Sonaiya
  • 461
  • 3
  • 10
  • There is no single, direct answer to this. And this is not specific to Go. This problem can occur in any database system, in any language. A [simple search](https://www.google.nl/search?q=site%3Astackoverflow.com+how+to+avoid+database+deadlocks&oq=site%3Astackoverflow.com+how+to+avoid+database+deadlocks&aqs=chrome..69i57j69i58.7020j0j7&sourceid=chrome&ie=UTF-8) shows that essentially the same question has been asked countless times. I suggest reading through the answers, to find one or more that applies to your situation. – Jonathan Hall May 24 '19 at 10:24
  • 1
    *Parallel* and *concurrent* are technical terms in database work. I think you mean *concurrent* here. Edit your question, and be consistent with the right term. – Mike Sherrill 'Cat Recall' May 24 '19 at 10:27
  • They're also technical terms in Go. [Suggested watching](https://blog.golang.org/concurrency-is-not-parallelism). – Jonathan Hall May 24 '19 at 10:30
  • @Flimzy I understand. We have tried solving the issue by restarting the new transaction after some delay, but still the deadlock issue occurs. So we are finding solution that we can implement in go to restart the transaction & resolve this deadlock. – Mukund Sonaiya May 24 '19 at 11:33
  • Best to avoid the deadlock entirely, rather than to restart transactions. – Jonathan Hall May 24 '19 at 11:39
  • @Peter We have tried restarting the transaction in GO, but the solution did not work as you can see in the above code – Mukund Sonaiya May 24 '19 at 11:40
  • @Flimzy Can you please suggest some way on how to avoid that in above scenario. As we have already brainstormed on that part. – Mukund Sonaiya May 24 '19 at 11:41
  • @Flimzy I have updated the question as you see. I need the solution in GO to retry the question. Can you please unmark it as duplication. Thanks. – Mukund Sonaiya May 24 '19 at 11:46
  • @Peter I have updated the question as you see. I need the solution in GO to retry the question. Can you please unmark it as duplication. Thanks. – Mukund Sonaiya May 24 '19 at 11:46
  • @Peter I am also updating the content. You can check the updates – Mukund Sonaiya May 24 '19 at 11:50
  • @Flimzy I have updated the content. You can also check the updates – Mukund Sonaiya May 24 '19 at 11:53

0 Answers0