data - LRU cache

๐Ÿง What is caching

์บ์‹ฑ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ค๋Š”๋ฐ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ฑฐ๋‚˜, ์‹คํ–‰ํ•˜๋Š”๋ฐ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์—ฐ์‚ฐ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฏธ๋ฆฌ ๊ณ„์‚ฐํ•˜์—ฌ ํ•„์š”ํ•  ๋•Œ ์ตœ์ดˆ๋กœ ํ•œ๋ฒˆ๋งŒ ๊ณ„์‚ฐํ•˜์—ฌ ์ €์žฅํ•ด๋†“๊ณ  ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์ˆ ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋ก ํŠธ์•ค๋“œ์—์„œ๋Š” ํด๋ฆฌ์ด์–ธํŠธ ์ปดํ“จํ„ฐ์— ์บ์‹œ๋ฅผ ๋‘๊ณ , ์ด ์บ์‹œ์— ์ „์— ๋ฐฉ๋ฌธํ–ˆ๋˜ ์›นํŽ˜์ด์ง€์˜ ๋‚ด์šฉ์„ ์ €์žฅํ•ด๋†“๊ณ  ๋™์ผํ•œ ํŽ˜์ด์ง€๋ฅผ ์žฌ๋ฐฉ๋ฌธ์‹œ ์ด ์ €์žฅํ•ด๋†“์€ ์‚ฌ๋ณธ์˜ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐฉ์‹์„ ์ทจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฑ์—”๋“œ์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ฐ›์€ ์š”์ฒญ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ์ €์žฅํ•ด๋‘๊ณ , ๋‚˜์ค‘์— ๋™์ผํ•œ ์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๋•Œ, ์ €์žฅํ•ด๋‘” ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜์—ฌ ์กฐํšŒ ์†๋„๋ฅผ ํ–ฅ์ƒ์‹œํ‚ค๊ณ , ์„œ๋ฒ„ ๋‹จ์˜ ๋ถ€ํ•˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„คํŠธ์›Œํฌ์—์„œ๋Š” ํ”„๋ก์‹œ ์„œ๋ฒ„๋‚˜ CDN์„ ๋Œ€ํ‘œ์ ์ธ ์บ์‹ฑ ์‚ฌ๋ก€๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์บ์‹ฑ ์ „๋žต์ด๋ž€?

์ผ๋ฐ˜์ ์œผ๋กœ ์บ์‹ฑ์„ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ์ €์žฅ ๋งค์ฒด๋Š” ๊ฐ€๊ฒฉ์ด ๋น„์Œ‰๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ์ €์žฅ ๋ฉ”์ฒด์˜ ์šฉ๋Ÿ‰์„ ์ œํ•œํ•˜์—ฌ ์ตœ๋Œ€ํ•œ ํšจ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ „๋žต์„ ์ทจํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ์บ์‹ฑ ์ „๋žต์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์บ์‹ฑ ์ „๋žต์€ ์บ์‹œ ์šฉ๋Ÿ‰์ด ๊ฝ‰ ์ฐผ์„ ๋•Œ, ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ๋‚จ๊ฒจ๋‘๊ณ , ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์›Œ์•ผํ• ์ง€์— ๋Œ€ํ•œ ๋ฐฉ๋ฒ•์„ ๋œปํ•ฉ๋‹ˆ๋‹ค. ์บ์‹ฑ ์ „๋žต์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ข…๋ฅ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • LRU(Least Recently Used) cache

  • MRU(Most Recently Used) cache

  • LFU(Least Frequently Used) cache

์บ์‹ฑ ์ „๋žต - LRU cache(Least Recently Used)

์—ฌ๊ธฐ์„œ๋Š” LRU cache ์ „๋žต์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

