|
| 1 | +Deployment |
| 2 | +========== |
| 3 | + |
| 4 | +Backpressure |
| 5 | +------------ |
| 6 | + |
| 7 | +.. note:: |
| 8 | + |
| 9 | + This section discusses the concept of backpressure from the perspective of |
| 10 | + a server but the concepts also apply to clients. The issue is symmetrical. |
| 11 | + |
| 12 | +With a naive implementation, if a server receives inputs faster than it can |
| 13 | +process them, or if it generates outputs faster than it can send them, data |
| 14 | +accumulates in buffers, eventually causing the server to run out of memory and |
| 15 | +crash. |
| 16 | + |
| 17 | +The solution to this problem is backpressure. Any part of the server that |
| 18 | +receives inputs faster than it can it can process them and send the outputs |
| 19 | +must propagate that information back to the previous part in the chain. |
| 20 | + |
| 21 | +``websockets`` is designed to make it easy to get backpressure right. |
| 22 | + |
| 23 | +For incoming data, ``websockets`` builds upon :class:`~asyncio.StreamReader` |
| 24 | +which propagates backpressure to its own buffer and to the TCP stream. Frames |
| 25 | +are parsed from the input stream and added to a bounded queue. If the queue |
| 26 | +fills up, parsing halts until some the application reads a frame. |
| 27 | + |
| 28 | +For outgoing data, ``websockets`` builds upon :class:`~asyncio.StreamWriter` |
| 29 | +which implements flow control. If the output buffers grow too large, it waits |
| 30 | +until they're drained. That's why all APIs that write frames are asynchronous |
| 31 | +in websockets (since version 2.0). |
| 32 | + |
| 33 | +Of course, it's still possible for an application to create its own unbounded |
| 34 | +buffers and break the backpressure. Be careful with queues. |
| 35 | + |
| 36 | +Buffers |
| 37 | +------- |
| 38 | + |
| 39 | +An asynchronous systems works best when its buffers are almost always empty. |
| 40 | + |
| 41 | +For example, if a client sends frames too fast for a server, the queue of |
| 42 | +incoming frames will be constantly full. The server will always be 32 frames |
| 43 | +(by default) behind the client. This consumes memory and adds latency for no |
| 44 | +good reason. |
| 45 | + |
| 46 | +If buffers are almost always full and that problem cannot be solved by adding |
| 47 | +capacity (typically because the system is bottlenecked by the output and |
| 48 | +constantly regulated by backpressure), reducing the size of buffers minimizes |
| 49 | +negative consequences. |
| 50 | + |
| 51 | +By default ``websockets`` has rather high limits. You can decrease them |
| 52 | +according to your application's characteristics. |
| 53 | + |
| 54 | +Bufferbloat can happen at every level in the stack where there is a buffer. |
| 55 | +The receiving side contains these buffers: |
| 56 | + |
| 57 | +- OS buffers: you shouldn't need to tune them in general. |
| 58 | +- :class:`~asyncio.StreamReader` bytes buffer: the default limit is 64kB. |
| 59 | + You can set another limit by passing a ``read_limit`` keyword argument to |
| 60 | + :func:`~websockets.client.connect` or :func:`~websockets.server.serve`. |
| 61 | +- ``websockets`` frame buffer: its size depends both on the size and the |
| 62 | + number of frames it contains. By default the maximum size is 1MB and the |
| 63 | + maximum number is 32. You can adjust these limits by setting the |
| 64 | + ``max_size`` and ``max_queue`` keyword arguments of |
| 65 | + :func:`~websockets.client.connect` or :func:`~websockets.server.serve`. |
| 66 | + |
| 67 | +The sending side contains these buffers: |
| 68 | + |
| 69 | +- :class:`~asyncio.StreamWriter` bytes buffer: the default size is 64kB. |
| 70 | + You can set another limit by passing a ``write_limit`` keyword argument to |
| 71 | + :func:`~websockets.client.connect` or :func:`~websockets.server.serve`. |
| 72 | +- OS buffers: you shouldn't need to tune them in general. |
| 73 | + |
1 | 74 | Deployment
|
2 | 75 | ----------
|
3 | 76 |
|
@@ -34,7 +107,6 @@ Here's a full example (Unix-only):
|
34 | 107 |
|
35 | 108 | .. literalinclude:: ../example/shutdown.py
|
36 | 109 |
|
37 |
| - |
38 | 110 | It's more difficult to achieve the same effect on Windows. Some third-party
|
39 | 111 | projects try to help with this problem.
|
40 | 112 |
|
|
0 commit comments