5. Content Performance
In this section, you will learn:
- How to triage content performance issues
- How different programming languages impact performance
- About runtime settings and examples for different use cases
- How to advise developers on improving app performance
- When to consider async programming
Triaging Performance Issues
When dealing with reported performance issues a good first step is to gauge whether slowness is a system-wide performance issue or something specific to a piece of content.
For system-wide issues refer to the Managing Resources and the Scaling sections of this course.
For suspected broken apps see the section on Troubleshooting which outlines how to consult your developers in debugging broken apps and using the content and server logs.
On Developing Performant Apps
You may be asked to debug performance for pieces of content where the most performance gain will happen by improving the content itself. There are a couple of tips to offer to your developers.
R and Python are single-threaded
Python and R are single-threaded languages. Meaning that while a process is shared across multiple connections only one task at a time will be run on that process. When users open connections to the content hosted on Connect there will be moments where their application waits for a task supporting a different user to complete before itβs their turn to run. Usually, this is barely noticeable, since most tasks complete quickly. However, in applications and APIs with high usage and long-running tasks, like data processing, performance issues may occur. This performance impact is independent of server resources or the Connect software.
There are packages developers can use to make R and Python content run asynchronously, but there are several other strategies to consider. Async programming is often a last resort as it can be the most challenging to implement.
Runtime Settings
Changing runtime settings is a balance between protecting server resources and supporting pieces of content. This support article explains process scheduling and provides some guidelines. Details for each setting are included in the Runtime/Scheduler configuration appendix of the Posit Connect Admin Guide.
There are a couple of key terms and parameters to define:
- Connections: A channel between a user and a piece of content
- Process: Running R or Python process on the server which connections to applications and APIs utilize.
- Max processes: Maximum number of processes that will be allowed to be created.
- Min processes: Minimum number of processes that will always be kept running.
- Max connections per process: Maximum allowed connections per process. Total concurrent sessions possible will be
Max processes x Max connections per process
. - Load factor: How pre-emptively new processes will be created where lower values (0) mean more aggressive process spin-up and higher values (1) are less aggressive.
Some tips and examples for how the runtime settings can be utilized:
- One way to immediately see improvements in performance for content is to decrease the number of allowed connections. For example, decreasing it to 1 would immediately give each connection its dedicated process, however, doing this will increase system resource usage.
- Setting the min processes to 1 or greater will ensure that applications and APIs are already running before the first user arrives.
Profiling and load testing
Have your developers profile their content to understand where the bulk of the time is being spent. Oftentimes the result is surprising and may point at a specific function or data loading task that can be reworked.
Using load testing together with profiling grants a very granular view of where the performance issues are happening. Often lower usage apps appear to have great performance, only to struggle as more users access that piece of content due to multiple users sharing the same R or Python process.
Async Programming
Improving scalability with async programming in R
When using async, encouraging developers to include additional debug messages, for example with log4r in R, is particularly important. This will allow developers to trace back errors to the session and connection
However, in general, async is only useful when there are specific steps that take a long time to run since that will free up the process to service other users. Usually async is saved as a last resort because it is usually the most challenging to implement.
Case Study
Take this example showing the troubleshooting process of a Shiny for R app as led by the founder of Shiny, Joe Cheng.
- Cran Whales writeup: https://rstudio.github.io/promises/articles/casestudy.html
- Cran Whales talk: https://www.youtube.com/watch?v=Wy3TY0gOmJw
Exercise
π Launch the exercise environment!
In the exercise environment you will get experience:
- Changing runtime settings for content
- Exploring the impact of changing runtime settings
- Setting server-level runtime defaults and limits
Go to: 6. Data Access