Headed to QCon 2024 in San Francisco? Book a meeting with us!

Distributed locks: Making them easier with Momento

Replace your DynamoDB Lock Client with Momento.

Pratik Agarwal
Author

Share

Distributed systems are like magic. Not the “I don’t know how this happened” kind of magic – well, not always, anyway. But the sort where, once you start understanding its intricacies, you begin to see everything differently. Years ago, when I used to purchase event tickets online, I’d often notice a message saying, Complete your purchase within 10 minutes to reserve your seat. Back then, it made me casually shrug, but now, it brings a knowing smile to my face as I write about distributed locks.

In distributed systems, different components need to coordinate effectively to maintain stability and handle various failure scenarios. A fundamental tool for this coordination is a locking mechanism that is highly available and resilient to network partitions. For instance, imagine thousands of football fans simultaneously trying to buy tickets for a popular game. It’s essential to sell each ticket just once to the correct buyer. Here, a distributed lock can serve as a virtual gatekeeper, ensuring that when someone is buying a ticket, that seat isn’t sold to anyone else. This mechanism maintains order and fairness, preventing the issues of double bookings and system overloads common in high-demand scenarios.

While advanced consensus algorithms like Paxos and Raft offer solutions to these challenges, they are complex to implement and manage. Then there is Apache Zookeeper, which abstracts out the challenges to implement such complex protocols, but introduces another layer of complexity to spin up Zookeeper clusters and manage the cluster instead. However, they are valuable and powerful mechanisms in their own right; just not necessarily the most simple for locking or leasing requirements. 

In response to these challenges, Amazon developed the DynamoDB Lock Client, a library that simplifies the implementation of distributed locks using DynamoDB’s robust infrastructure. This library offers a more straightforward approach to managing distributed locks, bypassing the complexities of setting up systems like Zookeeper or implementing consensus algorithms. Inspired by the efficiency and simplicity of DynamoDB’s library, we at Momento have crafted a drop-in replacement that aligns with the same principles but is tailored to integrate seamlessly with our system, and is 50-90% cheaper depending on your application workload. All you need to do is replace a few lines of your existing Java code to switch to using Momento!

The need for distributed locks

In our football ticketing example, it’s not just about preventing double bookings; it’s also about delivering a seamless and satisfying user experience. When a fan selects a seat, there might be several steps they need to go through before completing the purchase, like entering payment details or choosing additional options like parking or merchandise. Throughout this process, it’s crucial for the fan to feel confident that the seat they’ve selected is reserved for them until the end of their transaction. This is where Momento’s locking library plays a pivotal role. 

Once a fan selects a seat, the Momento Lock Client immediately locks that specific seat. This lock remains in place throughout the various steps of the transaction, ensuring that the fan doesn’t lose the seat they chose initially. Let’s take a look at how you can integrate Momento for your locking needs!

If you are changing your existing DynamoDB Lock Client library, all you need to do is change your client initialization. And if you’re looking to integrate Momento’s locking library into your application directly, hang tight, we have a release coming out for that soon in various languages!

Add your dependency:

<dependency>
  <groupId>software.momento.java</groupId>
  <artifactId>momento-dynamodb-lock-client</artifactId>
  <version>0.1.1</version>
</dependency>

Initialize the client:

final String hostname = InetAddress.getLocalHost().getHostName();
final String cacheName = "ticket-lock";
final CredentialProvider credentials = CredentialProvider.fromEnvVar("MOMENTO_API_KEY");
        
        final AmazonDynamoDBLockClient momentoLockClient = new MomentoDynamoDBLockClient(MomentoDynamoDBLockClientOptions.builder(cacheName)
                .withConfiguration(Configurations.Laptop.latest())
                .withCredentialProvider(credentials)
                .withLeaseDuration(600L)
                .withHeartbeatPeriod(3L)
                // host which acquires lock is the owner
                .withOwner(hostname)
                // let Momento manage heartbeating!
                .withCreateHeartbeatBackgroundThread(true)
                .withTimeUnit(TimeUnit.SECONDS)
                .build());

