Skip to content

Commit 8c9f6fc

Browse files
committed
Merge deployment topic guide into deployment section.
1 parent 2a61268 commit 8c9f6fc

File tree

6 files changed

+197
-190
lines changed

6 files changed

+197
-190
lines changed
File renamed without changes.

docs/deploy/index.rst

+196-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,39 @@
1-
Deployment guides
2-
=================
1+
Deployment
2+
==========
33

4-
Discover how to deploy your application on various platforms.
4+
.. currentmodule:: websockets
55

6-
Platforms-as-a-Service
6+
Architecture decisions
77
----------------------
88

9+
When you deploy your websockets server to production, at a high level, your
10+
architecture will almost certainly look like the following diagram:
11+
12+
.. image:: architecture.svg
13+
14+
The basic unit for scaling a websockets server is "one server process". Each
15+
blue box in the diagram represents one server process.
16+
17+
There's more variation in routing. While the routing layer is shown as one big
18+
box, it is likely to involve several subsystems.
19+
20+
As a consequence, when you design a deployment, you must answer two questions:
21+
22+
1. How will I run the appropriate number of server processes?
23+
2. How will I route incoming connections to these processes?
24+
25+
These questions are interrelated. There's a wide range of valid answers,
26+
depending on your goals and your constraints.
27+
28+
Platforms-as-a-Service
29+
......................
30+
31+
Platforms-as-a-Service are the easiest option. They provide end-to-end,
32+
integrated solutions and they require little configuration.
33+
34+
Here's how to deploy on some popular PaaS providers. Since all PaaS use
35+
similar patterns, the concepts translate to other providers.
36+
937
.. toctree::
1038
:titlesonly:
1139

@@ -14,8 +42,13 @@ Platforms-as-a-Service
1442
fly
1543
heroku
1644

17-
Self-hosted
18-
-----------
45+
Self-hosted infrastructure
46+
..........................
47+
48+
If you need more control over your infrastructure, you can deploy on your own
49+
infrastructure. This requires more configuration.
50+
51+
Here's how to configure some components mentioned in this guide.
1952