LRU cache ์ „๋žต์€ ์ตœ๊ทผ์— ์‚ฌ์šฉ๋œ ๋ฐ์ดํ„ฐ์ผ์ˆ˜๋ก ์•ž์œผ๋กœ๋„ ์‚ฌ์šฉ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค๋ผ๋Š” ๊ฐ€์„ค์„ ๋ฐ”ํƒ•์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค. ์ด ์ „๋žต์€ ๊ฐ€์žฅ ์˜ค๋žซ๋™์•ˆ ์ฐธ์กฐ(์‚ฌ์šฉ)๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜์—ฌ ๊ณต๊ฐ„์„ ํ™•๋ณดํ•˜๊ณ , ์กฐํšŒํ•œ ๋ฐ์ดํ„ฐ๋Š” ๊ฐ€์žฅ ์ตœ๊ทผ์— ์‚ฌ์šฉ๋œ ๋ฐ์ดํ„ฐ๋กœ ๊ฐ„์ฃผํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ œํ•œ๋˜์–ด์žˆ๊ณ  ์ž์ฃผ ์—‘์„ธ์Šคํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ๋น ๋ฅด๊ฒŒ ์—‘์„ธ์Šค ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

LRU cache์˜ ์„ธ๋ถ€ ๋™์ž‘๋ฐฉ์‹์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋  ๊ฒฝ์šฐ,

    • ์บ์‹œ์˜ ๊ณต๊ฐ„์ด ๊ฐ€๋“์ฐจ์ง€ ์•Š์€ ๊ฒฝ์šฐ, ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์žฅ ์ตœ๊ทผ ์œ„์น˜๋กœ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค.

    • ์บ์‹œ์˜ ๊ณต๊ฐ„์ด ๊ฐ€๋“์ฐฌ ๊ฒฝ์šฐ, ๊ฐ€์žฅ ์˜ค๋žซ๋™์•ˆ ์‚ฌ์šฉ๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ , ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์žฅ ์ตœ๊ทผ ์œ„์น˜๋กœ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค.

  • ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๊ฒฝ์šฐ,

    • ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์žฅ ์ตœ๊ทผ ์œ„์น˜๋กœ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค.

๐Ÿ“š ์šฉ์–ด๋„ ์•Œ์•„๋‘๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

  • Cache Hit: ์บ์‹œ์— ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์–ด, ๋””์Šคํฌ์— ์ ‘๊ทผํ•˜์ง€ ์•Š๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ

  • Cache Miss: ์บ์‹œ์— ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒƒ

  • Eviction: ์บ์‹œ ๊ณต๊ฐ„์ด ๊ฝ‰์ฐจ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ

LRU cache ๋™์ž‘๋ฐฉ์‹ ์•Œ์•„๋ณด๊ธฐ

์•„๋ž˜์˜ ์˜ˆ์‹œ์—์„œ๋Š” ๊ฐ€์žฅ ์™ผ์ชฝ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์žฅ ์ตœ์‹ ์— [์กฐํšŒ/์‚ฝ์ž…] ๋ฐ์ดํ„ฐ๋ผ๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

# ์บ์‹œ ํฌ๊ธฐ๊ฐ€ 3์ธ ์ดˆ๊ธฐ ์ƒํƒœ
[empty, empty, empty]

# ๋ฐ์ดํ„ฐ 1 ์ ‘๊ทผ, ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— 1์ถ”๊ฐ€
[1, empty, empty]

# ๋ฐ์ดํ„ฐ 2 ์ ‘๊ทผ, ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— 2์ถ”๊ฐ€, 2 ๊ฐ€์žฅ ์ฒ˜์Œ์œผ๋กœ
[2, 1, empty]

# ๋ฐ์ดํ„ฐ 3 ์ ‘๊ทผ, ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— 3์ถ”๊ฐ€, 3 ๊ฐ€์žฅ ์ฒ˜์Œ์œผ๋กœ
[3, 2, 1]

# ๋ฐ์ดํ„ฐ 4 ์ ‘๊ทผ, 4 ๋ฐ์ดํ„ฐ ์—†๊ธฐ ๋•Œ๋ฌธ์— 4์ถ”๊ฐ€, 4 ๊ฐ€์žฅ ์ฒ˜์Œ์œผ๋กœ, ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ์›์†Œ(1) ์ œ๊ฑฐ
[4, 3, 2]

# ๋ฐ์ดํ„ฐ 2 ์ ‘๊ทผ, ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๊ณ , 2 ๊ฐ€์žฅ ์ฒ˜์Œ์œผ๋กœ
[2, 4, 3]

