<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/alternative-approaches-to-scaling-shiny-with-rstudio-shiny-server-shinyproxy-or-custom-architecture/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://appsilon.com/alternatives-to-scaling-shiny/"> r – Appsilon Data Science | End­ to­ End Data Science Solutions</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<div><img sizes="(max-width: 600px) 100vw, 600px" src="https://i1.wp.com/appsilon.com/assets/uploads/2018/12/Scaling-Shiny-600x418.png?w=450&ssl=1" alt="" class="wp-post-image" data-recalc-dims="1"></div>
<div><img width="1" src="https://www.google-analytics.com/collect?v=1&tid=UA-46680230-1&cid=*%7CUNIQID%7C*&t=event&ec=repost&ea=open&cm=reposting&cn=Alternative%20approaches%20to%20scaling%20Shiny%20with%20RStudio%20Shiny%20Server,%20ShinyProxy%20or%20custom%20architecture." height="1/"></div>
<p>Shiny is a great tool for fast prototyping. When a data science team creates a Shiny app, sometimes it becomes very popular.<span> From that point this app becomes a tool used on production by many people, that</span><span> should be reliable and work fast for many concurrent users.</span> There are many ways to optimize a Shiny app like <a rel="nofollow" href="https://appsilon.com/an-example-of-how-to-use-the-new-r-promises-package/" target="_blank">using promises</a> for non-blocking access, <a rel="nofollow" href="https://rstudio.github.io/profvis/" target="_blank">profvis</a> for finding bottlenecks, and <a rel="nofollow" href="https://shiny.rstudio.com/articles/modules.html" target="_blank">shiny modules</a> for well-structured code, etc. Regardless of this, the main aspect you should focus on how you serve the application.</p>
<h1>Why is scaling Shiny tricky?</h1>
<h2>R is single-threaded</h2>
<p>This means all users connected to one R process will block each other. <u><a rel="nofollow" href="https://en.wikipedia.org/wiki/Thread_(computing)#Multithreading" target="_blank">Multithreading allows for application responsiveness</a>,</u> and by design, R doesn’t. You have to use workarounds to provide it.</p>
<p>For example, you can do this by serving multiple instances of the app. Also, a <u><a rel="nofollow" href="https://rstudio.github.io/promises/articles/intro.html" target="_blank">promises package</a></u> can be used to improve responsiveness, but it is still fundamentally different than promises in JavaScript. JavaScript promises are different thanks to the event loop mechanism, which features fully asynchronous I/O and worker threads.</p>
<h2>R is slow. It was designed for convenient data analysis, not for webapps.</h2>
<p>R language was created to make data analysis faster. It proved its power, and that’s why it is the tool of choice for many data scientists. However, faster analysis doesn’t mean better performance.</p>
<p>Data analysis in R is fast because of convenient syntax and the amazing amount of useful statistical packages, but the language execution time itself is slow. A detailed explanation of this is covered by Hadley Wickham in <u><a rel="nofollow" href="http://adv-r.had.co.nz/Performance.html" target="_blank">this article about R performance</a></u>. There are also many benchmarks on <u><a rel="nofollow" href="https://www.sas.upenn.edu/~jesusfv/comparison_languages.pdf" target="_blank">what the speed of R</a></u> is.</p>
<p>Personally, I am excited by alternative implementations of R language, which aim to improve performance. One of them is <u><a rel="nofollow" href="https://github.com/oracle/fastr" target="_blank">Oracle FastR</a></u> based on <u><a rel="nofollow" href="https://medium.com/graalvm/faster-r-with-fastr-4b8db0e0dceb" target="_blank">GraalVM</a></u>, and another is JVM-based <u><a rel="nofollow" href="http://www.renjin.org/" target="_blank">Renjin</a></u>. Currently, they are still evolving, but I believe their time will come soon.</p>
<h1>Four ways how you can serve Shiny</h1>
<p>Many people ask us what the effective options are for serving a Shiny app, especially for a large number of users. The industry standard tool for enterprises is RStudio Shiny Server Pro and it costs $9,995/year for 20 concurrent users. It is mature, powerful solution, which we often recommend to our clients.</p>
<p>However, this is not the only possibility.</p>
<p>Before you make a decision on how to scale your app to multiple users, it is important to understand what your needs are:</p>
<ul>
<li>What is the app initialization time?</li>
<li>Does it load a lot of data into memory on startup?</li>
<li>What is the app complexity?</li>
<li>How heavy are the calculations?</li>
<li>What is the expected behavior of users?</li>
</ul>
<p>Answering these questions will help you choose the best fit for your use case.</p>
<p>Now, let’s see what options are available to you:</p>
<h2>(1) Shiny Server Open Source</h2>
<p><a rel="nofollow" href="https://github.com/rstudio/shiny-server" target="_blank">Shiny Server Open Source</a> is limited to one R process per app, which potentially can serve multiple user sessions (connections to the app). This is totally fine for apps that don’t have many users, but it doesn’t work well for apps that will have large amounts of users. When you have many users, they all will be served by one process and will inevitably block each other.</p>
<p>This architecture is visualized by the following diagram:</p>
<p><img alt="Shiny Server Open Source scaling" src="https://i1.wp.com/appsilon.com/assets/uploads/2018/12/Shiny-Server-Opensource.png?w=450&ssl=1" class="wp-image-1576" data-recalc-dims="1"></p>
<h2>(2) Shiny Server Pro</h2>
<p>In contrast, on <a rel="nofollow" href="https://www.rstudio.com/products/shiny-server-pro/" target="_blank">Shiny Server Pro</a>, you can have multiple R processes per app. This means that many concurrent users can be distributed between separate processes and are served more efficiently. As there is no limitation on the number of processes, you can make use of all your machine resources.</p>
<p>On Shiny Server Pro, you can configure a strategy on how resources should be handled with `utilization_scheduler` parameter.</p>
<p>For example, you can set:</p>
<ul>
<li>The maximum R process capacity, i.e. the number of concurrent users per single R process;</li>
<li>The maximum number of R processes per single app;</li>
<li>When the server should spawn a new R process, e.g. when existing processes reach 90% of their capacity.</li>
</ul>
<p>Below you can see an example situation:<br>
<img alt="shiny server pro scaling" src="https://i2.wp.com/appsilon.com/assets/uploads/2018/12/Shiny-Server-Pro.png?w=450&ssl=1" class="wp-image-1577" data-recalc-dims="1"></p>
<p>In this scenario, five users want to access the app. Shiny Server Pro initializes three worker processes, and users are distributed between them.</p>
<h2>(3) ShinyProxy</h2>
<p><u><a rel="nofollow" href="https://www.shinyproxy.io/" target="_blank">ShinyProxy</a></u> from <u><a rel="nofollow" href="https://channel9.msdn.com/Events/useR-international-R-User-conferences/useR-International-R-User-2017-Conference/ShinyProxy" target="_blank">OpenAnalytics</a></u> is an open source alternative for serving Shiny apps. It provides many features required by enterprise applications. Its architecture is based on <u><a rel="nofollow" href="https://www.shinyproxy.io/shinyproxy-containers/" target="_blank">docker containers</a></u>, which isolate the app’s environment and can serve not only Shiny apps but <u><a rel="nofollow" href="https://github.com/openanalytics/shinyproxy-dash-demo" target="_blank">other apps, too (like Dash)</a></u>.</p>
<p>The key difference is that ShinyProxy starts a new app instance for each new user. The architecture is straightforward, convenient, and easy to maintain. This is how it looks on a diagram:</p>
<p><img sizes="(max-width: 889px) 100vw, 889px" src="https://i0.wp.com/appsilon.com/assets/uploads/2018/12/ShinyProxy.png?w=450&ssl=1" alt="ShinyProxy scaling" class="wp-image-1578" data-recalc-dims="1"></p>
<h2>(4) Custom architecture like Appsilon Revolver</h2>
<p>Sometimes deploying a Shiny app requires a custom solution. Let’s say we have a Shiny app that takes 60 seconds to initialize, and that time amount is deemed as an unacceptable wait time for a user. In this situation, starting an app instance for each user is not the way to go.</p>
<p>At Appsilon, we create custom architectures for Shiny apps. In many cases, we recommend Shiny Server or ShinyProxy because they are often the right tool for a given task. However, there are exceptions.</p>
<p>One of our custom architectures is a project code-named “Revolver.” We wanted to create a scalable architecture for a Shiny app that takes a long time to initialize and performs a lot of heavy computations. It is not a standalone product, and it was first designed for one of our clients. Since then, we’ve used it to deploy several production apps.</p>
<p>Here is how it looks:</p>
<p><img sizes="(max-width: 889px) 100vw, 889px" src="https://i0.wp.com/appsilon.com/assets/uploads/2018/12/Revolver.png?w=450&ssl=1" alt="Revolver scaling shiny" class="wp-image-1579" data-recalc-dims="1"></p>
<p> </p>
<p>This approach uses docker containers that serve the application using Shiny Server Open Source. In front of application instances, there is a load balancer that distributes the traffic.</p>
<p>The difference between our product and ShinyProxy is that there are N pre-initialized containers that wait for user connections. The number of containers is configured by the app admin and can be auto-adjusted. The advantage of this approach is that the app is served instantly. Users do not have to wait for the app initialization.</p>
<p>It is also worth noting that this custom architecture supports SSL connection, authentication, and other enterprise requirements.</p>
<h2>Cheat Sheet</h2>
<p>I hope this article on the possible solutions for scaling Shiny apps to many concurrent users was helpful to you. If you’d like to chat about a specific use case, you can contact us through <a rel="nofollow" href="https://appsilon.com/shiny" target="_blank">https://appsilon.com/shiny</a></p>
<p>Below, we have compiled the information shared above into a comparison cheat sheet diagram. Again, I hope it helps!</p>
<p><img sizes="(max-width: 1218px) 100vw, 1218px" src="https://i0.wp.com/appsilon.com/assets/uploads/2018/12/Scaling-Shiny-1.png?w=450&ssl=1" alt="Scaling Shiny" class="wp-image-1580" data-recalc-dims="1"></p>
<p>Article <a rel="nofollow" href="https://appsilon.com/alternatives-to-scaling-shiny/" target="_blank">Alternative approaches to scaling Shiny with RStudio Shiny Server, ShinyProxy or custom architecture.</a> comes from <a rel="nofollow" href="https://appsilon.com/" target="_blank">Appsilon Data Science | End­ to­ End Data Science Solutions</a>.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://appsilon.com/alternatives-to-scaling-shiny/"> r – Appsilon Data Science | End­ to­ End Data Science Solutions</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/AzdCXMqv0kg" height="1"></a></div>