aws

Copying DynamoDB Table Contents Across Regions

There is no direct way of copying data of a DynamoDB table across regions (i.e. from one region to another) from the DynamoDB management console.

Why would you need such an operation? i.e. moving data across regions. Answer may be, sometimes you need to setup multiple environments, one for each development phase. Like for example, development, SIT, UAT, Pre-production, performance-test environment etc.

I will be deploying a solution which requires using the Amazon EMR (Elastic Map Reduce). EMR is essentially the service recommended by Amazon to move data in and out of DynamoDB into S3 where it may then be picked up for further processing / use.

High Level Overview of the solution requiring EMR

  1. Start an EMR Job from the EMR Management Console, putty into the EMR Master Node, start Hive.
  2. Set the DynamoDB endpoint to the source region
  3. Set up a Hive table to reference to the DynamoDB table in the source region
  4. Create an S3 Bucket to store temporal data
  5. Set up a Hive table to reference to the S3 location where data from the DynamoDB table in the source region will be written to
  6. Issue the Hive command that does the actual copying from the DynamoDB table in the source region to the S3 location
  7. Set the DynamoDB endpoint to the destination region.
  8. Issue the Hive command that does the actual copying from the S3 location to the DynamoDB table in the destination region.

Step 1: Start an EMR Job from the EMR Management Console, putty into the EMR Master Console, start Hive.

This step is well detailed in Amazon EMR’s Documentation here at http://docs.aws.amazon.com/ElasticMapReduce/latest/DeveloperGuide/EMRforDynamoDB.html therefore i will not reiterate.

Follow the following steps in sequence

Step 1.1 (Create a Key pair): http://docs.aws.amazon.com/ElasticMapReduce/latest/DeveloperGuide/EMR_SetUp_KeyPair.html

Step 1.2 (Create a Cluster): http://docs.aws.amazon.com/ElasticMapReduce/latest/DeveloperGuide/EMR_CreateJobFlow.html

Step 1.3 (SSH into the Master Node): http://docs.aws.amazon.com/ElasticMapReduce/latest/DeveloperGuide/EMR_SetUp_SSH.html

Once the above three steps are completed, you would have secure shelled into the EMR Master Node and started Hive.

For example:

final

Step 2: Set the DynamoDB endpoint to the source region

Now you will need to set the DynamoDB endpoint to the source region, this is the region where your source table resides. In this example, i am setting the source region endpoint to Singapore.

SET dynamodb.endpoint=dynamodb.ap-southeast-1.amazonaws.com;

For example:

source

Step 3: Set up a Hive table to reference to the DynamoDB table in the source region

In the earlier step i have pointed Hive to DynamoDB in the source region, i shall now create an external table in Hive to reference to the DynamoDB table.

CREATE EXTERNAL TABLE hive_dynamodb_customer_lines (cust_id string, lines bigint)
STORED BY 'org.apache.hadoop.hive.dynamodb.DynamoDBStorageHandler' 
TBLPROPERTIES ("dynamodb.table.name" = "customer_lines", 
"dynamodb.column.mapping" = "cust_id:cust_id,lines:lines");

In this script i am creating an external table named ‘hive_dynamodb_customer_lines’, this Hive table would reference the DynamoDB table ‘customer_lines’ containing the actual data. The table ‘customer_lines’ has the fields cust_id and lines.

Step 4: Create an S3 Bucket to store temporal data

In this step i am creating an S3 Bucket to store temporal data. This bucket and its contents can be deleted at the end of the data migration.

Create a bucket in S3, in this example, i am have created the bucket named ‘dynamodb-migration’. This can be named anything for you, subject to availability (i.e. there cannot be two buckets with the same time in S3)

For example:

migration

 

In the newly created S3 Bucket, create a folder named ‘temp’.

For example:

migratio

Step 5: Set up a Hive table to reference to the S3 location where data from the DynamoDB table in the source region will be written to

I now need to create a Hive table that references to the newly created S3 location where i would dump the data of the DynamoDB table into.

CREATE EXTERNAL TABLE hive_s3_customer_lines (cust_id string, lines bigint)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
LOCATION 's3://dynamodb-migration/temp';

Step 6: Issue the Hive command that does the actual copying from the DynamoDB table in the source region to the S3 location

In this step i will issue the Hive command that does the copying from the DynamoDB table to S3.

INSERT OVERWRITE TABLE hive_s3_customer_lines SELECT * 
FROM hive_dynamodb_customer_lines;

Once this step executes, data from the DynamoDB table will be copied over into S3. You could go into your S3 bucket to see this file.

For example:

file

