从零构建一个 Mini Redis:理解高性能数据结构的核心原理

最好的学习方式:造轮子

Redis 是面试必问、工作必用的中间件。但大多数人停留在"会用""能背八股"的层面。这篇文章带你从零写一个 Mini Redis,彻底搞懂底层原理。

第一层:网络层(IO 多路复用)

Redis 的单线程高性能,核心是 epoll。我们用 Python 的 selectors 模块模拟:

import selectors, socket

sel = selectors.DefaultSelector()

def accept(sock, mask):
    conn, addr = sock.accept()
    conn.setblocking(False)
    sel.register(conn, selectors.EVENT_READ, read)

def read(conn, mask):
    data = conn.recv(1024)
    if data:
        response = process_command(data)
        conn.send(response)
    else:
        sel.unregister(conn)
        conn.close()

server = socket.socket()
server.bind(('0.0.0.0', 6379))
server.listen(128)
server.setblocking(False)
sel.register(server, selectors.EVENT_READ, accept)

while True:
    events = sel.select()
    for key, mask in events:
        key.data(key.fileobj, mask)

第二层:协议解析(RESP)

Redis 使用 RESP(REdis Serialization Protocol),非常简单。

def parse_resp(data):
    """解析 RESP 协议"""
    lines = data.decode().split('\r\n')
    if lines[0][0] == '*':  # 数组
        count = int(lines[0][1:])
        args = []
        idx = 1
        for _ in range(count):
            if lines[idx][0] == '$':
                length = int(lines[idx][1:])
                idx += 1
                args.append(lines[idx])
                idx += 1
        return args
    return [lines[0]]

def encode_resp(data):
    """编码 RESP 响应"""
    if isinstance(data, str):
        return f"+{data}\r\n".encode()
    if data is None:
        return "$-1\r\n".encode()
    if isinstance(data, int):
        return f":{data}\r\n".encode()

第三层:核心数据结构——跳表(Skip List)

Redis 的 Sorted Set 底层是跳表。跳表 = 多层索引的有序链表

import random

class SkipNode:
    def __init__(self, key, value, level):
        self.key = key
        self.value = value
        self.forward = [None] * (level + 1)

class SkipList:
    MAX_LEVEL = 16
    
    def __init__(self):
        self.head = SkipNode(None, None, self.MAX_LEVEL)
        self.level = 0
    
    def random_level(self):
        level = 0
        while random.random() < 0.25 and level < self.MAX_LEVEL:
            level += 1
        return level
    
    def insert(self, key, value):
        update = [None] * (self.MAX_LEVEL + 1)
        current = self.head
        
        for i in range(self.level, -1, -1):
            while current.forward[i] and current.forward[i].key < key:
                current = current.forward[i]
            update[i] = current
        
        level = self.random_level()
        if level > self.level:
            for i in range(self.level + 1, level + 1):
                update[i] = self.head
            self.level = level
        
        node = SkipNode(key, value, level)
        for i in range(level + 1):
            node.forward[i] = update[i].forward[i]
            update[i].forward[i] = node

跳表的插入/查询/删除复杂度都是 O(log n),而且实现比红黑树简单得多。

第四层:过期机制

class MiniRedis:
    def __init__(self):
        self.store = {}  # key -> value
        self.expires = {}  # key -> timestamp
    
    def get(self, key):
        # 惰性删除
        if key in self.expires and time.time() > self.expires[key]:
            del self.store[key]
            del self.expires[key]
            return None
        return self.store.get(key)
    
    def set(self, key, value, px=None):
        self.store[key] = value
        if px:
            self.expires[key] = time.time() + px / 1000
    
    def clean_expired(self):
        """定期随机抽查删除(Redis 的做法)"""
        keys = list(self.expires.keys())
        random.shuffle(keys)
        now = time.time()
        for key in keys[:20]:
            if self.expires[key] < now:
                del self.store[key]
                del self.expires[key]

完整架构图

Client → Socket → selectors (epoll) → RESP Parser
                                         ↓
                                    Command Router
                                    /    |    \
                              GET/SET  EXPIRE  DEL
                                    \    |    /
                                     Hash Table
                                     Skip List (ZSET)
                                     List (LIST)

下一步

你可以在 Mini Redis 上继续添加:AOF 持久化、主从复制、事务(MULTI/EXEC)、Pub/Sub、Lua 脚本支持。每一个功能的实现,都会让你对 Redis 的理解上一个台阶。