2053
.. toctree::
2154
:titlesonly:
@@ -24,3 +57,160 @@ Self-hosted
2457
supervisor
2558
nginx
2659
haproxy
60+
61+
Running server processes
62+
------------------------
63+
64+
How many processes do I need?
65+
.............................
66+
67+
Typically, one server process will manage a few hundreds or thousands
68+
connections, depending on the frequency of messages and the amount of work
69+
they require.
70+
71+
CPU and memory usage increase with the number of connections to the server.
72+
73+
Often CPU is the limiting factor. If a server process goes to 100% CPU, then
74+
you reached the limit. How much headroom you want to keep is up to you.
75+
76+
Once you know how many connections a server process can manage and how many
77+
connections you need to handle, you can calculate how many processes to run.
78+
79+
You can also automate this calculation by configuring an autoscaler to keep
80+
CPU usage or connection count within acceptable limits.
81+
82+
.. admonition:: Don't scale with threads. Scale only with processes.
83+
:class: tip
84+
85+
Threads don't make sense for a server built with :mod:`asyncio`.
86+
87+
How do I run processes?
88+
.......................
89+
90+
Most solutions for running multiple instances of a server process fall into
91+
one of these three buckets:
92+
93+
1. Running N processes on a platform:
94+
95+
* a Kubernetes Deployment
96+
97+
* its equivalent on a Platform as a Service provider
98+
99+
2. Running N servers:
100+
101+
* an AWS Auto Scaling group, a GCP Managed instance group, etc.
102+
103+
* a fixed set of long-lived servers
104+
105+
3. Running N processes on a server:
106+
107+
* preferably via a process manager or supervisor
108+
109+
Option 1 is easiest if you have access to such a platform. Option 2 usually
110+
combines with option 3.
111+
112+
How do I start a process?
113+
.........................
114+
115+
Run a Python program that invokes :func:`~asyncio.server.serve` or
116+
:func:`~asyncio.router.route`. That's it!
117+
118+
Don't run an ASGI server such as Uvicorn, Hypercorn, or Daphne. They're
119+
alternatives to websockets, not complements.
120+
121+
Don't run a WSGI server such as Gunicorn, Waitress, or mod_wsgi. They aren't
122+
designed to run WebSocket applications.
123+
124+
Applications servers handle network connections and expose a Python API. You
125+
don't need one because websockets handles network connections directly.
126+
127+
How do I stop a process?
128+
........................
129+
130+
Process managers send the SIGTERM signal to terminate processes. Catch this
131+
signal and exit the server to ensure a graceful shutdown.
132+
133+
Here's an example:
134+
135+
.. literalinclude:: ../../example/faq/shutdown_server.py
136+
:emphasize-lines: 14-16
137+
138+
When exiting the context manager, :func:`~asyncio.server.serve` closes all
139+
connections with code 1001 (going away). As a consequence:
140+
141+
* If the connection handler is awaiting
142+
:meth:`~asyncio.server.ServerConnection.recv`, it receives a
143+
:exc:`~exceptions.ConnectionClosedOK` exception. It can catch the exception
144+
and clean up before exiting.
145+
146+
* Otherwise, it should be waiting on
147+
:meth:`~asyncio.server.ServerConnection.wait_closed`, so it can receive the
148+
:exc:`~exceptions.ConnectionClosedOK` exception and exit.
149+
150+
This example is easily adapted to handle other signals.
151+
152+
If you override the default signal handler for SIGINT, which raises
153+
:exc:`KeyboardInterrupt`, be aware that you won't be able to interrupt a
154+
program with Ctrl-C anymore when it's stuck in a loop.
155+
156+
Routing connections
157+
-------------------
158+
159+
What does routing involve?
160+
..........................
161+
162+
Since the routing layer is directly exposed to the Internet, it should provide
163+
appropriate protection against threats ranging from Internet background noise
164+
to targeted attacks.
165+
166+
You should always secure WebSocket connections with TLS. Since the routing
167+
layer carries the public domain name, it should terminate TLS connections.
168+
169+
Finally, it must route connections to the server processes, balancing new
170+
connections across them.
171+
172+
How do I route connections?
173+
...........................
174+
175+
Here are typical solutions for load balancing, matched to ways of running
176+
processes:
177+
178+
1. If you're running on a platform, it comes with a routing layer:
179+
180+
* a Kubernetes Ingress and Service
181+
182+
* a service mesh: Istio, Consul, Linkerd, etc.
183+
184+
* the routing mesh of a Platform as a Service
185+
186+
2. If you're running N servers, you may load balance with:
187+
188+
* a cloud load balancer: AWS Elastic Load Balancing, GCP Cloud Load
189+
Balancing, etc.
190+
191+
* A software load balancer: HAProxy, NGINX, etc.
192+
193+
3. If you're running N processes on a server, you may load balance with:
194+
195+
* A software load balancer: HAProxy, NGINX, etc.
196+
197+
* The operating system — all processes listen on the same port
198+
199+
You may trust the load balancer to handle encryption and to provide security.
200+
You may add another layer in front of the load balancer for these purposes.
201+
202+
There are many possibilities. Don't add layers that you don't need, though.
203+
204+
How do I implement a health check?
205+
..................................
206+
207+
Load balancers need a way to check whether server processes are up and running
208+
to avoid routing connections to a non-functional backend.
209+
210+
websockets provide minimal support for responding to HTTP requests with the
211+
``process_request`` hook.
212+
213+
Here's an example:
214+
215+
.. literalinclude:: ../../example/faq/health_check_server.py
216+
:emphasize-lines: 7-9,16

docs/howto/index.rst

-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ features, which websockets supports fully.
3939

4040
extensions
4141

42-
.. _deployment-howto:
43-
4442
If you're integrating the Sans-I/O layer of websockets into a library, rather
4543
than building an application with websockets, follow this guide.
4644

docs/spelling_wordlist.txt

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ middleware
5151
mutex
5252
mypy
5353
nginx
54+
PaaS
5455
Paketo
5556
permessage
5657
pid

0 commit comments

Comments
 (0)