ЁЯЧВя╕П рдзрдбрд╛ 06 тАФ Caching рдЖрдгрд┐ memoization: scoreboard рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рддреЛ
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 06 ┬╖ рдорд╛рдЧреЗ: lesson-05-memory ┬╖ рдкреБрдвреЗ: lesson-07-io-batching
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ05, рдЕрдзрд┐рдХ caching: рдЖрдзреАрдЪ рдХрд╛рдврд▓реЗрд▓реЗ рдЙрддреНрддрд░ рдареЗрд╡реВрди рджреНрдпрд╛, рдореНрд╣рдгрдЬреЗ рдкреБрдврдЪреНрдпрд╛
request рд▓рд╛ рддреЗ рдЬрд╡рд│рдЬрд╡рд│ рдлреБрдХрдЯ рдорд┐рд│рддреЗ. Memoization рдореНрд╣рдгрдЬреЗ рдПрдЦрд╛рджреНрдпрд╛ function рдЪреЗ results cache рдХрд░рдгреЗ;
рдЬрд╛рдЧрд╛ рдорд░реНрдпрд╛рджрд┐рдд рдЕрд╕рддрд╛рдирд╛ LRU cache рд╕рд░реНрд╡рд╛рдд рдЕрд▓реАрдХрдбреЗ рд╡рд╛рдкрд░рд▓реЗрд▓реА рдЙрддреНрддрд░реЗ рдареЗрд╡рддреЛ; рдЖрдгрд┐
cache рдЙрдкрдпреЛрдЧреА рдЖрд╣реЗ рдХреА рдирд╛рд╣реА рд╣реЗ hit ratio рдард░рд╡рддреЛ. perf/demo.py рдордзрд▓реЗ caching() рдЖрдгрд┐
perf/sim.py рдордзрд▓реЗ fib_plain, fib_memo, LRU, request_stream рдЖрдгрд┐
cached_cost.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдкрд╛рд▓рдХ рд╕рд╛рд░рдЦреЗ results office рдордзреНрдпреЗ рдпреЗрдд рд░рд╛рд╣рддрд╛рдд: "рдХрддрд░рд┐рдирд╛рдЪреА рд╡реЗрд│ рдХрд╛рдп рд╣реЛрддреА?" ЁЯЩЛтАНтЩАя╕П
рдкреНрд░рддреНрдпреЗрдХ рд╡реЗрд│реА рдРрд╢реНрд╡рд░реНрдпрд╛ рдорд╛рдЧрдЪреНрдпрд╛ рдЦреЛрд▓реАрдд рдЬрд╛рддреЗ, рдирд┐рдХрд╛рд▓рд╛рдВрдЪреЗ рдореЛрдареЗ рдкреБрд╕реНрддрдХ рдЙрдШрдбрддреЗ, рдкрд╛рди рд╢реЛрдзрддреЗ, рдЖрдгрд┐ рдкрд░рдд рдпреЗрддреЗ. рдпрд╛рдд 50 seconds рдЬрд╛рддрд╛рдд.
рдордЧ рддреА рджрд╛рд░рд╛рдЬрд╡рд│ рдПрдХ рдЫреЛрдЯрд╛ scoreboard рд▓рд╛рд╡рддреЗ. ЁЯУЛ рддреА рд╢реЛрдзрд▓реЗрд▓реЗ рдкреНрд░рддреНрдпреЗрдХ рдЙрддреНрддрд░ board рд╡рд░ рд▓рд┐рд╣рд┐рддреЗ. рдкреБрдврдЪреНрдпрд╛ рд╡реЗрд│реА рдХреЛрдгреА рддреЛрдЪ рдкреНрд░рд╢реНрди рд╡рд┐рдЪрд╛рд░рд▓рд╛, рддрд░ рддреА рдлрдХреНрдд board рд╡рд╛рдЪрддреЗ: 1 second.
- рдкреНрд░рд╢реНрди board рд╡рд░ рдЕрд╕реЗрд▓, рддрд░ рддреЛ hit рдЖрд╣реЗ. тЬЕ
- рдирд╕реЗрд▓, рддрд░ рддреЛ miss рдЖрд╣реЗ тАФ рдкреБрдиреНрд╣рд╛ рдореЛрдареНрдпрд╛ рдкреБрд╕реНрддрдХрд╛рдХрдбреЗ. тЭМ
Board рд╡рд░ рдлрдХреНрдд 100 рдирд╛рд╡рд╛рдВрд╕рд╛рдареА рдЬрд╛рдЧрд╛ рдЖрд╣реЗ. рддреЛ рднрд░рд▓реНрдпрд╛рд╡рд░, рдЬреНрдпрд╛ рдирд╛рд╡рд╛рдмрджреНрджрд▓ рд╕рд░реНрд╡рд╛рдд рдЬрд╛рд╕реНрдд рдХрд╛рд│ рдХреЛрдгреАрд╣реА рд╡рд┐рдЪрд╛рд░рд▓реЗ рдирд╛рд╣реА рддреЗ рддреА рдкреБрд╕реВрди рдЯрд╛рдХрддреЗ. рдмрд╣реБрддреЗрдХ рдкрд╛рд▓рдХ рддреНрдпрд╛рдЪ рдХрд╛рд╣реА рдЕрдВрддрд┐рдо рдлреЗрд░реАрддрд▓реНрдпрд╛ рдзрд╛рд╡рдкрдЯреВрдВрдмрджреНрджрд▓ рд╡рд┐рдЪрд╛рд░рддрд╛рдд, рдореНрд╣рдгреВрди рдЫреЛрдЯрд╛ board рдЦреВрдк рдкреНрд░рд╢реНрдирд╛рдВрдЪреА рдЙрддреНрддрд░реЗ рджреЗрддреЛ.
рдПрдХ рдзреЛрдХрд╛: рдореЛрдареНрдпрд╛ рдкреБрд╕реНрддрдХрд╛рдд рдПрдЦрд╛рджреА рд╡реЗрд│ рджреБрд░реБрд╕реНрдд рдЭрд╛рд▓реА, рддрд░ рдХреЛрдгреА update рдХрд░реЗрдкрд░реНрдпрдВрдд board рдЕрдЬреВрдирд╣реА рдЬреБрдиреА рд╡реЗрд│ рджрд╛рдЦрд╡рддреЛ. ЁЯХ░я╕П
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
ask["ЁЯЩЛ 2000 lookups<br/>500 runners, a few popular"] --> board{"ЁЯУЛ on the board?<br/>LRU of 100"}
board -->|"hit 44.9%"| fast["1 ms"]
board -->|"miss"| book["ЁЯУЪ the back room<br/>50 ms, then write it on the board"]
fast --> avg["average 28.0 ms<br/>(no cache: 50 ms)"]
book --> avg
fib["fib(25): 242,785 calls"] -->|"lru_cache"| memo["26 calls"]
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/performance/lesson-diagrams.html#l06
тЭУ рдХрд╛рдп
- Cache тАФ рдЖрдзреАрдЪ рдХрд╛рдврд▓реЗрд▓реНрдпрд╛ рдХрд┐рдВрд╡рд╛ рдЖрдгрд▓реЗрд▓реНрдпрд╛ рдЙрддреНрддрд░рд╛рдВрдЪрд╛ рдЫреЛрдЯрд╛, рдЬрд▓рдж рд╕рд╛рдард╛. рдЖрдзреА cache рд▓рд╛ рд╡рд┐рдЪрд╛рд░рдгреЗ рдЖрдгрд┐ рдлрдХреНрдд miss рдЭрд╛рд▓реНрдпрд╛рд╡рд░рдЪ рд╣рд│реВ рд╕реНрд░реЛрддрд╛рдХрдбреЗ рдЬрд╛рдгреЗ рдпрд╛рд▓рд╛ cache-aside pattern рдореНрд╣рдгрддрд╛рдд.
- Memoization тАФ function рдЪреЗ results рддреНрдпрд╛рдЪреНрдпрд╛ arguments рдиреБрд╕рд╛рд░ cache рдХрд░рдгреЗ. Python рдордзреНрдпреЗ рддреЗ built in рдЖрд╣реЗ:
functools.lru_cache(maxsize=...)рдЖрдгрд┐functools.cache(рдЖрдХрд╛рд░рд╛рдЪреА рдорд░реНрдпрд╛рджрд╛ рдирд╛рд╣реА). рддреЗ рдлрдХреНрдд pure functions рд╕рд╛рдареАрдЪ рдпреЛрдЧреНрдп рдЖрд╣реЗ: рддреЗрдЪ arguments, рддреЗрдЪ рдЙрддреНрддрд░, рдХреЛрдгрддреЗрд╣реА side effects рдирд╛рд╣реАрдд. - Hit ratio тАФ hits ├╖ рд╕рдЧрд│реЗ lookups. рд╕рд░рд╛рд╕рд░реА рдЦрд░реНрдЪ рд╕рд╛рдзрд╛рд░рдг hit ratio ├Ч hit cost + (1 тИТ hit ratio) ├Ч miss cost рдЕрд╕рддреЛ. 1 ms рдЪрд╛ hit рдЖрдгрд┐ 50 ms рдЪрд╛ miss рдЕрд╕реЗрд▓, рддрд░ 45% hit ratio рд╕реБрдорд╛рд░реЗ 28 ms рджреЗрддреЛ тАФ рдЪрд╛рдВрдЧрд▓реЗ, рдкрдг 1 ms рдкрд╛рд╕реВрди рдЦреВрдк рджреВрд░.
- Eviction тАФ cache рднрд░рд▓реНрдпрд╛рд╡рд░ рдХрд╛рдп рд╡рд┐рд╕рд░рд╛рдпрдЪреЗ. LRU (least recently used) рд╕рд░реНрд╡рд╛рдд рдЬрд╛рд╕реНрдд рдХрд╛рд│ рди рд╡рд╛рдкрд░рд▓реЗрд▓реА entry рд╡рд┐рд╕рд░рддреЛ. рдЗрддрд░: LFU (least frequently used), FIFO, random.
- Skew тАФ рдЦрд░реЗ traffic рдЕрд╕рдорд╛рди рдЕрд╕рддреЗ: рдХрд╛рд╣реА keys рдирд╛ рдмрд╣реБрддреЗрдХ requests рдорд┐рд│рддрд╛рдд. рдореНрд╣рдгреВрдирдЪ рдЫреЛрдЯреНрдпрд╛ cache рдЪрд╛ hit ratio рдЪрд╛рдВрдЧрд▓рд╛ рдЕрд╕реВ рд╢рдХрддреЛ. Lab рдЪрд╛ stream key тМК500 ├Ч u┬│тМЛ рдирд┐рд╡рдбрддреЛ (u random), рдореНрд╣рдгреВрди рдХрдореА рдХреНрд░рдорд╛рдВрдХрд╛рдЪреНрдпрд╛ "рдЕрдВрддрд┐рдо рдлреЗрд░реАрддрд▓реНрдпрд╛ рдзрд╛рд╡рдкрдЯреВрдВрдмрджреНрджрд▓" рдЦреВрдк рдЬрд╛рд╕реНрдд рд╡реЗрд│рд╛ рд╡рд┐рдЪрд╛рд░рд▓реЗ рдЬрд╛рддреЗ.
- рд╢рд┐рд│реЗрдкрдгрд╛ рдЖрдгрд┐ invalidation тАФ cache рдордзрд▓реЗ рдЙрддреНрддрд░ рдЬреБрдиреЗ рдЕрд╕реВ рд╢рдХрддреЗ. рддреБрдореНрд╣реА рдПрдХрддрд░ рдкреНрд░рддреНрдпреЗрдХ entry рд▓рд╛ TTL (time to live) рджреЗрддрд╛ рдЖрдгрд┐ рддреЗрд╡рдвреНрдпрд╛ рдХрд╛рд│рд╛рдкрд░реНрдпрдВрддрдЪрд╛ рд╢рд┐рд│реЗрдкрдгрд╛ рд╕реНрд╡реАрдХрд╛рд░рддрд╛, рдХрд┐рдВрд╡рд╛ рд╕реНрд░реЛрдд рдмрджрд▓рд▓реНрдпрд╛рд╡рд░ entry delete/update рдХрд░рддрд╛ (рд╣реЗ рдРрдХрдгреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЕрд╡рдШрдб рдЖрд╣реЗ).
- Cache stampede тАФ рдПрдЦрд╛рджреА рд▓реЛрдХрдкреНрд░рд┐рдп entry expire рд╣реЛрддреЗ рдЖрдгрд┐ рд╢реЗрдХрдбреЛ requests рдПрдХрджрдо miss рд╣реЛрдКрди рд╕рдЧрд│реНрдпрд╛ рд╣рд│реВ рд╕реНрд░реЛрддрд╛рд╡рд░ рдЖрджрд│рддрд╛рдд. рдЙрдкрд╛рдп: рдПрдХрд╛ request рд▓рд╛ refresh рдХрд░реВ рджреНрдпрд╛ рдЖрдгрд┐ рдмрд╛рдХреАрдЪреНрдпрд╛ рдерд╛рдВрдмрддреАрд▓ рдХрд┐рдВрд╡рд╛ рдЬреБрдиреА value рдШреЗрддреАрд▓, рдЖрдгрд┐ TTLs рдордзреНрдпреЗ рдереЛрдбрд╛ random jitter рдЬреЛрдбрд╛.
Machines рджрд░рдореНрдпрд╛рдирдЪреЗ caches тАФ рдЕрдиреЗрдХ servers рдкреБрдврдЪреЗ CDNs рдЖрдгрд┐ shared caches тАФ рд╣реЗ Scaling school рдордзреНрдпреЗ рдЖрд╣реЗрдд.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рд╕рд░реНрд╡рд╛рдд рд╕реНрд╡рд╕реНрдд рдХрд╛рдо рдореНрд╣рдгрдЬреЗ рдЬреЗ рддреБрдореНрд╣реА рд╡рдЧрд│рддрд╛ рддреЗ. рд╕рд╛рдзреЗ recursive fib(25) рддреЗрдЪ
рдЙрдк-рдкреНрд░рд╢реНрди рд▓рд╛рдЦреЛ рд╡реЗрд│рд╛ рдкреБрдиреНрд╣рд╛ рдХрд░рддреЗ; cache рдкреНрд░рддреНрдпреЗрдХрд╛рд▓рд╛ рдПрдХрд╛рдЪ рдЧрдгрдиреЗрдд рдмрджрд▓рддреЛ.
рдкрдг cache рдореНрд╣рдгрдЬреЗ memory рд╕реБрджреНрдзрд╛ рдЖрд╣реЗ (рдзрдбрд╛ 05), рдЪреБрдХреАрдЪрд╛ data рджреЗрдгреНрдпрд╛рдЪрд╛ рдПрдХ рдирд╡рд╛ рдорд╛рд░реНрдЧ, рдЖрдгрд┐ restart рдирдВрддрд░
warm up рдХрд░рд╛рд╡реА рд▓рд╛рдЧрдгрд╛рд░реА рдЖрдгрдЦреА рдПрдХ рдЧреЛрд╖реНрдЯ. рдЖрдзреА рдЖрдгрд┐ рдирдВрддрд░ hit ratio рдореЛрдЬрд╛; 5% hit ratio рдЕрд╕рд▓реЗрд▓рд╛ cache
рдмрд╣реБрддрд╛рдВрд╢ рдЦрд░реНрдЪрдЪ рдЕрд╕рддреЛ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
perf/sim.py рдордзрд▓реЗ fib_plain(n) рдЖрдкрд▓реНрдпрд╛ calls CALLS["fib"] рдордзреНрдпреЗ рдореЛрдЬрддреЗ;
fib_memo(n) рддреЗрдЪ recursion functools.lru_cache рдордзреНрдпреЗ рдЧреБрдВрдбрд╛рд│рддреЗ рдЖрдгрд┐ рдЙрддреНрддрд░ рдЖрдгрд┐
рдЦрд░реЗ cache_info() рдкрд░рдд рджреЗрддреЗ. LRU(cap) рд╣рд╛ OrderedDict рд╡рд░ рдмрд╛рдВрдзрд▓реЗрд▓рд╛ рдЫреЛрдЯрд╛ least-recently-used cache рдЖрд╣реЗ,
рдЬреЛ hits рдЖрдгрд┐ misses рдореЛрдЬрддреЛ. request_stream() 500
keys рд╡рд░ рдЬреЛрд░рджрд╛рд░ skew рд╕рд╣ 2000 seeded lookups рдмрдирд╡рддреЗ, рдЖрдгрд┐ cached_cost(cap, stream, hit_ms, miss_ms) hit ratio
рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ request рдЪрд╛ simulated рд╕рд░рд╛рд╕рд░реА рдЦрд░реНрдЪ рдкрд░рдд рджреЗрддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 perf/demo.py caching
python3 - <<'EOF'
import sys; sys.path.insert(0, "perf"); import sim
for n in (10, 20, 25, 30):
sim.CALLS["fib"] = 0; sim.fib_plain(n); plain = sim.CALLS["fib"]
sim.CALLS["fib"] = 0; sim.fib_memo(n); memo = sim.CALLS["fib"]
print(f"fib({n:>2}): plain {plain:>9,} calls ┬╖ memoized {memo:>3}")
s = sim.request_stream()
for miss_ms in (5, 50, 500):
r, cost = sim.cached_cost(100, s, miss_ms=miss_ms)
print(f"cache of 100, a miss costs {miss_ms:>3} ms тЖТ hit ratio {r:.1%} ┬╖ average {cost:6.1f} ms")
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
caching рд╣реЗ рдЫрд╛рдкрддреЗ:
тФАтФА fib(25) = 75025: plain recursion does the work 242,785 times ┬╖ memoized (lru_cache) 26 times (23 cache hits)
тФАтФА parents look up results: 2000 requests over 500 runners, a few asked for far more often ┬╖ a hit costs 1 ms, a miss 50 ms
LRU cache of 10 тЖТ hit ratio 15.4% ┬╖ average 42.5 ms per request
LRU cache of 50 тЖТ hit ratio 33.0% ┬╖ average 33.9 ms per request
LRU cache of 100 тЖТ hit ratio 44.9% ┬╖ average 28.0 ms per request
LRU cache of 250 тЖТ hit ratio 67.7% ┬╖ average 16.8 ms per request
рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:
fib(10): plain 177 calls ┬╖ memoized 11
fib(20): plain 21,891 calls ┬╖ memoized 21
fib(25): plain 242,785 calls ┬╖ memoized 26
fib(30): plain 2,692,537 calls ┬╖ memoized 31
cache of 100, a miss costs 5 ms тЖТ hit ratio 44.9% ┬╖ average 3.2 ms
cache of 100, a miss costs 50 ms тЖТ hit ratio 44.9% ┬╖ average 28.0 ms
cache of 100, a miss costs 500 ms тЖТ hit ratio 44.9% ┬╖ average 275.9 ms
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
Memoization рдиреЗ рдШрд╛рддрд╛рдВрдХреА (exponential) рдХрд╛рдорд╛рдЪреЗ рд░реЗрд╖реАрдп (linear) рдХрд╛рдорд╛рдд рд░реВрдкрд╛рдВрддрд░ рдХреЗрд▓реЗ: fib(30) 2,692,537 calls рд╡рд░реВрди 31 рд╡рд░ рдЖрд▓реЗ. Lookup cache рд╕рд╛рдареА, 10 slots рдиреАрдЪ 15.4% requests рдкрдХрдбрд▓реНрдпрд╛, рдХрд╛рд░рдг traffic skewed рд╣реЛрддреЗ, рдкрдг cache рджреБрдкреНрдкрдЯ рдХреЗрд▓реНрдпрд╛рдиреЗ hit ratio рдХрдзреАрдЪ рджреБрдкреНрдкрдЯ рдЭрд╛рд▓рд╛ рдирд╛рд╣реА. рдЖрдгрд┐ 500 ms рдЪреНрдпрд╛ miss рд╕рд╣, 44.9% hit ratio рдЕрд╕реВрдирд╣реА рд╕рд░рд╛рд╕рд░реА 275.9 ms рдЙрд░рддреЗ: рдЬреЗрд╡реНрд╣рд╛ misses рдорд╣рд╛рдЧ рдЕрд╕рддрд╛рдд, рддреЗрд╡реНрд╣рд╛ miss path рд╕реБрджреНрдзрд╛ рдЬрд▓рдж рдЕрд╕рд╛рдпрд▓рд╛ рд╣рд╡рд╛.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рдШрдбреНрдпрд╛рд│, database рдХрд┐рдВрд╡рд╛ рдмрджрд▓рдгрд╛рд░реА рдХреЛрдгрддреАрд╣реА рдЧреЛрд╖реНрдЯ рд╡рд╛рдЪрдгрд╛рд▒реНрдпрд╛ function рд╡рд░
@lru_cache - method рд╡рд░
@lru_cache: cacheselfрд▓рд╛ рдЬрд┐рд╡рдВрдд рдареЗрд╡рддреЛ (рдЕрд▓реНрдкрд╛рдпреБрд╖реА objects рд╕рд╛рдареА memory leak) - рдЖрдХрд╛рд░рд╛рдЪреА рдорд░реНрдпрд╛рджрд╛ рдирд╕рд▓реЗрд▓рд╛ cache тАФ
functools.cacheрдХрд╛рдпрдо рд╡рд╛рдврдд рд░рд╛рд╣рддреЛ - TTL рдирд╛рд╣реА рдЖрдгрд┐ invalidation рдирд╛рд╣реА, рдореНрд╣рдгреВрди рджреБрд░реБрд╕реНрдд рдХреЗрд▓реЗрд▓рд╛ result рдХрдзреАрдЪ рджрд┐рд╕рдд рдирд╛рд╣реА
- рдкреНрд░рддреНрдпреЗрдХ user рдЪреА pages рдПрдХрд╛ shared key рдЦрд╛рд▓реА cache рдХрд░рдгреЗ тАФ рдПрдХрд╛ user рд▓рд╛ рджреБрд╕рд▒реНрдпрд╛рдЪрд╛ data рджрд┐рд╕рддреЛ
- profiling рдХрд░рдгреНрдпрд╛рдЖрдзреАрдЪ cache рдЬреЛрдбрдгреЗ; рд╣рд│реВ рднрд╛рдЧ рдкреБрдиреНрд╣рд╛ рдкреБрдиреНрд╣рд╛ рд╣реЛрдгрд╛рд░реЗ рдХрд╛рдо рдирд╕реВрд╣реА рд╢рдХрддреЛ
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ Redis рд╕рд╣ cache-aside, TTL рд╕рд╣:
import json, redis
r = redis.Redis(host="cache.school.internal")
def best_lap(runner_id):
key = f"best_lap:{runner_id}"
hit = r.get(key)
if hit is not None:
return json.loads(hit)
value = db_best_lap(runner_id) # the slow source
r.set(key, json.dumps(value), ex=60) # expire after 60 s
return value
Redis рддреБрдордЪреНрдпрд╛рд╕рд╛рдареА рдареЗрд╡рдд рдЕрд╕рд▓реЗрд▓рд╛ hit ratio рддрдкрд╛рд╕рд╛:
redis-cli INFO stats | grep -E 'keyspace_hits|keyspace_misses'
redis-cli CONFIG SET maxmemory-policy allkeys-lru # evict least recently used keys when full
Python process рдордзреНрдпреЗ, рдорд░реНрдпрд╛рджрд┐рдд memo:
from functools import lru_cache
@lru_cache(maxsize=1024)
def house_of(bib: int) -> str: ...
print(house_of.cache_info()) # hits, misses, maxsize, currsize
ЁЯПн Production рдордзреНрдпреЗ рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ рдЖрд╣реЗ: рдкреНрд░рддреНрдпреЗрдХ cache рд╕рд╛рдареА, рддреНрдпрд╛рдЪрд╛ hit ratio рдЖрдгрд┐ рддреНрдпрд╛рдЪреА miss latency chart рдХрд░рд╛, рдЖрдгрд┐ рддреНрдпрд╛рдЪрд╛ data рдХрд┐рддреА рд╢рд┐рд│рд╛ рдЕрд╕реВ рд╢рдХрддреЛ рддреЗ рд▓рд┐рд╣реВрди рдареЗрд╡рд╛. рдХреЛрдгреАрд╣реА рди рдореЛрдЬрд▓реЗрд▓рд╛ cache рдореНрд╣рдгрдЬреЗ рдлрдХреНрдд рдЕрдВрджрд╛рдЬ.
тПня╕П рдкреБрдвреЗ
Misses "рдорд╛рдЧрдЪреНрдпрд╛ рдЦреЛрд▓реАрдд" рдЧреЗрд▓реЗ. рддрд┐рдерд▓реА рдкреНрд░рддреНрдпреЗрдХ рдлреЗрд░реА рдореНрд╣рдгрдЬреЗ рд╡реЗрд│ рдЦрд╛рдгрд╛рд░реЗ рдПрдХ рд╣рд╕реНрддрд╛рдВрддрд░ (hand-off). рдкреБрдвреЗ: I/O тАФ N+1 queries, batching рдЖрдгрд┐ buffering.
git checkout lesson-07-io-batching