Shiny: Load testing and horizontal scaling

“Money can’t buy you happiness, but it can buy you more EC2 Instances…” – With this quote Sean Lopp, Product Manager at RStudio, PBC, rang in his “Scaling Shiny” showcase. In this showcase, he uses a load-testing approach to show how a Shiny application can be scaled for 10,000 users. RStudio’s shiny WebApp framework is an R package that allows you to create interactive web applications directly from R. It has long been established as a powerful web application development tool for R developers around the world, whether for business applications, online reporting or data management. It is not only reserved for small development teams, but is also increasingly being made available to a wide range of employees throughout the company. In part 1 of our blog series we will share our own experiences regarding the scaling of our test application. In addition, explanations will be provided that have emerged from this project.

Setup - Architecture, Load Testing Tools & Test Application

At the heart of the system are two RStudio Connect servers and a load balancer that simultaneously provides a shared file system and postgres database for the Connect servers.

We use the R package shinyloadtest provided by RStudio and the associated Java application shinycannon as load testing tools.

The functionality of the tools can be explained by the figure above:

The package shinyloadtest offers the possibility to open a shiny application and record a user session of any length. The recorded session can then be used for load testing by providing a link to the shinycannon application. A fixed number of users (so called “workers”) is specified, who try to execute the recorded session on the server as often as possible within a selected time period. Finally, a report can be generated from the collected data of the load test, which will be discussed in the next paragraph.

Test application

server <- function(input, output) {

output$distPlot <- renderPlot({

x <- rep.int(faithful[, 2], times = 1000)
bins <- seq(min(x), max(x), length.out = input$bins + 1)

hist(x, breaks = bins, col = 'darkgray', border = 'white')

})

}

Our test application is hardly different from the Shiny sample application, except for the amount of data used for the histogram. This ensures that each started session always generates enough load.

Sessions Session Duration Event Waterfall Latency Event Duration Event Concurrency

Conclusion & Outlook

The step from a prototype to a business application can bring many hurdles that need to be overcome during the scaling process. In many cases, not only the usability/load capacity of the app, but also smaller problem areas are scaled to significant problems. These can also result in an unstable or faulty application. A detailed load testing can be an essential aid in identifying and eliminating potential weaknesses early enough before the application goes live. How exactly this troubleshooting can look like will be examined in parts 2 to 4 of our blog series, where we deal with the in-app optimization of Shiny applications.

We would be pleased to support you within the scope of our eoda | analytic infrastructure consulting in scaling processes in the data science context in your company.