Caching(draft)

Caching Algorithm

์บ์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋ฐ์ดํ„ฐ์˜ ์žฌ์‚ฌ์šฉ์„ ์ตœ์ ํ™”ํ•˜๊ณ , ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ์—ฌ๋Ÿฌ ์ „๋žต ์ค‘ ํ•˜๋‚˜๋‹ค.

์ฃผ๋กœ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์‚ฌ์šฉ๋œ, ํ˜น์€ ๊ฐ€์žฅ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฉ”๋ชจ๋ฆฌ์— ๋ณด๊ด€ํ•œ๋‹ค.

์ด๋Š” I/O ์ž‘์—…์˜ ๋น„์šฉ์„ ์ค„์ด๊ณ  ์‘๋‹ต ์‹œ๊ฐ„์„ ๋‹จ์ถ•ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค.

๋‹ค์Œ์€ ์บ์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์‹œ ์ด๋‹ค

LRU (Least Recently Used)

๊ฐ€์žฅ ์˜ค๋ž˜์ „์— ์‚ฌ์šฉ๋œ ํ•ญ๋ชฉ์„ ์บ์‹œ์—์„œ ์ œ๊ฑฐํ•˜๋Š” ๋ฐฉ์‹์„ ๋งํ•œ๋‹ค.

์ƒˆ๋กœ์šด ํ•ญ๋ชฉ์ด ์บ์‹œ์— ์ถ”๊ฐ€๋  ๋•Œ, ๊ฐ€์žฅ ์˜ค๋ž˜์ „์— ์ ‘๊ทผํ•œ ํ•ญ๋ชฉ๋ถ€ํ„ฐ ์ œ๊ฑฐํ•œ๋‹ค.

์ด ๋ฐฉ์‹์€ **'๊ฐ€์žฅ ์ตœ๊ทผ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ํ•ญ๋ชฉ์ด ๊ฐ€์žฅ ๋‚˜์ค‘์— ๋‹ค์‹œ ์‚ฌ์šฉ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์ž‘๋‹ค'**๋Š” ์ถ”์ •์— ๊ธฐ๋ฐ˜์„ ๋‘๊ณ  ์žˆ๋‹ค.

Redis๋ฅผ ์‚ฌ์šฉํ•ด๋ดค๋‹ค๋ฉด ๋“ค์–ด๋ดค์„ ๋ฒ•ํ•œ ์šฉ์–ด์ผ ๊ฒƒ์ด๋‹ค.

์ง์ ‘ LRU๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด ์–ด๋–ค์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

Linked list์™€ map์„ ์ด์šฉํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ ๊ฐ€๋Šฅํ•˜๋‹ค.

package main

import (
	"container/list"
	"fmt"
)

type LRUCache struct {
	size      int
	evictList *list.List
	items     map[interface{}]*list.Element
}

type entry struct {
	key   interface{}
	value interface{}
}

func NewLRUCache(size int) *LRUCache {
	return &LRUCache{size: size, evictList: list.New(), items: make(map[interface{}]*list.Element)}
}

// Set adds a value to the cache.
func (c *LRUCache) Set(key, value interface{}) {
	// Check if item already exists
	if ee, ok := c.items[key]; ok {
		c.evictList.MoveToFront(ee)
		ee.Value.(*entry).value = value
		return
	}

	// Add new item
	ent := &entry{key, value}
	entry := c.evictList.PushFront(ent)
	c.items[key] = entry

	if c.evictList.Len() > c.size {
		c.removeOldest()
	}
}

// Get retrieves an item from the cache.
func (c *LRUCache) Get(key interface{}) (value interface{}, ok bool) {
	if ent, ok := c.items[key]; ok {
		c.evictList.MoveToFront(ent)
		return ent.Value.(*entry).value, true
	}
	return
}

// removeOldest removes the oldest item from the cache.
func (c *LRUCache) removeOldest() {
	ent := c.evictList.Back()
	if ent != nil {
		c.removeElement(ent)
	}
}

