How to implement Atomic Counters in DynamoDB for high throughput

Munish Chandel | July 28, 2018 at 10:00 AM | 192 views | algorithm-datastructures


Atomic Updates in Amazon Dynamo DB

Dynamo DB provides functionality to atomcially updates numeric attributes, unconditionaly, without interfering with other write operations, thus giving a much better throughput than conventional load-modify-save kind of operations.

We can use UpdateItem operation to implement an atomic counter on a numeric attribute.

But we must understand that atomic update operations are not idempotent i.e. numeric value will increment each time we call UpdateItem, thus these operations may not be suitable for banking operations, instead it may be safer to use conditional writes if you can afford a slight change in the value due to retry of operation.

Step 1. Creating the DynamoDB config

We must have a valid AWS account with DynamoDB credentials to use this tutorial. We will need three properties: AccessKey, SecretKey and Region for dynamoDB.

/src/main/resources/application.yml
aws:
  accessKey : <your-aws-access-key>
  secretKey : <your-aws-secret>
  region : us-east-1
  dynamodb :
    endpoint:

First of all we need to create a AmazonDynamoDBClient and DynamoDB bean to get started with.

/src/main/java/foo/DynamoConfig.java
@Configuration
public class DynamoConfig {
    private static final Logger logger = LoggerFactory.getLogger(DynamoConfig.class);

    @Bean
    AmazonDynamoDBClient dbClient(@Value("${aws.dynamodb.endpoint}") String amazonDynamoDBEndpoint, AWSSettings awsSettings) {
        AmazonDynamoDBClient dbClient = new AmazonDynamoDBClient(
                new BasicAWSCredentials(awsSettings.getAccessKey(), awsSettings.getSecretKey()));
        dbClient.setRegion(Region.getRegion(Regions.fromName(awsSettings.getRegion())));
        logger.info("DB Endpoint is " + amazonDynamoDBEndpoint);
        if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
            dbClient.setEndpoint(amazonDynamoDBEndpoint);
        }
        if (awsSettings.getRegion().equalsIgnoreCase("local")) {
            dbClient.setEndpoint("http://localhost:8000");
        }
        return dbClient;
    }

    @Bean
    DynamoDB dynamoDB(AmazonDynamoDBClient client) {
        return new DynamoDB(client);
    }
}

Step 2. Create Model for table

Lets create a Content table that stores news title and description. We will create a siumilar table in DynamoDB making id as the hashkey.

/src/main/java/foo/Content.java
@Data
@DynamoDBTable(tableName = "local-content")
public class Content {
    @DynamoDBHashKey(attributeName = "id")
    private String id;

    @DynamoDBAttribute
    private String title;

    @DynamoDBAttribute
    private String description;

    @DynamoDBAttribute
    private long views;
}

Step 3. Creating DAO layer that updates views atomically

Lets create DAO layer for Content that will save and update number of views of a given content.

/src/main/java/foo/ContentDao.java
@Repository
public class ContentDao {

    @Autowired
    private AmazonDynamoDBClient dynamoDBClient;

    @Autowired
    private DynamoDB dynamoDB;

    public Content create(Content dto)  {
        DynamoDBMapper mapper = new DynamoDBMapper(dynamoDBClient);
        mapper.save(dto);
        return dto;
    }

    /**
     * This method atomically updates number of views without interfering with other update operations, use it with caution because method is not idempotent in nature.
     * @param contentId ID of the content
     * @param delta the number of views to increment
     */
    public void incrementViews(String contentId, long delta) {
        Map<String, AttributeValue> key = new HashMap<>();
        key.put("id", new AttributeValue().withS(contentId));

        UpdateItemRequest updateRequest =
                new UpdateItemRequest().withTableName("local-content")
                        .withKey(key)
                        .addAttributeUpdatesEntry("views", new AttributeValueUpdate()
                            .withValue(new AttributeValue().withN("" + delta))
                            .withAction(AttributeAction.ADD));
        dynamoDBClient.updateItem(updateRequest);
    }

Important Caution

  1. Do not use atomic counters for attribute that can not tolerate slight overcounting or undercounting for e.g. in banking applications.

  2. Atomic counter operations are not idempotent in nature, a simple retry will increment the value again.

Use Cases for Atomic Counters

Website counters are ideal candidates for atomic counters.

Download Git Repository

Code in this tutorial is available at https://github.com/cancerian0684/dynamodb-atomic-updates


Buy DRM Free PDF for Complete Collection of Interview Questions
Generic placeholder image
ebook PDF - Cracking Spring Microservices Interviews for Java Developers

This ebook discusses 120 plus real problems and their solutions for Spring microservices architecture based on Spring Boot, Spring Cloud, Cloud Native Applications. It covers core concepts of microservices architecture, various design patterns, interview questions & answers, security in microservices, testing strategies and best practices in distributed system design.

Free Email Updates
Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.


Similar Articles:
  1. What is Eventual Consistency in DynamoDB?
  2. How to implement Atomic Counters in DynamoDB for high throughput
  3. How to automatically Retry DynamoDB Write on ProvisionedThroughputExceededException
  4. Amazon DynamoDB Java Interview Questions
  5. How will you ensure that no two threads update the same db record in parallel in amazon DynamoDB
  6. What are Best Practices for Using Amazon DynamoDB?
  7. Implementing Adhaar Card Service using DynamoDB
  8. scan all records of a Amazon DynamoDB table using a Java Code
  9. What are Conditional Writes in AWS DynamoDB

This website uses cookies to ensure you get the best experience on our website. more info