Primrose Docs
  • Home
    • ⛓️Blockchain
      • Avalanche
        • What is AVAX?
      • Ethereum
        • Ethereum Cancun Upgrade Explained(draft)
        • go-ethereum: gas estimate
        • Blockchain Transaction Lifecycle
        • Mempool
        • Gas optimization in Solidity, Ethereum
      • Solidity DeepDive
        • Meta transaction
        • solidity: patterns
        • UUPS vs Transparent
        • Solidity Interface
        • Smart contract storage
        • ERC-2981 Contract
        • Solidity modifier
        • Solidity delete keyword
        • How To Make NFTs with On-Chain Metadata - Hardhat and JavaScript
        • How to Build "Buy Me a Coffee" DeFi dapp
        • How to Develop an NFT Smart Contract (ERC 721) with Alchemy
        • Upgradeable Contract
        • Smart Contract Verification
      • Common
        • Eigenlayer
        • MultiSig(draft)
        • Chain-Based Proof-of- Stake, BFT-Style Proof-of-Stake
        • Byzantine Fault Tolerance
        • Zero-knowledge
        • Hierarchical Deterministic Wallet
        • Maker DAO
        • Defi
        • Uniswap
        • IBC
        • Cosmos
        • Gossip Protocol
        • Tendermint
        • UTXO vs Account
        • Blockchain Layer
        • Consensus Algorithm
        • How does mining work?
        • Immutable Ledger
        • SHA256 Hash
        • Filecoin
        • IPFS - InterPlanetary File System
        • IPFS와 파일코인
        • Livepeer
        • Layer 0
      • Bitcoin
        • BIP for HD Wallet
        • P2WPKH
        • Segwit vs Native Segwit
    • 📖Languages
      • Javascript/Typescript
        • Hoisting
        • This value in Javascript
        • Execution Context
        • About Javscript
        • tsconfig.json
        • Nest js Provider
        • 'return await promise' vs 'return promise'
      • Python
        • Pythonic
        • Python: Iterable, Iterator
        • Uvicorn & Gunicorn
        • WSGI, ASGI
        • Python docstring
        • Decorator in Python
        • Namespace in Python
        • Python Method
      • Go
        • GORM+MySQL Connection Pool
        • Context in golang
        • How to sign Ethereum EIP-1559 transactions using AWS KMS
        • Mongo DB in golang(draft)
        • Golang HTTP Package
        • Panic
        • Golang new/make
        • golang container package
        • errgroup in golang
        • Generic Programming in Golang
        • Goroutine(draft)
    • 📝Database
      • MongoDB in golang
      • Nested loop join, Hash join
      • DB Query plan
      • Index
      • Optimistic Lock Pessimistic Lock
    • 💻Computer Science
      • N+1 query in go
      • Web server 를 구성할 때 Thread, Process 개수를 어떻게 정할 것인가?
      • CAP
      • Socket programming
      • DNS, IP
      • URL, URI
      • TLS과 SSL
      • Caching(draft)
      • Building Microservices: Micro Service 5 Deploy Principle
      • Red Black Tree
      • AOP
      • Distributed Lock
      • VPC
      • Docker
      • All about Session and JWT
      • Closure
      • Singleton Pattern
      • TCP 3 way handshake & 4 way handshake
      • Race Condition
      • Process Address Space 
      • Call by value, Call by reference, Call by assignment
      • Zookeeper, ETCD
      • URL Shortening
      • Raft consensus
      • Sharding, Partitioning
    • 📒ETC
      • K8S SIGTERM
      • SQS
      • Git Branch Strategy: Ship / Show / Ask
      • Kafka
      • Redis Data Types
      • CI/CD
      • How does Google design APIs?
      • Minishell (42 cursus)
      • Coroutine & Subroutine
      • Redis
Powered by GitBook
On this page
  1. Home
  2. Computer Science

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가 더 적합할 수 있다.

PreviousTLS과 SSLNextBuilding Microservices: Micro Service 5 Deploy Principle

Last updated 1 year ago

💻