// removeElement removes a given list element from the cache.
func (c *LRUCache) removeElement(e *list.Element) {
	c.evictList.Remove(e)
	kv := e.Value.(*entry)
	delete(c.items, kv.key)
}

func main() {

	lru := NewLRUCache(2)

	lru.Set("1", 1)
	lru.Set("2", 2)
	fmt.Println(lru.Get("1")) // returns 1
	lru.Set("3", 3)           // evicts key "2"
	fmt.Println(lru.Get("2")) // returns nil
	lru.Set("4", 4)           // evicts key "1"
	fmt.Println(lru.Get("1")) // returns nil
	fmt.Println(lru.Get("3"))
	fmt.Println(lru.Get("4"))
}

LFU (Least Frequently Used)

๊ฐ€์žฅ ์ ๊ฒŒ ์‚ฌ์šฉ๋œ ํ•ญ๋ชฉ์„ ์บ์‹œ์—์„œ ์ œ๊ฑฐํ•˜๋Š” ๋ฐฉ์‹์„ ๋งํ•œ๋‹ค.

์บ์‹œ๊ฐ€ ๊ฝ‰ ์ฐผ์„ ๋•Œ, ๊ฐ€์žฅ ์ ๊ฒŒ ์ ‘๊ทผ๋œ ํ•ญ๋ชฉ์ด ์ œ๊ฑฐ๋œ๋‹ค.

์ด๋Š” **'๊ณผ๊ฑฐ์— ์ž์ฃผ ์‚ฌ์šฉ๋˜์ง€ ์•Š์€ ํ•ญ๋ชฉ์€ ์•ž์œผ๋กœ๋„ ์ž์ฃผ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๋‹ค'**๋Š” ์ถ”์ •์— ๊ธฐ๋ฐ˜ํ•œ๋‹ค.

LFU๋Š” ์ฃผ๋กœ min heap์„ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ, ์ฝ”๋“œ๊ฐ€ ๊ฝค ๊ธธ ๊ฒƒ ๊ฐ™์œผ๋ฏ€๋กœ ํ•ด๋‹น ๋ถ€๋ถ„์€ ์ƒ๋žตํ•˜๊ฒ ๋‹ค.

FIFO (First In, First Out)

๊ฐ€์žฅ ์œ ๋ช…ํ•˜๋‹ค. ์„ ์ž…์„ ์ถœ.

์ƒˆ๋กœ์šด ํ•ญ๋ชฉ์ด ์บ์‹œ์— ์ถ”๊ฐ€๋  ๋•Œ, ์บ์‹œ์— ๊ฐ€์žฅ ๋จผ์ € ๋“ค์–ด์˜จ ํ•ญ๋ชฉ์ด ์ œ๊ฑฐ๋œ๋‹ค.

์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ตฌํ˜„์ด ์‰ฝ๊ณ  ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์— ์žˆ์–ด์„œ ์ผ๊ด€์„ฑ์ด ์žˆ์ง€๋งŒ ๋Š˜ ์ตœ์ ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด์ง€๋Š” ๋ชปํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ํŠน์ • ์ƒํ™ฉ์—์„œ ์žฅ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์–ด๋–ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๊ฐ€์žฅ ์ ํ•ฉํ•œ์ง€๋Š” ํŠน์ • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฐ์ดํ„ฐ์˜ ์ ‘๊ทผ ํŒจํ„ด์ด ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด LFU๊ฐ€ ์ข‹์€ ์„ฑ๋Šฅ์„ ๋ณด์ผ ์ˆ˜ ์žˆ๋‹ค. ๋ฐ˜๋ฉด, ๋ฐ์ดํ„ฐ์˜ ์ ‘๊ทผ ํŒจํ„ด์ด ์‹œ๊ฐ„์— ๋”ฐ๋ผ ํฌ๊ฒŒ ๋ณ€ํ•œ๋‹ค๋ฉด LRU๊ฐ€ ๋” ์ ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Last updated