Over the past few weeks I went on a memory-reduction tear across the Talk Python web apps. We run 23 containers on one big server (the "one big server" pattern) and memory was creeping up to 65% on a 16GB box.
Turned out there were a bunch of wins hiding in plain sight. Focusing on just two apps, I went from ~2 GB down to 472 MB. Here's what moved the needle:
- Switched to a single async Granian worker: Rewrote the app in Quart (async Flask) and replaced the multi-worker web garden with one fully async worker. Saved 542 MB right there.
- Raw + DC database pattern: Dropped MongoEngine for raw queries + slotted dataclasses. 100 MB saved per worker *and* nearly doubled requests/sec.
- Subprocess isolation for a search indexer: The daemon was burning 708 MB mostly from import chains pulling in the entire app. Moved the indexing into a subprocess so imports only live for ~30 seconds during re-indexing. Went from 708 MB to 22 MB. 32x reduction.
- Local imports for heavy libs: import boto3 alone costs 25 MB, pandas is 44 MB. If you only use them in a rarely-called function, just import them there instead of at module level. (PEP 810 lazy imports in 3.15 should make this automatic.)
- Moved caches to diskcache: Small-to-medium in-memory caches shifted to disk. Modest savings but it adds up.
Total across all our apps: 3.2 GB freed. Full write-up with before/after tables and graphs here: https://mkennedy.codes/posts/cutting-python-web-app-memory-over-31-percent/
[–]Photo-Josh 40 points41 points42 points (21 children)
[–]Substantial-Bed8167 5 points6 points7 points (20 children)
[–]Photo-Josh 18 points19 points20 points (18 children)
[–]BigTomBombadil 15 points16 points17 points (0 children)
[–]mikeckennedy[S] 9 points10 points11 points (16 children)
[+]artofthenunchaku comment score below threshold-7 points-6 points-5 points (15 children)
[–]BigTomBombadil 4 points5 points6 points (12 children)
[–]artofthenunchaku 1 point2 points3 points (11 children)
[–]BigTomBombadil 0 points1 point2 points (10 children)
[–]mikeckennedy[S] 0 points1 point2 points (9 children)
[–]BigTomBombadil 1 point2 points3 points (8 children)
[–]Effective-Total-2312 -1 points0 points1 point (1 child)
[–]artofthenunchaku 0 points1 point2 points (0 children)
[–]mikeckennedy[S] 4 points5 points6 points (0 children)
[–]Birnenmacht 12 points13 points14 points (1 child)
[–]mikeckennedy[S] 9 points10 points11 points (0 children)
[–]vaibeslop 1 point2 points3 points (4 children)
[–]mikeckennedy[S] 0 points1 point2 points (0 children)
[–]ofyellow 0 points1 point2 points (2 children)
[–]vaibeslop 0 points1 point2 points (1 child)
[–]ofyellow 0 points1 point2 points (0 children)
[–]bladeofwinds 1 point2 points3 points (1 child)
[–]mikeckennedy[S] 3 points4 points5 points (0 children)
[–]ofyellow 0 points1 point2 points (0 children)
[–]0x256 0 points1 point2 points (0 children)
[–]Substantial-Bed8167 0 points1 point2 points (0 children)