Josh Thompson     about     archive     turing     office hours

How to Run Your Rails App in Profiling Mode

Last time, I wrote about setting up DataDog for your Rails application. Even when “just” running the app locally, it is sending data to DataDog.

This is super exciting, because I’m getting close to being able to glean good insights from DataDog’s Application Performance Monitoring tool.

For a variety of reasons, I want to run DataDog against the app as it is running locally, on my laptop. This will scale up to monitoring all this in production, but for now, I can rapidly experiment, and since we’re not deploying anything (yet) I can freely experiment with gathering/interpreting all this data locally.

The problem with running the app locally is it’s usually running on development mode, which means Rails does lots of stuff to make local development easier, but which makes actual page load time take longer.

Nate covered how to configure your app to run it in a “production-like” environment, locally, but I got tripped up in some of the minor details involved with porting generalized instructions to our specific codebase.

So, today, I’m going to explain how to run the app locally in a way that mimics production. Some of this will be specific to our app, but I some of it could be useful to anyone else with a Rails app

Required changes to config/development.rb

Nate suggested setting these options in development.rb:

# config/environments/development.rb
config.cache_classes = true
config.eager_load = true
config.serve_static_files = true # 4.2 or less
# config.public_file_server.enabled = true # 5.0 or more
config.assets.compile = false
config.assets.digest = true
config.active_record.migration_error = false
>> Read more

Setting up Application Performance Monitoring in DataDog in your Rails App

When I write guides to things, I write them first and foremost for myself, and I tend to work through things in excruciating detail. You might find this to be a little too in-depth, or you might appreciate the detail. Either way, if you want a step-by-step guide, this should do it.

As mentioned in Load Testing your app with Siege, I want to get Application Performance Monitoring in place for our app. We use Rails.

To someone who doesn’t know much about this space, there was more friction than I expected.

I’ll wander around, get everything set up, and outline any places that I bump into stuff.

First, DataDog has a handy video about how to configure your app to use APM:

https://docs.datadoghq.com/videos/rails/

Unfortunately, the link they give in the video to https://app.datadoghq.com/apm/docs redirects to https://app.datadoghq.com/apm/intro, which fails to tell you how to find the actual docs. 🙄

So, I found https://docs.datadoghq.com/tracing/, which don’t look anything like what’s in the video. Docs go out of date, this isn’t a problem.

It looks like the setup involves a few steps:

  1. Enable Trace collection in the Datadog Agent
  2. Instrument your application to send traces to your Datadog Agent
  3. Enable Trace Search & Analytics
  4. Enrich tracing

I don’t know that we’ll get to step 4, but 1-3 look great.

Enable Trace collection in the Datadog Agent

There’s a lot of complexity boiled into this short little paragraph:

Install and configure the latest Datadog Agent. (On macOS, install and run the Trace Agent in addition to the Datadog Agent. See the macOS Trace Agent documentation for more information). APM is enabled by default in Agent 6, however there are additional configurations to be set in a containerized environment including setting apm_non_local_traffic: true. To get an overview of all the possible settings for APM including setting up APM in containerized environments such as Docker or Kubernetes, get started Sending traces to Datadog.

>> Read more

Load Testing your app with Siege

Last time, I dug into using Apache Benchmark to do performance testing on a page that requires authentication to access.

Today, we’ll figure out how to use siege to visit many unique URLs on our page, and to get benchmarks on that process. I’ll next figure out performance profiling in Datadog, and with these three tools put together, we should be ready to make some meaningful improvements to our application.

This series of posts is a direct result of Nate Berkopec’s The Complete Guide to Rails Performance, with aid from his screencasts, as well as Steve Grossi’s Load Testing Rails Apps with Apache Bench, Siege, and JMeter. Armed with these resources, and standing on shoulders of giants, off we go.

Siege’s description:

Siege is an http load testing and benchmarking utility. It was designed to let web developers measure their code under duress, to see how it will stand up to load on the internet. Siege supports basic authentication, cookies, HTTP, HTTPS and FTP protocols. It lets its user hit a server with a configurable number of simulated clients. Those clients place the server “under siege.”

