Shiny: Load Testing und Horizontale Skalierung

„Money can’t buy you happiness, but it can buy you more EC2-Instances…“– Mit diesem Satz läutete Sean Lopp, Product Manager bei RStudio, PBC, seinen „Scaling Shiny“ Showcase ein. In diesem zeigt er mittels eines Load-Testing-Ansatzes, wie eine Shiny-Applikation für 10.000 Nutzer skaliert werden kann. RStudio’s hauseigenes WebApp-Framework shiny ist ein R-Paket, mit dem sich interaktive Webanwendungen direkt aus R heraus erstellen lassen. Es hat sich schon lange als mächtiges Tool zur Entwicklung von Webanwendungen für R-Entwickler auf der ganzen Welt etabliert, sei es für Business-Applikationen, Online-Reports oder Datenmanagement. Diese werden nicht nur kleinen Entwicklerteams vorbehalten, sondern sollen immer öfter firmenweit für eine breite Masse an Mitarbeitern zugänglich gemacht werden. In Teil 1 unserer Blogserie werden wir unsere eigenen Erfahrungen bezüglich der Skalierung unserer Test-Applikation wiedergeben. Zudem werden Erklärungen geliefert, die aus dem Projekt entstanden sind.

Setup – Architektur, Load-Testing-Tools & Testanwendung

Im Zentrum stehen dabei zwei RStudio-Connect Server und ein Load-Balancer, welcher gleichzeitig ein geteiltes Dateisystem und eine Postgres-Datenbank für die Connect-Server zur Verfügung stellt.

Als Load-Testing-Tools verwenden wir das von RStudio zur Verfügung gestellte R-Paket shinyloadtest und die zugehörige Java-Applikation shinycannon.

Die Funktionsweise der Tools lässt sich anhand des obigen Bildes erklären:

Das Paket shinyloadtest bietet die Möglichkeit, eine Shiny-Applikation zu öffnen und eine beliebig lange Nutzer-Session aufzuzeichnen. Die aufgezeichnete Session kann dann unter Angabe eines Links zur Applikation von shinycannon zum Load-Testing verwendet werden. Dabei wird eine feste Anzahl von Nutzern (sog. „Workern“) angegeben, welche in einem gewählten Zeitraum so oft wie möglich versuchen die aufgezeichnete Session auf dem Server auszuführen. Zum Schluss kann aus den gesammelten Daten des Load-Tests ein Report generiert werden, welcher im nächsten Abschnitt genauer betrachtet wird.

Testanwendung

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')

})

}

Unsere Test-Applikation unterscheidet sich im Wesentlichen kaum von der Shiny-Beispielapplikation, bis auf die für das Histogramm verwendete Datenmenge. Dies stellt sicher, dass jede gestartete Session stets ausreichend Belastung generiert.

Sessions Session Duration Event Waterfall Latency Event Duration Event Concurrency

Fazit & Ausblick

Der Schritt vom Prototyp zur Business-Applikation kann viele Hürden mit sich bringen, die es im Laufe des Skalierungsprozesses zu bewältigen gilt. In vielen Fällen werden nicht nur die Nutz- und Belastbarkeit der App, sondern auch kleinere Problemstellen zu signifikanten Problemen skaliert. Diese können ebenfalls eine instabile oder fehlerhafte Applikation zur Folge haben. Ein detailliertes Load-Testing kann dabei eine essenzielle Hilfestellung leisten, potenzielle Schwachstellen früh genug zu erkennen und zu beseitigen, bevor die Applikation in den Produktivbetrieb geht. Wie genau diese Problembehandlung aussehen kann, werden wir in Teil 3 und Teil 4 unserer Blogserie unter die Lupe nehmen, in denen wir uns mit der In-App-Optimierung von Shiny-Applikationen beschäftigen. Unser theoretischer Artikel legt Ihnen den Grundstein für das selbstständige Testen der App. Außerdem zeigen wir Ihnen im zweiten Teil unserer Blogserie, wie sich YUNA und Shiny gegenseitig ergänzen und welche Vorteile daraus resultieren.

Gern unterstützen wir Sie im Rahmen unseres eoda | analytic infrastructure consulting bei Skalierungsprozessen im Data-Science-Kontext in Ihrem Unternehmen. Erfahren Sie mehr über unsere Leistungen rund um das Thema Shiny.