The above code requires a Momento cache called ticket-lock, and an API key set through the environment variable MOMENTO_API_KEY. You can create both of them through the Momento Console.

Now let’s move on to booking our seats:

// Seat ID for the ticket being purchased
final String seatID = "A5"; 

// Attempt to acquire a lock on the seatID
final Optional lockItem =
        momentoLockClient.tryAcquireLock(AcquireLockOptions.builder(seatID).build());
if (lockItem.isPresent()) {
    System.out.println("Success! Seat " + seatID + " is reserved for you. Complete your purchase within the next 10 minutes.");
    
    // Code to guide the user through the remaining purchase steps goes here

    momentoLockClient.releaseLock(lockItem.get());
    System.out.println("Thank you for your purchase! Seat " + seatID + " is now officially yours.");
} else {
    // case where more than 1 request comes from the front-end for the 
    // same seat at the same time
    System.out.println("Apologies, seat " + seatID + " seems to be in another transaction. Please try selecting a different seat.");
}

// Closing the client stops heartbeating, so this should be done at the end of the application lifecycle
momentoLockClient.close();

During the initialization of the client, the concept of heartbeat plays a vital role, mirroring the fundamental importance of a heartbeat in human life. In distributed systems, heartbeating to locks is critical for maintaining the lock’s integrity and functionality. These regular signals to the system confirm that the client holding the lock is still operational, much like a beating heart signals vitality.

In the context of our football ticketing example, heartbeating ensures a smooth user experience for fans during the ticket purchasing process. As a fan navigates through various steps – from selecting a seat to entering payment details – the heartbeat of the lock maintains their claim on the chosen seat. Without this consistent heartbeating, the system might prematurely release the lock on the seat, potentially leading to a frustrating experience for the fan. This heartbeat process is seamlessly handled by Momento’s library, ensuring uninterrupted and efficient management of locks throughout the transaction.

But why pessimistically lock?

One fundamental question arises: Why do we need to pessimistically lock a seat instead of using Optimistic Concurrency Control (OCC) for the same booking system?

OCC operates under the assumption that data conflicts are rare, and this assumption falters in high-traffic scenarios like ticket sales. The moment a fan selects a seat, the likelihood of another fan aiming for the same seat is high. Employing OCC in such a scenario could lead to a frustrating experience for users. Fans might reach the final stages of booking, only to discover the seat has been taken by someone else. This late-stage conflict resolution can erode user trust and satisfaction. Therefore, despite its resource intensity, pessimistic locking is the strategic choice for our ticketing system, ensuring reliability and a seamless booking experience for every fan, every time.

But why Momento?

Choosing Momento for lock management offers distinct advantages, tailored to the specific requirements of such systems:

  • Cost-Effectiveness: Momento’s solution is significantly more cost-effective, especially at scale. This affordability is crucial for systems handling large volumes of transactions. You don’t believe us?Check out our detailed cost analysis between DynamoDB and Momento Lock clients.
  • Optimized for High Traffic and Performance: Designed for high-traffic and bursty scenarios, Momento efficiently handles numerous simultaneous requests, ensuring a smooth user experience.
  • Do you need strong consistency and durability?: Given that locks are generally short to medium-lived, the properties offered by DynamoDB becomes less critical. Our system’s high availability minimizes instances of lock loss or double issuance. 
  • No Infrastructure Management: The ease of setting up and managing Momento’s lock library reduces significant technical overhead, saving time and resources.

Conclusion

Momento’s locking library offers a seamless and cost-effective solution for managing high-traffic locking scenarios with ease and efficiency. It’s an ideal choice for those seeking a robust, user-friendly approach to distributed lock management.

Dive into Momento’s drop-in replacement for the DynamoDB lock library firsthand and integrate it into your system now.

Watch this space for the generic Momento library coming soon! 

Share