Maximizing Heroku
You’ve gotten an application up and running, but how do you make sure it stays up and highly responsive?
Touring the Web Interface
A poweruser is going to use Toolbelt to do most everything from the terminal. But there are a lot of things you can do in the web interface. Let’s take a look at several of them including:
- scaling dyno numbers and size
- browse and manage add-ons
- display the deployment history
- control who has deployment access
- change the name, 404, domain names, and ownership
Scaling Web Dynos
Even with threading, the traffic a single dyno can serve is limited. The easiest way to scale the number of concurrent requests your application can handle is to increase the number of dynos.
Through the GUI
Option one is to use the graphical interface on Heroku.com. You should:
- Visit https://dashboard.heroku.com/apps
- Click the name of the application you want to manipulate
- Under "Dynos", slide the marker to the right
- Click "Apply Changes" (your account will really be debited by the minute)
From the CLI
Scaling through the GUI is cute, but it’s not fast and difficult to script. Maybe, for instance, you find that your traffic spikes during certain hours and want to scale up your dynos just for those hours. You could write a script to manipulate the dynos from the command line.
Within your project directory you can check on your current dynos:
Terminal
$ |
|
From that we know:
web (1X)
shows that we’re using Heroku’s smallest, cheapest dyno typetarget/start
is the actual command that is executed on the dynoweb.1
tells us that only a single dyno is running
From there you can do everything available in the GUI, such as changing the dyno type:
Terminal
$ |
|
And changing the number of dynos up to 8:
Terminal
$ |
|
And checking the results with ps
again:
Terminal
$ |
|
Now your dynos are twice as powerful, and there are eight times as many of them! Get back to the free settings with:
Terminal
$ $ $ |
|
Scaling in Action
In the sample application we’ve embedded a small test script that will make several requests to your application. Run it like this:
Terminal
$
|
|
And you will see output that starts like this:
Terminal
|
Note that the total response time is increasing linearly because the requests are queuing up for the single dyno.
Parallelizing with Dynos
Now let’s ramp up four dynos and see what happens:
Terminal
$
|
|
And run the test again:
Terminal
$ |
|
Your numbers will vary, but you will see greater variability in the total response time but all of them should be well under the slowest from the first run. Our requests are getting served by multiple dynos, balancing the load.
Scaling Memory
It turns out that the end point we’re hitting makes use of a lot of RAM. Our 1X dynos are struggling. Let’s scale up the memory available by using a 2X dyno and run the test again:
Terminal
$ $ |
|
You should observe your responses coming back even faster.
Using the Procfile
Heroku’s Cedar stack allows you a lot of flexibility through the Procfile
. You can define and name one or more commands that your application should run when deployed. We saw an example of a command to start the Play application earlier.
A Basic Procfile
Typically this starts with a web
server. A web
process type for a Play application looks like this:
1
|
|
- The
web
part defines the name of the process type - The part to the right of the
:
is what you’d run from a UNIX terminal to execute the command - Environment variables can be used (like
$PORT
and$RACK_ENV
here) - Runs the command
target/start
- Passes several options from the environment variables (
PORT
,JAVA_OPTS
,DATABASE_URL
) - Automatically runs the database "evolutions" if needed
Defining Multiple Process Types
If you want to run multiple dynos each running the same application, like eight instances of your web
process type, then you’re already done.
Commonly, however, you’ll want to run multiple different process types. An application, for instance, might want to have 16 dynos running the web
process to respond to web requests, then four dynos running as background workers sending email or doing other jobs.
You can define multiple process types in the Procfile
:
1 2 |
|
Other than web
to respond to requests, you can makeup whatever process names are germane to your domain. Whatever name you used can be used from the web interface or CLI to scale dynos up and down.
References
- Procfile configuration options on Heroku’s Dev Center
Configuration
Web applications typically rely on some pieces of data that either can’t or shouldn’t be stored in the source code. This might include:
- Resource locations, like the IP address of the database
- Security credentials, like OAuth tokens
- Execution environment markers, like "production" and "development"
These bits of data can be stored on Heroku and made available as environment variables.
Querying the Config
All apps start out with a default set of variables. From within a Heroku project’s directory on your local system, run heroku config
. The below example is from a Java Play application with some pieces removed for security:
Terminal
$ |
|
Note, particularly, the DATABASE_URL
which is the location of the PostgreSQL database provisioned for this application.
Adding a Value
Say we now want to store a key named OAUTH_SHARED_SECRET
on the server. We use heroku config:add
:
Terminal
$ |
|
Then we can query for the defined values again to verify it’s there:
Terminal
$ |
|
Accessing Values in Code
Defining those pieces of data is only useful if you can access them from your code. Below are examples for both Ruby and Java. The implementation will depend on your language of choice, not Heroku. Typically if you ask for a key that is not defined you’ll get back an empty string.
Java
In Java, accessing environment variables is as easy as calling System.getenv
and passing the name of the key:
Terminal
$ |
|
Considering Security
Environment variables are an appropriate place to store secure credentials, but you must keep in mind who has read access to them. Any of the following people could read your environment variables:
- Collaborators on an application
- A person who steals your laptop and can login as you and you have no SSH passphrase
- A person who accesses your computer while the SSH keychain is unlocked
If that’s a concern, then you can mitigate the issue by reducing deployment access. For instance, you could setup a Continuous Integration server which runs your tests and, if they pass, it deploys the code. The majority of developers wouldn’t need access to the Heroku application itself, so there’s less risk.
References
- Configuration Variables on Heroku’s Dev Center
Installing an Add-on / Upgrading Your Database
One of Heroku’s great strengths is the rich library of add-ons. There are dozen of options available at https://addons.heroku.com/ , giving you everything from data storage to video processing. Many of them can be installed/setup with little or no change to your application code.
Heroku offers many different data storage options, but most applications are centered around PostgreSQL. Let’s look at how to upgrade to a production-tier Postgres instance using the add-ons system.
PostgreSQL Levels
When you provision an application on Heroku it automatically comes with the Hobby-Dev level database.
Hobby-Dev Limitations
You should be aware that the free Hobby-Dev database has some significant limitations:
- It allows only 10,000 rows of data in aggregate across all tables
- It does not allow for "follower" databases, making backup more complex
- Max 20 connections
- 0mb of RAM
Standard-Yanari
We’ll upgrade to the Standard-Yanari level which:
- Costs $50/month
- Unlimited data rows, 64gb total data
- Follower databases enabled
- Max 60 connections
- 410mb RAM
From there it goes up and up. You can spend $6,000/month on an instance with 68gb of dedicated RAM and support for a terrabyte of data. You can see all the options here.
Replacement vs Migration
Let’s look at how to upgrade an application from the "Hobby Dev" to "Standard Yanari", the bottom level that Heroku considers "production scale."
There are different procedures for replacing the database with a new one versus migrating the existing data to a new instance. Let’s look at the easier of the two, full replacement.
Checking the Before-State
Before we start changing things around, let’s look at the existing application configurations DATABASE_URL
and HEROKU_POSTGRESQL
keys:
Terminal
|
When we add a new database that JADE
URL will stick around. This allows us to connect to the old database, in this case a free instance, if we wanted to access old data.
If, however, the old database were a paid plan, we’d keep getting charged until it’s deprovisioned.
Using pg:info
The key name is a random color and doesn’t tell you anything about what actual database type is at that address. For much more useful information, we can use pg:info
:
Terminal
$ |
|
If your application had more than one PostgreSQL database then there’d be more than one listing here.
Provisioning
To add the new database instance we just need a single instruction:
Terminal
$ |
|
As instructed, you can run heroku pg:wait
which will hang until the new instance is ready.
Terminal
$ |
|
Now you’re ready to actually use it.
Configuring
Your application, either through the Procfile
or code itself, should be relying on the DATABASE_URL
environment variable. Therefore, using this database should be as easy as:
- Change the
DATABASE_URL
variable to the newly provisioned instance - Restart the application
- Run any data migrations / evolutions
Change the DATABASE_URL
If you run heroku config
again, you’ll see the new database location defined:
Terminal
$ |
|
Then unset
the DATABASE_URL
…
Terminal
$ |
|
And set it using the value of HEROKU_POSTGRESQL_ROSE_URL
from above:
Terminal
$ |
|
Migrating / Evolving
At this point you’ve got a blank database. If you’re deploying a Rails application, you’d want to run your migrations:
Terminal
$
|
|
If you’re running a Play application with auto-apply evolutions enabled, then they’ll be run on the first request.
Deprovisioning
Please carefully think through what you’re doing before following these instructions. If you deprovision a database on Heroku you cannot get the data back.
That production-quality instance we just added upped our bill by $50/month. That far exceed the budget of a little sample application. Let’s undo it:
- Change the
DATABASE_URL
back to the free instance - Remove the Yanari instance
It’s the reverse of what we did before:
Terminal
$ $ |
|
Where the URL in step two was our original HEROKU_POSTGRESQL_JADE_URL
.
The add-on removal will ask you for a confirmation. Consider that a person who has access to your application could similarly drop the production database.
References
Setting Up Custom Domains
Heroku’s haiku-inspired generated URLs like "boiling island" are cute, but most of the time you’ll want to use a custom domain you’ve purchased elsewhere.
Adding a Domain Name
Add the domain names like this:
Terminal
$ $ |
|
Note that, yes, you need both if you want both http://example.com and http://www.example.com to resolve to your application.
DNS Configuration
Your DNS settings are likely controlled by the registrar you used to purchase the domain (like http://dnsimple.com or http://namecheap.com). You’ve configured Heroku to listen for requests to those domains, but you need to configure the DNS server to send the traffic to Heroku in the first place.
The exact settings and process will vary per registrar, but essentially you want to create a CNAME record pointing to your application’s herokuapp
URL, like boiling-island-2815.herokuapp.com
.
References
- Custom Domains on Heroku’s Dev Center