MST

星途 面试题库

面试题:Redis链表在分布式缓存系统中的基础应用

请阐述如何利用Redis链表的特性来设计分布式缓存系统中的缓存淘汰策略,比如LRU(最近最少使用)算法,简要说明实现思路并给出关键代码片段(语言不限)。
43.5万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

利用Redis链表特性设计LRU缓存淘汰策略的实现思路

  1. 数据结构
    • 使用Redis的双向链表(Redis的链表实现为双向链表)来维护缓存数据的访问顺序。链表中的每个节点对应一个缓存数据项。
    • 同时使用一个哈希表(Redis的哈希结构)来存储缓存数据,哈希表的键为缓存数据的标识,值为指向链表中对应节点的指针。这样可以在O(1)时间复杂度内根据键找到对应的链表节点。
  2. 访问操作
    • 当缓存命中时,将对应链表节点移动到链表头部,表示该数据最近被访问。如果是新数据,则在链表头部插入新节点,并在哈希表中添加相应记录。
  3. 淘汰操作
    • 当缓存满时,删除链表尾部的节点(最近最少使用的节点),并同时从哈希表中删除相应的记录。

关键代码片段(以Python为例,借助redis - py库模拟实现)

import redis

# 初始化Redis连接
r = redis.Redis(host='localhost', port=6379, db = 0)

# 链表节点类
class Node:
    def __init__(self, key, value):
        self.key = key
        self.value = value
        self.prev = None
        self.next = None

class LRUCache:
    def __init__(self, capacity):
        self.capacity = capacity
        self.cache = {}
        self.head = Node(None, None)
        self.tail = Node(None, None)
        self.head.next = self.tail
        self.tail.prev = self.head

    # 将节点移动到链表头部
    def move_to_head(self, node):
        self.remove_node(node)
        self.add_to_head(node)

    # 在链表头部添加节点
    def add_to_head(self, node):
        node.next = self.head.next
        node.prev = self.head
        self.head.next.prev = node
        self.head.next = node

    # 删除节点
    def remove_node(self, node):
        node.prev.next = node.next
        node.next.prev = node.prev

    # 删除尾部节点
    def pop_tail(self):
        node = self.tail.prev
        self.remove_node(node)
        return node

    # 获取缓存值
    def get(self, key):
        if key in self.cache:
            node = self.cache[key]
            self.move_to_head(node)
            return node.value
        return -1

    # 设置缓存值
    def put(self, key, value):
        if key in self.cache:
            node = self.cache[key]
            node.value = value
            self.move_to_head(node)
        else:
            new_node = Node(key, value)
            self.cache[key] = new_node
            self.add_to_head(new_node)
            if len(self.cache) > self.capacity:
                removed = self.pop_tail()
                del self.cache[removed.key]

实际Redis中LRU相关实现说明

在实际Redis中,虽然没有完全按照上述纯链表 + 哈希表的方式实现LRU。Redis采用了一种近似LRU算法,每个对象头中记录了一个24位的lru字段,记录对象最后一次被访问的时间戳。当需要淘汰时,随机采样一定数量的键,然后淘汰lru字段值最小(最久未被访问)的键。通过调整采样数量等参数,可以在性能和精确性之间取得平衡。