# ๋ฐ์ดํ„ฐ 4 ์ ‘๊ทผ, ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๊ณ , 4 ๊ฐ€์žฅ ์ฒ˜์Œ์œผ๋กœ
[4, 2, 3] # 4๊ฐ€ ๊ฐ€์žฅ ์ตœ๊ทผ ์‚ฌ์šฉ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋จ

Python์—์„œ LRU ์บ์‹œ ์‚ฌ์šฉ

functools ๋ชจ๋“ˆ์˜ lru_cache ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ LRU ์บ์‹œ๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import random

from functools import lru_cache


def fetch_num(n: int):
    print(f'Fetching num: {n}')
    return n


@lru_cache(maxsize=3)
def get_num(n: int) -> int:
    return fetch_num(n)


def main():
    for _ in range(10):
        get_num(random.randint(0, 10))

    print(get_num.cache_info())


if __name__ == '__main__':
    main()


# Fetching num: 1
# Fetching num: 7
# Fetching num: 2
# Fetching num: 0
# Fetching num: 9
# Fetching num: 5
# CacheInfo(hits=4, misses=6, maxsize=3, currsize=3) << ๋žœ๋ค์œผ๋กœ ๋ณ€๊ฒฝ๋จ

maxsize ์˜ ์˜๋ฏธ

lru_cache ๋ฐ์ฝ”๋ ˆ์ด์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ maxsize๋Š” ์บ์‹œ์— ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ํ•ญ๋ชฉ ์ˆ˜๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์บ์‹œ๊ฐ€ ์ด ํฌ๊ธฐ๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ์ตœ๊ทผ์— ๊ฐ€์žฅ ์ ๊ฒŒ ์‚ฌ์šฉ๋œ ํ•ญ๋ชฉ์€ ์ƒˆ ํ•ญ๋ชฉ์„ ์œ„ํ•œ ๊ณต๊ฐ„์„ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•ด ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค.

๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ maxsize์˜ ๊ธฐ๋ณธ ๊ฐ’์€ 128์ž…๋‹ˆ๋‹ค. ์ด ๊ฐ’์„ None์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ์บ์‹œ๊ฐ€ ์ œํ•œ ์—†์ด ์ปค์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

LRU ์บ์‹œ ํด๋ž˜์Šค ๊ตฌํ˜„

from collections import OrderedDict


class LRUCache:
    def __init__(self, max_size):
        self.cache = OrderedDict()
        self.max_size = max_size

    def get(self, key):
        if key in self.cache:
            # ํ‚ค๋ฅผ ๊ฐ€์žฅ ์ตœ๊ทผ ์‚ฌ์šฉ๋œ ์ƒํƒœ๋กœ ๊ฐฑ์‹ 
            value = self.cache.pop(key)
            self.cache[key] = value
            return value
        return None

    def put(self, key, value):
        if key in self.cache:
            # ๊ธฐ์กด ํ‚ค๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์ตœ๊ทผ ์‚ฌ์šฉ๋œ ์ƒํƒœ๋กœ ๊ฐฑ์‹ 
            self.cache.pop(key)
        elif len(self.cache) >= self.max_size:
            # ์บ์‹œ๊ฐ€ ๊ฐ€๋“ ์ฐฌ ๊ฒฝ์šฐ ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ํ•ญ๋ชฉ ์ œ๊ฑฐ
            self.cache.popitem(last=False)
        # ์ƒˆ๋กœ์šด ํ‚ค-๊ฐ’ ์Œ ์ถ”๊ฐ€
        self.cache[key] = value

    def __str__(self):
        return str(self.cache)


max_size = 3  # ์ตœ๋Œ€ ํฌ๊ธฐ๋ฅผ 3์œผ๋กœ ์„ค์ •
lru_cache = LRUCache(max_size)

lru_cache.put("a", "apple")
lru_cache.put("b", "banana")
lru_cache.put("c", "cherry")

print(lru_cache) # ์ถœ๋ ฅ: OrderedDict([('a', 'apple'), ('b', 'banana'), ('c', 'cherry')])