Step 7: Set the DynamoDB endpoint to the destination region.

In this step i am setting the DynamoDB endpoint to the destination region where i want the contents of the DynamoDB table to be copied into. In this example, my destination DynamoDB region would be Ireland.

SET dynamodb.endpoint=dynamodb.eu-west-1.amazonaws.com;

Step 8: Issue the Hive command that does the actual copying from the S3 location to the DynamoDB table in the destination region.

In this step i am issuing the hive command that performs the actual copy from S3 to the DynamoDB table in the destination region.

INSERT OVERWRITE TABLE hive_dynamodb_customer_lines SELECT * FROM hive_s3_customer_lines;

When completed, you could go to the DynamoDB table in the destination region to verify that your data is copied successfully.

 

Remember to terminate the EMR Job created through Step 1 and delete the S3 Bucket created in Step 4 to stop incurring AWS resources / charges at the end of the exercise.

Share
simple form

Target Unreachable, xxx returned null

This error is probably happening when you are trying to submit a form. JSF tries to populate all the user entered form values into the corresponding backing bean attributes that aren’t yet initialized, i.e. null.

Consider this simple form where we are trying to collect the Price Model Name from the user.

simple form

createPriceModel.xhtml JSF2 Form

In the form, the value of the price model name text field is set into a backing bean containing a complex data object PriceModel which contains the attribute priceModelName.

<h:form>
	<p:inputText id="priceModelName"
		value="#{priceModelBackingBean.priceModel.priceModelName}" />
	</p:inputText>
	...
</h:form>

PriceModelBackingBean.java Backing Bean

@ManagedBean
@SessionScoped
public class PriceModelBackingBean implements IPriceModelBackingBean {
	private PriceModel priceModel;
	...
	accessors and mutators
	...
}

PriceModel.java POJO

public class PriceModel {
	private String priceModelName;

	...
	accessors and mutators
	...
}

So, what could go wrong?

Solution

Initialize the priceModel attribute!

You did not initialize the value of priceModel in the backing bean. When the user submits the form and JSF tries to populate the value of the price model name which is “Standard Price Model”, it hits a null pointer exception.

While we could do this in a constructor of the backing bean, it is not advisable to do so, instead use the @PostConstruct JSF bean lifecycle annotation to help you. This way it is guaranteed that the attribute priceModel is initialized.

public class PriceModelBackingBean implements IPriceModelBackingBean {
    private PriceModel priceModel;
     
    @PostConstruct
    public void init() {
        this.priceModel = new PriceModel();
    }
     
    ...
}

Error Message Encountered (Reference)

22:05:11,706 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (http-localhost-127.0.0.1-8080-1) /facelet/manage/pricing/createPriceModel.xhtml @47,64 value="#{priceModelBackingBean.priceModel.priceModelName}": Target Unreachable, 'priceModel' returned null: javax.el.PropertyNotFoundException: /facelet/manage/pricing/createPriceModel.xhtml @47,64 value="#{priceModelBackingBean.priceModel.priceModelName}": Target Unreachable, 'priceModel' returned null
	at com.sun.faces.facelets.el.TagValueExpression.getType(TagValueExpression.java:100) [jsf-impl-2.1.7-jbossorg-2.jar:]
	at org.primefaces.renderkit.InputRenderer.findImplicitConverter(InputRenderer.java:170) [primefaces-3.4.jar:]
	at org.primefaces.renderkit.InputRenderer.findConverter(InputRenderer.java:190) [primefaces-3.4.jar:]
	at org.primefaces.renderkit.InputRenderer.getConvertedValue(InputRenderer.java:196) [primefaces-3.4.jar:]
	at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at javax.faces.component.UIInput.validate(UIInput.java:960) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at javax.faces.component.UIInput.executeValidate(UIInput.java:1233) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at javax.faces.component.UIInput.processValidators(UIInput.java:698) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at org.primefaces.component.fieldset.Fieldset.processValidators(Fieldset.java:197) [primefaces-3.4.jar:]
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at org.primefaces.component.layout.Layout.processValidators(Layout.java:245) [primefaces-3.4.jar:]
	at javax.faces.component.UIForm.processValidators(UIForm.java:253) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76) [jsf-impl-2.1.7-jbossorg-2.jar:]
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.7-jbossorg-2.jar:]
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) [jsf-impl-2.1.7-jbossorg-2.jar:]
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
	at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
	at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
	at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_35]
Share
  • Newsflash

    March 2012: We have change our site theme to F2.
  • Who's Online

    5 visitors online now
    5 guests, 0 members
    Powered by Visitor Maps