Skip to main content

Setting Up Connection Pooling With Elastic Beanstalk

    Amazon's Elastic Beanstalk is a service which automatically scales your application when needed. It uses Amazon's Elastic Compute Cloud (EC2) instances as deployable containers which when your app requires more resources more containers will be deployed. This removes the need to manually configure your EC2 instance whenever you need more connections or resources and attempts to add simplicity to the maintenance aspect of your application. So, when you get more users of your app, your app will scale accordingly.

    Unfortunately, along with the ability to scale automatically, comes less control and configuration. Things you would normally have the ability to configure to your liking, such as your server, you no longer can. Amazon attempts to address this issue with configuration files. You can provide configuration files which can set up your server. These files are either written in JSON or the horrible format YAML. Though these files provide some level of control, you can't use these files with a pre-configured Docker instance. For Java EE developers, the only provided instance from Amazon with full Java EE support is a pre-configured GlassFish Docker instance. So, if we program with Java, how can we configure our environment?

    One very common scenario for a developer is to setup a database for their application. Amazon provides an example of how to set up a database with Elastic Beanstalk using Java. The problem with this example is it manually creates and uses the connection. This would be fine in a Java SE application with only one user at a time. However, in an application that is hosted on the cloud and used by many users, this is inefficient. In such a situation you would create a Java EE application that will be hosted on a server that can be deployed on Elastic Beanstalk to handle scaling. But in this case, manually creating, closing, and handling each connection for every user and transaction would be error prone and inefficient. In a Java EE environment, you would use CDI (Context Dependency Inject) and JPA (Java Persistence API) to handle this work for you.

    In a normal Java EE environment (one where you have complete control over the server), you would go to your server admin console, and set up your connection pool to point to your database and a resource to point to the connection pool. Then, in your persistence.xml file, you would point to that created resource using its JNDI (Java Naming and Directory Interface) name. Then, wherever you needed to perform a database transaction, you would inject an EntityManager and perform the task you needed. Creating, closing, error and transaction handling, and thread management are all handled by the server (because of the use of JDBC and JPA).

    However, when Elastic Beanstalk scales it creates new EC2 instances each with their own server running your application. Because of this, manually creating the connection pool through the admin console (not that you can anyway) is inefficient and destroys the scalable paradigm Elastic Beanstalk implements. So, how can we set up connection pooling with Elastic Beanstalk? Also, back to our question before, how can we configure our [Elastic Beanstalk] environment? With the following tutorial, I'll answer both of these questions with a step-to-step guide.

