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
0 commit comments