# ์ ‘๊ทผํ•˜์—ฌ 'a'๋ฅผ ์ตœ์‹  ์ƒํƒœ๋กœ ๊ฐฑ์‹ 
print(lru_cache.get("a"))  # ์ถœ๋ ฅ: apple
print(lru_cache)  # ์ถœ๋ ฅ: OrderedDict([('b', 'banana'), ('c', 'cherry'), ('a', 'apple')])

# ์ƒˆ๋กœ์šด ํ•ญ๋ชฉ ์ถ”๊ฐ€๋กœ ์ธํ•ด ๊ฐ€์žฅ ์˜ค๋ž˜๋œ 'b'๊ฐ€ ์ œ๊ฑฐ๋จ
lru_cache.put("d", "durian")
print(lru_cache)  # ์ถœ๋ ฅ: OrderedDict([('c', 'cherry'), ('a', 'apple'), ('d', 'durian')])

# ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ‚ค ์ ‘๊ทผ ์‹œ None ๋ฐ˜ํ™˜
print(lru_cache.get("b"))  # ์ถœ๋ ฅ: None
print(lru_cache)  # ์ถœ๋ ฅ: OrderedDict([('c', 'cherry'), ('a', 'apple'), ('d', 'durian')])

max_size = 3  # ์ตœ๋Œ€ ํฌ๊ธฐ๋ฅผ 3์œผ๋กœ ์„ค์ •
lru_cache = LRUCache(max_size)

lru_cache.put("a", "apple")
lru_cache.put("b", "banana")
lru_cache.put("c", "cherry")

print(lru_cache)  # ์ถœ๋ ฅ: OrderedDict([('a', 'apple'), ('b', 'banana'), ('c', 'cherry')])

# ์ ‘๊ทผํ•˜์—ฌ 'a'๋ฅผ ์ตœ์‹  ์ƒํƒœ๋กœ ๊ฐฑ์‹ 
print(lru_cache.get("a"))  # ์ถœ๋ ฅ: apple
print(lru_cache)  # ์ถœ๋ ฅ: OrderedDict([('b', 'banana'), ('c', 'cherry'), ('a', 'apple')])

# ์ƒˆ๋กœ์šด ํ•ญ๋ชฉ ์ถ”๊ฐ€๋กœ ์ธํ•ด ๊ฐ€์žฅ ์˜ค๋ž˜๋œ 'b'๊ฐ€ ์ œ๊ฑฐ๋จ
lru_cache.put("d", "durian")
print(lru_cache)  # ์ถœ๋ ฅ: OrderedDict([('c', 'cherry'), ('a', 'apple'), ('d', 'durian')])

# ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ‚ค ์ ‘๊ทผ ์‹œ None ๋ฐ˜ํ™˜
print(lru_cache.get("b"))  # ์ถœ๋ ฅ: None
print(lru_cache)  # ์ถœ๋ ฅ: OrderedDict([('c', 'cherry'), ('a', 'apple'), ('d', 'durian')])


# LRUCache ํด๋ž˜์Šค
- __init__(self, max_size): ์ตœ๋Œ€ ์บ์‹œ ํฌ๊ธฐ๋ฅผ ์„ค์ •ํ•˜๋Š” ์ƒ์„ฑ์ž์ž…๋‹ˆ๋‹ค.
- get(self, key): ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋ฉด ๊ฐ€์žฅ ์ตœ๊ทผ ์‚ฌ์šฉ๋œ ์ƒํƒœ๋กœ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.
- put(self, key, value): ํ‚ค-๊ฐ’ ์Œ์„ ์บ์‹œ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์บ์‹œ๊ฐ€ ๊ฐ€๋“ ์ฐจ๋ฉด ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ํ•ญ๋ชฉ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
- __str__(self): ์บ์‹œ์˜ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

- put ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์บ์‹œ์— ๋ฌธ์ž์—ด ๊ฐ’์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
- get ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์บ์‹œ์—์„œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ณ , ์ตœ๊ทผ ์‚ฌ์šฉ๋œ ์ƒํƒœ๋กœ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.
- ์บ์‹œ๊ฐ€ ๊ฐ€๋“ ์ฐฌ ์ƒํƒœ์—์„œ ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ํ•ญ๋ชฉ์ด ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค.

Last updated