Note: I will be using the most up to date Pre-configured GlassFish 4.1 Docker Instance running Java 8. Also, I will be connecting to a MySQL database instance running on Amazon's RDS. Though, this guide can easily be altered to suit any database need.

  • The first thing you want to do is set up your Elastic Beanstalk environment. Since I'm using RDS for hosting my database, when I set up my Elastic Beanstalk environment I can also set up my database which will be made available to the instance. So, log into the AWS console and select Elastic Beanstalk. Then look for the Actions button drop down in the top right corner of the screen. Press the button and select Launch New Environment. Next you will be provided with two choices for the type of environment you will be creating; choose Create Web Server. A pop-up will be displayed asking for permissions the environment will be created with; choose an appropriate IAM profile or the default. Then choose the pre-configured GlassFish Docker instance from the drop down (Note: you can use a pre-configured TomCat instance but configuration will be differently):
   
          Make sure Load balancing, auto scaling is selected in the next drop down (otherwise there's no point in using Elastic Beanstalk):

          The next thing it's going to ask you for is your application. If you don't already have a Java EE application, create one now just as a base to set up the environment (we'll add the functional connection pooling soon) and upload the WAR file. Then follow through with setting up the environment providing the details needed. The next important part for my scenario is creating the RDS database instance. Overall it's pretty straightforward setting up an Elastic Beanstalk environment. Once you do so, it will take a few minutes for the environment to launch.


  • Now, we need to create a glassfish-resources.xml file which is where we configure the connection pool and JDBC resources for the application. This file is placed in your applications WEB-INF folder:


          And here's an example of the file:



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <jdbc-connection-pool name="POOL_NAME" 
                          associate-with-thread="false"
            connection-creation-retry-attempts="0" 
            connection-creation-retry-interval-in-seconds="10"
           connection-leak-reclaim="false" 
           connection-leak-timeout-in-seconds="0" 
           connection-validation-method="auto-commit"
           datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
             fail-all-connections="false" 
             idle-timeout-in-seconds="300" 
             is-isolation-level-guaranteed="true" 
             lazy-connection-association="false"
           lazy-connection-enlistment="false" 
           match-connections="false" 
           max-connection-usage-count="0" 
           max-pool-size="32" 
           max-wait-time-in-millis="60000" 
           allow-non-component-callers="false"
           non-transactional-connections="false" 
           pool-resize-quantity="2" 
           res-type="javax.sql.ConnectionPoolDataSource" 
           statement-timeout-in-seconds="-1" 
           steady-pool-size="8"
           validate-atmost-once-period-in-seconds="0" 
           wrap-jdbc-objects="false">
        <property name="portNumber" value="3306"/>
        <property name="databaseName" value="YOUR_DATABASE_NAME"/>
        <property name="User" value="YOUR_DATABASE_USERNAME"/>
        <property name="Password" value="YOUR_DATABASE_PASSWORD"/>
        <property name="URL" value="jdbc:mysql://REPLACE_THIS_WITH_THE_URL_TO_YOUR_DATABASE"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    </jdbc-connection-pool>
    <jdbc-resource enabled="true" jndi-name="java:app/jdbc/CHOOSE_RESOURCE_NAME" object-type="user" pool-name="POOL_NAME"/>
</resources>


  • We can now reference this resource in our persistence.xml file. So, open your persistence.xml file, which should be located in the META-INF folder of your application:



          Note: If you see other files I don't specify that you don't have in your application file directories, ignore them for now.

          Your persistence file should look something like this:



<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
 <persistence-unit name="WebApplication" transaction-type="JTA">
  <jta-data-source>java:app/jdbc/YOUR_RESOURCE_NAME</jta-data-source>
                <properties>
   <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
   <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
  </properties>
 </persistence-unit>
</persistence>



  • Finally, the last step is to set up the MySQL JDBC library (Connector/J). Normally, you would place libraries in your applications build path, however, in this case, the library needs to be placed in GlassFish's library folder. In a normal environment you could just download the library and place it in the glassfish/domains/yourdomain/lib folder. But as stated earlier you don't have control of an Elastic Beanstalk environment like you do with your local machine. Also, since we're using a Pre-configured Docker instance, we can't use Amazon's configuration files. So, what we do is create a Dockerfile which is essentially a script that gets executed when the Docker environment is first being created (More information on Docker here). In the WebContent folder of your application, create a file called Dockerfile (no suffix):



# Use the AWS Elastic Beanstalk GlassFish image
FROM amazon/aws-eb-glassfish:4.1-jdk8-onbuild-3.5.1

EXPOSE 8080 3306

# Install MySQL dependencies
RUN curl -L -o /usr/local/glassfish4/glassfish/domains/domain1/lib/mysql-connector-java-5.1.35.jar https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.35/mysql-connector-java-5.1.35.jar

RUN /usr/local/glassfish4/bin/asadmin restart-domain

          The first line (excluding comments), FROM amazon/aws-eb-glassfish:4.1-jdk8-onbuild-3.5.1, specifies the Docker instance we will be executing commands on. The second line, EXPOSE 8080 3306, makes sure that the HTTP and MySQL ports are open on our Docker instance. The third line, RUN curl -L -o /usr/local/glassfish4/glassfish/domains/domain1/lib/mysql-connector-java-5.1.35.jar https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.35/mysql-connector-java-5.1.35.jar, downloads the library into the correct GlassFish directory. The fourth and final line, RUN /usr/local/glassfish4/bin/asadmin restart-domain, restarts the GlassFish server, this is essential for GlassFish to acknowledge the new library it has installed.


  • It's all set up, so now we can use CDI for creating EntityManager instances in our application that will handle transactions and execute queries:


@PersistenceContext(unitName = "WebApplication")
private EntityManager em;

          Now, we can deploy our application to our environment and we're all done!

Note: If your application won't load and you check the logs and you are getting a CommunicationsException it may have to do with the FireWall. I faced this problem, and I fixed it by changing my RDS VPN Security Group's inbound rules to allow for the Elastic Beanstalk environment's IP address.

If you wish to use a Pre-configured TomCat environment, the directions are similar but instead of a glassfish-resources.xml file, you would create a context.xml file, and you have the luxury of using configuration files. However, in such a scenario you would have to download the appropriate libraries for TomCat to make it a full Java EE server. Hopefully, you found this information useful. Before I wrote this tutorial I searched the internet for articles on how to do this and none seemed to exist, so, it was necessary. Now, you can create a real world application (as opposed to Amazon's useless "hello world" type examples) that is scalable!

Comments

Popular posts from this blog

Face detection and live filters

Live video filters are becoming a popular trend fueled by Facebook (through their purchase of Msqrd) and Snapchat incorporating the features into their apps. These filters apply images or animations to your face using face tracking software. This technology has been around for awhile but is becoming increasingly more common due to the powerful CPU's that our mobile phones now have. Google provides an API that provides face tracking abilities through the Google Play Services library called Mobile Vision. I'm going to use their API to build a basic live filter app. The end result will look something like this:


    The bounding box wraps around the detected face and the sunglasses are the filter I chose (which is just a PNG image) which are drawn over the eyes. You could use any PNG image (with alpha for the background) you want, you will just have to adjust the layout according to where the image should be displayed. As you move your head, the box and sunglasses are redrawn…

Android Guitar Tuner

Recently I created a guitar tuner application for Android that is written with pure Java (no C++ or NDK usage). The design was inspired by the Google Chrome team's guitar tuner web app using the WebAudio API. I wanted to code a version written natively for Android that didn't have to rely on a WebView, the WebAudio APIs, or server-side logic. Also, I wanted this application to be available to as many versions of Android as possible (whereas the WebAudio API may only be supported in more recent versions of WebView available only on newer flavors of Android). So, I coded it from scratch. I used a portion of the open source TarsosDSP project (their YIN algorithm) to help with the pitch detection.

    The application is available in the Google Play Store for Android: https://play.google.com/store/apps/details?id=com.chrynan.guitartuner. The project is completely open source and the code can be found on the GitHub repository: https://github.com/chRyNaN/Android-Guitar-Tuner. Fi…