You can get siege with brew install siege.

I’m using it because it can run a list of URLs you give it. Imagine your app is a store, and it lists a few thousand products. Each product should have a unique URL, something like www.mystore.com/product-name, or maybe www.mystore.com/productguid-product-name. That product-guid makes sure that you can have unique URLs, even if there are two items with the same product name.

Knowing what’s in your database, you can easily concat product-guid and product-name, stick it to the end of www.mystore.com, and come up with a list of a hundred or a thousand or ten thousand unique product URLs in your application. If you saved these to a text file and had Siege visit every single one of those pages as quickly as possible… this might look like some sort of good stress test, huh?

Dumping unique URLs into a text file

You’ll probably start working in a rails console session, to figure out how to access the URL scheme just right.

I fired up the console, and entered:

File.open("all_campaign_urls.txt", "w") do |file|
  # this opens the file in write mode; will over-write contents of file if it exists
  Campaign.where(account_id: 4887).find_each do |campaign|
    puts "writing " + "http://localhost:3000/account/campaigns/" + campaign.to_param
    file.puts "http://localhost:3000/account/campaigns/" + campaign.to_param
  end
end
>> Read more

Benchmarking a page protected by a login with Apache Benchmark

I’ve been slowly working through The Complete Guide to Rails Performance. I’m taking the ideas and concepts from Nate’s book and working on applying the lessons to the app I work on in my day job.

I had a chance to attend Nate’s workshop in Denver a few days ago, as well; while there, we fired up our apps in production-like mode, and used wrk, a HTTP benchmarking tool, to see how many pages our app could serve in a given amount of time. (wrk docs).

A normal wrk run might look like so:

$ wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html

wrk will run for a [t]hread count of 12, with 400 [c]onnections, for a [d]uration of 30 seconds, against 127.0.0.1:8080/index.html

This is fine for testing unprotected home pages, but the app I work on requires a login before getting to anything interesting. So, I wondered

how does one use a HTTP benchmarking tool against an application with a login page?

And I found the answer.

Apache Benchmark

Apache Benchmark describes itself as [an] Apache HTTP server benchmarking tool. Similar to wrk, but a bit more feature-rich.

You can use it very similarly to wrk - give it a thread count, connection count, duration, and address, and it’ll hammer that page and serve up all sorts of good results.

The “rule of thumb” for benchmarking “protected” pages is:

Whatever page you can access locally in an incognito browser is what your benchmarking tool can hit without any special authentication.

In other words, when I visit http://localhost:3000/ locally, I get redirected to http://localhost:3000/users/sign_in. This is fine for apache bench, if I want to test how quickly our sign-in page loads. I can run:

$ ab -t 10 http://127.0.0.1:3000/

which returns:

>> Read more

Deliberate Practice in Programming with Avdi Grimm and the Rake gem

I’ve had the concept of Deliberate Practice stuck in my head for a while.

I want to improve at things (all the things!) in general, but writing and reading code, specifically. Writing and reading code is germane to my primary occupation (software developer) and drives most of my effectiveness on my team.

If there are two people, one who knows more about something, and one who knows less, but the person who knows less is learning new things faster than the other person, in short order, they’ll switch places.

This concept comes from John Ousterhout, and his talk at Stanford about how the slope is more important than y-intercept.

slope and intercept

I know how to write the code I know how to write; I don’t know how to write better code than that. So, I’m taking advantage of code written by people who are really good at what they do, and I’m modeling my code after them.

Deliberate Practice

I’m trying to apply the principles of deliberate practice to writing code.

Eric Anders coined the term Deliberate Practice, and it boils down to four components:

  1. You must be motivated to attend to the task and exert effort to improve your performance.
  2. The design of the task should take into account your pre-existing knowledge so that the task can be correctly understood after a brief period of instruction.
  3. You should receive immediate informative feedback and knowledge of results of your performance.
  4. You should repeatedly perform the same or similar tasks.
>> Read more