-
-
Notifications
You must be signed in to change notification settings - Fork 573
docs: Add section in load balancing about Bokeh extensions #7832
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0e380fe
d99c06e
f2cb837
7554afb
f510a46
e1c0e3d
6e69987
0d89e89
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,12 +1,158 @@ | ||||||
| # Load balancing | ||||||
|
|
||||||
| Setting up load balancing is a huge topic dependent on the precise system you are using so we won't go into any specific implementation here. In most cases you set up a reverse proxy (like NGINX) to distribute the load across multiple application servers. If you are using a system like Kubernetes it will also handle spinning up the servers for you and can even do so dynamically depending on the amount of concurrent users to ensure that you are not wasting resources when there are fewer users. | ||||||
| Setting up load balancing is a huge topic, dependent on the precise system you | ||||||
| are using, so the example below will be very generic. In most cases | ||||||
| you set up a reverse proxy (like NGINX) to distribute the load across multiple | ||||||
| application servers. If you are using a system like Kubernetes, it will also | ||||||
| handle spinning up and shutting down the servers for you, and can even do so dynamically, depending | ||||||
| on the amount of concurrent users to ensure that you are not wasting resources | ||||||
| when there are fewer users, and / or when there is less computing demand. | ||||||
|
|
||||||
| <figure> | ||||||
| <img src="https://www.nginx.com/wp-content/uploads/2014/07/what-is-load-balancing-diagram-NGINX-1024x518.png" width="768"></img> | ||||||
| <img src="https://assets.holoviz.org/panel/how_to/concurrency/what-is-load-balancing-diagram-NGINX.png" width="768"></img> | ||||||
| <figcaption>Diagram showing concept of load balancing (NGINX)</figcaption> | ||||||
| </figure> | ||||||
|
|
||||||
| Load balancing is the most complex approach to set up but is guaranteed to improve concurrent usage of your application since different users are not contending for access to the same process or even necessarily the same physical compute and memory resources. At the same time it is more wasteful of resources since it potentially occupies multiple machines and since each process is isolated there is no sharing of cached data or global state. | ||||||
| Load balancing is the most complex approach to set up but is guaranteed to | ||||||
| improve concurrent usage of your application since different users are not | ||||||
| contending for access to the same process or even necessarily the same physical | ||||||
| compute and memory resources. At the same time it is more wasteful of resources | ||||||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| since it potentially occupies multiple machines and since each process is | ||||||
| isolated there is no sharing of cached data or global state. | ||||||
|
|
||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should there be a mention that Tornado is used by default, and that Django, Flask and FastAPI are also options? I am not sure if and how using one of these four (or more)? options relates to concurrency / load balancing, but should this at least be mentioned, with links to the Panel docs for use of Flask and FastAPI?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would not mention it, as it has nothing to do with load balancing. |
||||||
| To get started configuring a load balancer take a look at the [Bokeh documentation](https://docs.bokeh.org/en/latest/docs/user_guide/server/deploy.html#load-balancing) which provides example configurations for Apache and NGINX. | ||||||
| To get started configuring a load balancer take a look at the [Bokeh | ||||||
| documentation](https://docs.bokeh.org/en/latest/docs/user_guide/server/deploy.html#load-balancing). | ||||||
philippjfr marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ## Use NGINX and Containers with Panel along with other Bokeh extensions | ||||||
|
|
||||||
| Panel is built on top of Bokeh and uses the Bokeh server to serve applications. To serve Panel-specific resources, Panel is defined as a Bokeh extension. | ||||||
| While Panel's resources are available via a CDN, other Bokeh extensions may require being served directly by the Bokeh server. | ||||||
| To enable this, set the `BOKEH_RESOURCES` environment variable to `server`. | ||||||
|
|
||||||
| An example is given below with [ipywidget_bokeh](https://github.com/bokeh/ipywidgets_bokeh) as a Bokeh extension - but this will also work for other Bokeh extensions. | ||||||
|
|
||||||
| ### Files | ||||||
|
|
||||||
| ::::{tab-set} | ||||||
|
|
||||||
| :::{tab-item} app.py | ||||||
|
|
||||||
| ```python | ||||||
| import ipywidgets | ||||||
| import panel as pn | ||||||
|
|
||||||
| pn.Row(ipywidgets.HTML("This is an IPywidget served with Panel")).servable() | ||||||
| ``` | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| :::{tab-item} Containerfile | ||||||
|
|
||||||
| ```Dockerfile | ||||||
| FROM ubuntu:latest | ||||||
|
|
||||||
| # Linux Packages | ||||||
| RUN apt-get update && \ | ||||||
| apt-get install -y build-essential wget nginx && \ | ||||||
| apt-get clean && \ | ||||||
| rm -rf /var/lib/apt/lists/* | ||||||
|
|
||||||
| # Python Packages | ||||||
| ENV CONDA_DIR /opt/conda | ||||||
| RUN wget --quiet https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O ~/conda.sh && \ | ||||||
| /bin/bash ~/conda.sh -b -p $CONDA_DIR && rm ~/conda.sh | ||||||
| ENV PATH=$CONDA_DIR/bin:$PATH | ||||||
| RUN conda install python ipywidgets ipywidgets_bokeh panel -y | ||||||
|
|
||||||
| # Bokeh | ||||||
| ENV BOKEH_RESOURCES server | ||||||
| ENV BOKEH_ALLOW_WS_ORIGIN localhost | ||||||
|
|
||||||
| # Nginx | ||||||
| RUN rm /etc/nginx/sites-available/default | ||||||
| COPY nginx.conf /etc/nginx/sites-available/default | ||||||
|
|
||||||
| # App | ||||||
| COPY app.py . | ||||||
| COPY panel-serve.sh . | ||||||
| RUN chmod +x panel-serve.sh | ||||||
| WORKDIR / | ||||||
| CMD ["/bin/bash", "panel-serve.sh"] | ||||||
| ``` | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| :::{tab-item} panel-serve.sh | ||||||
|
|
||||||
| ```bash | ||||||
| #!/bin/bash | ||||||
|
|
||||||
| nginx | ||||||
|
|
||||||
| # Serve the panel apps | ||||||
| panel serve app.py --port 5100 & | ||||||
| panel serve app.py --port 5101 & | ||||||
| panel serve app.py --port 5102 & | ||||||
|
|
||||||
| # Never stop | ||||||
| wait -n | ||||||
| ``` | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| :::{tab-item} nginx.conf | ||||||
|
|
||||||
| ```nginx | ||||||
| upstream app { | ||||||
| # Should match what is defined in panel-serve.sh | ||||||
| least_conn; | ||||||
| server 127.0.0.1:5100; | ||||||
| server 127.0.0.1:5101; | ||||||
| server 127.0.0.1:5102; | ||||||
| } | ||||||
| server { | ||||||
| listen 80 default_server; | ||||||
| server_name _; | ||||||
| access_log /tmp/bokeh.access.log; | ||||||
| error_log /tmp/bokeh.error.log debug; | ||||||
| location = /proxy { | ||||||
| return 301 http://$http_host/proxy/; | ||||||
| } | ||||||
| location /proxy/ { | ||||||
| rewrite ^/proxy/(.*)$ /$1 break; | ||||||
| proxy_pass http://app/; | ||||||
| proxy_set_header Host $host:$server_port; | ||||||
| proxy_set_header X-Real-IP $remote_addr; | ||||||
| } | ||||||
| location ~ ^/proxy/(.*)/ws$ { | ||||||
| rewrite ^/proxy/(.*)/ws$ /$1/ws break; | ||||||
| proxy_pass http://app; | ||||||
| proxy_http_version 1.1; | ||||||
| proxy_set_header Connection "Upgrade"; | ||||||
| proxy_set_header Host $host:$server_port; | ||||||
| proxy_set_header Upgrade $http_upgrade; | ||||||
| } | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| ::: | ||||||
|
|
||||||
| :::: | ||||||
|
|
||||||
| ### Launching the app | ||||||
|
|
||||||
| You can use any container framework to run the app. The commands below are for Podman, but you can use Docker as well. | ||||||
| First, build the container with `podman build -t my-container .` and the run it `podman run -dt -p 8000:80 localhost/my-container` | ||||||
|
|
||||||
| :::{seealso} | ||||||
| [admin](../profiling/admin): An app for monitoring resource usage and user behavior. | ||||||
|
|
||||||
| [profile](../profiling/profile): To profile an application in terms of execution time and memory usage. | ||||||
| ::: | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the same time it can be more resource-intensive. Since each process is isolated, there is no sharing of cached data or global state between processes.
Note: are there potential solutions to isolated cache / global state? Like a cache at a higher level that is accessible by each process?
If so, provide some high-level mention or hint to these solutions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing multiple machines as part of the sentence is incorrect to me, mainly because a way to share resources if you were on the same machine would be to save them to disk.
I don't think there is a high-level solution. It will depend on the use case. One acceptable solution would be to accept it is isolated; another would be to have a server used to communicate with it or set your system up to have file access.
People who need to use load balancing will likely already know how to handle it; if not, there will be better resources for this than this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, my suggestion (without the multiple machine part) was an incomplete paste from the original.
I meant to suggest keeping the paragraph the same, but using "resource-intensive" instead of "wasteful of resources".