跳转到内容
Go back

Redis数据结构深度解析:从基础类型到高级应用的完整指南

Redis数据结构深度解析:从基础类型到高级应用的完整指南

Redis数据结构概述

Redis不仅仅是一个简单的key-value存储系统,它支持丰富的数据结构,这使得它能够胜任各种复杂的应用场景。理解这些数据结构的特点和底层实现,是用好Redis的关键。

Redis的核心优势

内存存储:所有数据存储在内存中,提供极快的读写速度。

丰富的数据结构:不仅支持基本的字符串,还支持列表、集合、哈希等复杂结构。

原子操作:所有操作都是原子性的,天然支持并发场景。

持久化支持:通过RDB和AOF提供数据持久化能力。

Redis数据结构分类

五种核心数据结构

其他数据结构

String(字符串)数据结构

String是Redis最基础也是最常用的数据结构,但它的功能远比想象中强大。

基本特性

存储内容

最大长度:512MB

常用命令

基础操作

# 设置和获取
SET key value
GET key

# 批量操作
MSET key1 value1 key2 value2
MGET key1 key2

# 设置过期时间
SET key value EX 3600  # 1小时后过期
SETEX key 3600 value   # 等价写法

# 条件设置
SET key value NX       # 键不存在时才设置
SET key value XX       # 键存在时才设置

数值操作

# 自增自减
INCR counter           # +1
DECR counter           # -1
INCRBY counter 5       # +5
DECRBY counter 3       # -3
INCRBYFLOAT price 0.1  # 浮点数增加

# 示例:实现分布式ID生成
INCR global:user:id    # 返回递增的用户ID

字符串操作

# 追加内容
APPEND key " world"    # 在值后追加内容

# 获取长度
STRLEN key

# 获取子串
GETRANGE key 0 4       # 获取前5个字符
SETRANGE key 6 "Redis" # 从位置6开始替换

底层实现原理

SDS(Simple Dynamic String): Redis使用自己实现的SDS而不是C语言原生字符串,主要优势:

struct sdshdr {
    int len;        // 字符串长度
    int free;       // 未使用空间长度
    char buf[];     // 字符数组
};

SDS的优势

  1. O(1)时间复杂度获取长度:直接读取len字段
  2. 缓冲区溢出保护:操作前检查空间是否足够
  3. 减少内存重分配:预分配策略减少分配次数
  4. 二进制安全:可以存储任意二进制数据

内存分配策略

使用场景

1. 缓存

// Java示例:缓存用户信息
@Service
public class UserService {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    public User getUserById(Long userId) {
        String key = "user:" + userId;
        String userJson = redisTemplate.opsForValue().get(key);
        
        if (userJson != null) {
            return JSON.parseObject(userJson, User.class);
        }
        
        // 从数据库查询
        User user = userRepository.findById(userId);
        if (user != null) {
            // 缓存1小时
            redisTemplate.opsForValue().set(key, JSON.toJSONString(user), 
                Duration.ofHours(1));
        }
        return user;
    }
}

2. 计数器

# 网站访问统计
INCR site:pv:20240410
INCR user:123:login:count

# 限流实现
SET api:user:123:limit 100 EX 3600  # 每小时限制100次
DECR api:user:123:limit

3. 分布式锁

# 获取锁
SET lock:resource:123 "client-id" NX EX 30

# 释放锁(使用Lua脚本保证原子性)
# if redis.call("get", KEYS[1]) == ARGV[1] then
#     return redis.call("del", KEYS[1])
# else
#     return 0
# end

4. Session存储

# 存储用户会话
SET session:abc123def456 '{"userId":123,"username":"john","loginTime":1712745600}' EX 1800

Hash(哈希表)数据结构

Hash结构类似于编程语言中的Map或Dictionary,非常适合存储对象。

基本特性

结构:key -> {field1: value1, field2: value2, …}

优势

常用命令

基础操作

# 设置字段
HSET user:123 name "John" age 25 email "john@example.com"

# 获取字段
HGET user:123 name
HMGET user:123 name age    # 批量获取

# 获取所有字段
HGETALL user:123

# 删除字段
HDEL user:123 email

# 检查字段是否存在
HEXISTS user:123 name

# 获取字段数量
HLEN user:123

# 获取所有字段名或值
HKEYS user:123
HVALS user:123

数值操作

# 数值字段自增
HINCRBY user:123 age 1
HINCRBYFLOAT user:123 balance 10.5

# 条件设置
HSETNX user:123 created_time "2024-04-10"  # 字段不存在时才设置

底层实现原理

Redis Hash有两种底层实现,会根据数据量自动切换:

1. ZipList(压缩列表) 当同时满足以下条件时使用:

# ZipList结构示例(内存紧凑)
[zlbytes][zltail][zllen][entry1][entry2]...[entryN][zlend]

优点:内存使用效率高 缺点:查找时间复杂度为O(n)

2. HashTable(哈希表) 当不满足ZipList条件时,自动转换为HashTable:

typedef struct dict {
    dictht ht[2];          // 两个哈希表,用于rehash
    long rehashidx;        // rehash进度,-1表示未进行
    // ...
} dict;

typedef struct dictht {
    dictEntry **table;     // 哈希表数组
    unsigned long size;    // 哈希表大小
    unsigned long sizemask;// 哈希表大小掩码
    unsigned long used;    // 已有节点数量
} dictht;

渐进式rehash: 为避免rehash时的性能问题,Redis采用渐进式rehash:

  1. 为ht[1]分配空间
  2. 将ht[0]中的数据逐步迁移到ht[1]
  3. 迁移完成后,ht[1]成为ht[0]

使用场景

1. 用户信息存储

// 存储用户信息
@Service
public class UserProfileService {
    
    public void saveUserProfile(Long userId, UserProfile profile) {
        String key = "user:profile:" + userId;
        
        Map<String, String> profileMap = new HashMap<>();
        profileMap.put("name", profile.getName());
        profileMap.put("age", String.valueOf(profile.getAge()));
        profileMap.put("email", profile.getEmail());
        profileMap.put("phone", profile.getPhone());
        
        redisTemplate.opsForHash().putAll(key, profileMap);
        redisTemplate.expire(key, Duration.ofHours(24));
    }
    
    public UserProfile getUserProfile(Long userId) {
        String key = "user:profile:" + userId;
        Map<Object, Object> profileMap = redisTemplate.opsForHash().entries(key);
        
        if (profileMap.isEmpty()) {
            return null;
        }
        
        UserProfile profile = new UserProfile();
        profile.setName((String) profileMap.get("name"));
        profile.setAge(Integer.parseInt((String) profileMap.get("age")));
        profile.setEmail((String) profileMap.get("email"));
        profile.setPhone((String) profileMap.get("phone"));
        
        return profile;
    }
}

2. 购物车实现

# 添加商品到购物车
HSET cart:user:123 product:456 2    # 商品456,数量2
HSET cart:user:123 product:789 1    # 商品789,数量1

# 获取购物车所有商品
HGETALL cart:user:123

# 更新商品数量
HINCRBY cart:user:123 product:456 1  # 数量+1

# 删除商品
HDEL cart:user:123 product:789

3. 统计信息

# 网站统计
HSET stats:20240410 pv 10000 uv 5000 orders 200 revenue 50000.00

# 用户行为统计
HINCRBY user:123:stats login_count 1
HINCRBY user:123:stats page_views 5

List(列表)数据结构

List是一个有序的字符串列表,支持在两端进行插入和删除操作。

基本特性

特点

最大长度:2^32 - 1个元素

常用命令

插入操作

# 左端插入
LPUSH mylist "world" "hello"    # 结果:["hello", "world"]

# 右端插入  
RPUSH mylist "!"                # 结果:["hello", "world", "!"]

# 指定位置插入
LINSERT mylist BEFORE "world" "beautiful"  # 在"world"前插入

# 设置指定位置的值
LSET mylist 0 "hi"             # 设置索引0的值

获取操作

# 获取指定范围的元素
LRANGE mylist 0 -1             # 获取所有元素
LRANGE mylist 0 2              # 获取前3个元素

# 获取指定位置的元素
LINDEX mylist 0                # 获取第一个元素

# 获取列表长度
LLEN mylist

删除操作

# 从两端删除
LPOP mylist                    # 删除并返回第一个元素
RPOP mylist                    # 删除并返回最后一个元素

# 阻塞式删除(用于实现队列)
BLPOP mylist 10                # 阻塞10秒等待元素

# 删除指定值
LREM mylist 2 "hello"          # 删除2个"hello"

# 修剪列表
LTRIM mylist 0 99              # 只保留前100个元素

底层实现原理

Redis List有两种底层实现:

1. QuickList(快速列表) Redis 3.2版本后的默认实现,结合了双向链表和压缩列表的优点:

typedef struct quicklist {
    quicklistNode *head;        // 头节点
    quicklistNode *tail;        // 尾节点
    unsigned long count;        // 总元素个数
    unsigned long len;          // quicklistNode节点个数
    int fill : 16;             // 单个节点的填充因子
    unsigned int compress : 16; // 压缩深度
} quicklist;

typedef struct quicklistNode {
    struct quicklistNode *prev; // 前驱节点
    struct quicklistNode *next; // 后继节点
    unsigned char *zl;          // ZipList或LZF压缩数据
    unsigned int sz;            // ziplist的字节数
    unsigned int count : 16;    // ziplist中的元素个数
    // ...
} quicklistNode;

QuickList的优势

配置参数

# 单个ziplist的最大字节数或元素个数
list-max-ziplist-size -2

# 压缩深度,0表示不压缩
list-compress-depth 0

使用场景

1. 消息队列

// 生产者
@Service
public class MessageProducer {
    
    public void sendMessage(String queue, String message) {
        // 从右端插入,实现FIFO队列
        redisTemplate.opsForList().rightPush(queue, message);
    }
}

// 消费者
@Service
public class MessageConsumer {
    
    public String consumeMessage(String queue, int timeout) {
        // 从左端阻塞式获取,实现可靠消费
        List<String> result = redisTemplate.opsForList()
            .leftPop(queue, Duration.ofSeconds(timeout));
        return result.isEmpty() ? null : result.get(0);
    }
}

2. 最新动态列表

# 用户发布动态
LPUSH user:123:timeline "发布了一条新动态" 

# 获取最新10条动态
LRANGE user:123:timeline 0 9

# 限制动态数量(只保留最新1000条)
LTRIM user:123:timeline 0 999

3. 栈实现

# 压栈
LPUSH stack:user:123 "page1" "page2" "page3"

# 弹栈
LPOP stack:user:123

Set(集合)数据结构

Set是一个无序的字符串集合,元素唯一,支持集合运算。

基本特性

特点

常用命令

基础操作

# 添加元素
SADD myset "apple" "banana" "orange"

# 删除元素
SREM myset "banana"

# 获取所有元素
SMEMBERS myset

# 随机获取元素
SRANDMEMBER myset 2            # 随机获取2个元素
SPOP myset                     # 随机删除并返回一个元素

# 检查元素是否存在
SISMEMBER myset "apple"

# 获取集合大小
SCARD myset

集合运算

# 创建测试集合
SADD set1 "a" "b" "c" "d"
SADD set2 "c" "d" "e" "f"

# 交集
SINTER set1 set2               # 结果:["c", "d"]
SINTERSTORE result set1 set2   # 将交集存储到result集合

# 并集
SUNION set1 set2               # 结果:["a", "b", "c", "d", "e", "f"]
SUNIONSTORE result set1 set2

# 差集
SDIFF set1 set2                # 结果:["a", "b"]
SDIFFSTORE result set1 set2

底层实现原理

Redis Set有两种底层实现:

1. IntSet(整数集合) 当集合只包含整数且元素数量较少时使用:

typedef struct intset {
    uint32_t encoding;          // 编码类型
    uint32_t length;           // 元素个数
    int8_t contents[];         // 元素数组
} intset;

编码类型

升级机制:当添加的元素超出当前编码范围时,会升级编码类型。

2. HashTable(哈希表) 当不满足IntSet条件时使用HashTable,只使用键,值设为NULL。

使用场景

1. 标签系统

# 给文章添加标签
SADD article:123:tags "Redis" "NoSQL" "Database" "Cache"

# 获取文章标签
SMEMBERS article:123:tags

# 查找有特定标签的文章
SISMEMBER article:123:tags "Redis"

# 统计标签数量
SCARD article:123:tags

2. 去重

// 统计独立访客
@Service
public class VisitorService {
    
    public void recordVisitor(String date, String userId) {
        String key = "visitors:" + date;
        redisTemplate.opsForSet().add(key, userId);
        // 设置过期时间
        redisTemplate.expire(key, Duration.ofDays(7));
    }
    
    public long getUniqueVisitors(String date) {
        String key = "visitors:" + date;
        return redisTemplate.opsForSet().size(key);
    }
    
    public Set<String> getCommonVisitors(String date1, String date2) {
        String key1 = "visitors:" + date1;
        String key2 = "visitors:" + date2;
        return redisTemplate.opsForSet().intersect(key1, key2);
    }
}

3. 权限管理

# 用户权限
SADD user:123:permissions "read" "write" "delete"

# 角色权限
SADD role:admin:permissions "read" "write" "delete" "admin"

# 检查用户是否有某权限
SISMEMBER user:123:permissions "write"

# 获取用户和角色的共同权限
SINTER user:123:permissions role:admin:permissions

Zset(有序集合)数据结构

Zset(Sorted Set)结合了Set和List的特点,既保证元素唯一性,又维护有序性。

基本特性

特点

应用:排行榜、优先队列、延时队列等

常用命令

基础操作

# 添加元素
ZADD leaderboard 100 "alice" 200 "bob" 150 "charlie"

# 获取指定范围的元素(按分数排序)
ZRANGE leaderboard 0 -1                    # 所有元素,分数从低到高
ZRANGE leaderboard 0 -1 WITHSCORES         # 包含分数
ZREVRANGE leaderboard 0 2                  # 前3名(分数从高到低)

# 按分数范围获取
ZRANGEBYSCORE leaderboard 100 200          # 分数在100-200之间
ZREVRANGEBYSCORE leaderboard 200 100       # 分数在200-100之间(降序)

# 获取元素排名
ZRANK leaderboard "alice"                  # 升序排名(从0开始)
ZREVRANK leaderboard "alice"               # 降序排名

# 获取元素分数
ZSCORE leaderboard "alice"

# 获取集合大小
ZCARD leaderboard

# 获取分数范围内的元素个数
ZCOUNT leaderboard 100 200

更新操作

# 增加分数
ZINCRBY leaderboard 50 "alice"             # alice分数+50

# 删除元素
ZREM leaderboard "bob"

# 按排名删除
ZREMRANGEBYRANK leaderboard 0 0            # 删除第一名

# 按分数删除
ZREMRANGEBYSCORE leaderboard 0 100         # 删除分数0-100的元素

集合操作

# 创建两个有序集合
ZADD zset1 1 "a" 2 "b" 3 "c"
ZADD zset2 2 "b" 3 "c" 4 "d"

# 并集
ZUNIONSTORE result 2 zset1 zset2           # 分数相加
ZUNIONSTORE result 2 zset1 zset2 WEIGHTS 1 2  # 给zset2的分数乘以2

# 交集
ZINTERSTORE result 2 zset1 zset2           # 只保留共同元素

底层实现原理

Zset使用两种数据结构的组合:

1. 跳跃表(Skip List) 用于范围查询和排序操作:

typedef struct zskiplist {
    struct zskiplistNode *header, *tail;   // 头尾节点
    unsigned long length;                   // 节点数量
    int level;                             // 最大层数
} zskiplist;

typedef struct zskiplistNode {
    sds ele;                               // 元素值
    double score;                          // 分数
    struct zskiplistNode *backward;        // 后退指针
    struct zskiplistLevel {
        struct zskiplistNode *forward;     // 前进指针
        unsigned long span;                // 跨度
    } level[];                            // 层级数组
} zskiplistNode;

跳跃表的优势

2. 哈希表 用于O(1)时间查找元素:

为什么不用平衡树

使用场景

1. 排行榜系统

@Service
public class LeaderboardService {
    
    // 更新用户分数
    public void updateScore(String userId, double score) {
        String key = "game:leaderboard";
        redisTemplate.opsForZSet().incrementScore(key, userId, score);
    }
    
    // 获取排行榜前N名
    public List<UserScore> getTopN(int n) {
        String key = "game:leaderboard";
        Set<ZSetOperations.TypedTuple<String>> result = 
            redisTemplate.opsForZSet().reverseRangeWithScores(key, 0, n - 1);
        
        return result.stream()
            .map(tuple -> new UserScore(tuple.getValue(), tuple.getScore()))
            .collect(Collectors.toList());
    }
    
    // 获取用户排名
    public Long getUserRank(String userId) {
        String key = "game:leaderboard";
        Long rank = redisTemplate.opsForZSet().reverseRank(key, userId);
        return rank != null ? rank + 1 : null; // 排名从1开始
    }
    
    // 获取用户周围的排名
    public List<UserScore> getUserNeighbors(String userId, int range) {
        String key = "game:leaderboard";
        Long rank = redisTemplate.opsForZSet().reverseRank(key, userId);
        if (rank == null) return Collections.emptyList();
        
        long start = Math.max(0, rank - range);
        long end = rank + range;
        
        Set<ZSetOperations.TypedTuple<String>> result = 
            redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        
        return result.stream()
            .map(tuple -> new UserScore(tuple.getValue(), tuple.getScore()))
            .collect(Collectors.toList());
    }
}

2. 延时队列

@Service
public class DelayedQueueService {
    
    // 添加延时任务
    public void addDelayedTask(String taskId, String taskData, long delaySeconds) {
        String key = "delayed:queue";
        long executeTime = System.currentTimeMillis() / 1000 + delaySeconds;
        
        // 使用执行时间作为分数
        redisTemplate.opsForZSet().add(key, taskId + ":" + taskData, executeTime);
    }
    
    // 获取到期的任务
    public List<String> getExpiredTasks(int count) {
        String key = "delayed:queue";
        long currentTime = System.currentTimeMillis() / 1000;
        
        Set<String> tasks = redisTemplate.opsForZSet()
            .rangeByScore(key, 0, currentTime, 0, count);
        
        // 删除已获取的任务
        if (!tasks.isEmpty()) {
            redisTemplate.opsForZSet().remove(key, tasks.toArray());
        }
        
        return new ArrayList<>(tasks);
    }
}

3. 时间序列数据

# 存储用户访问时间
ZADD user:123:visits 1712745600 "page1" 1712745660 "page2" 1712745720 "page3"

# 获取最近1小时的访问
ZRANGEBYSCORE user:123:visits (1712742000 1712745600

# 统计时间范围内的访问次数
ZCOUNT user:123:visits 1712742000 1712745600

其他数据结构简介

除了上述五种核心数据结构,Redis还提供了一些高级数据结构:

Bitmap(位图)

HyperLogLog

Geo(地理位置)

Stream(流)

这些高级数据结构在特定场景下非常有用,但日常开发中主要还是使用前面介绍的五种核心数据结构。

性能分析和优化建议

时间复杂度对比

数据结构添加删除查找遍历
StringO(1)O(1)O(1)-
HashO(1)O(1)O(1)O(n)
ListO(1)O(n)O(n)O(n)
SetO(1)O(1)O(1)O(n)
ZsetO(log n)O(log n)O(1)O(log n + m)

内存使用优化

1. 选择合适的数据结构

# 不好的设计:为每个用户属性创建单独的key
SET user:123:name "John"
SET user:123:age "25"
SET user:123:email "john@example.com"

# 好的设计:使用Hash存储相关属性
HSET user:123 name "John" age "25" email "john@example.com"

2. 利用压缩配置

# Redis配置优化
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64

3. 设置合理的过期时间

// 避免内存泄漏
redisTemplate.opsForValue().set(key, value, Duration.ofMinutes(30));

性能监控

监控关键指标

# 内存使用情况
INFO memory

# 命令统计
INFO commandstats

# 慢查询日志
SLOWLOG GET 10

# 客户端连接
INFO clients

实际应用最佳实践

1. 缓存设计模式

Cache-Aside模式

@Service
public class ProductService {
    
    public Product getProduct(Long productId) {
        String key = "product:" + productId;
        
        // 1. 先查缓存
        String productJson = redisTemplate.opsForValue().get(key);
        if (productJson != null) {
            return JSON.parseObject(productJson, Product.class);
        }
        
        // 2. 查数据库
        Product product = productRepository.findById(productId);
        if (product != null) {
            // 3. 写入缓存
            redisTemplate.opsForValue().set(key, JSON.toJSONString(product), 
                Duration.ofMinutes(30));
        }
        
        return product;
    }
    
    public void updateProduct(Product product) {
        // 1. 更新数据库
        productRepository.save(product);
        
        // 2. 删除缓存
        String key = "product:" + product.getId();
        redisTemplate.delete(key);
    }
}

2. 分布式锁实现

@Component
public class DistributedLock {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    private static final String UNLOCK_SCRIPT = 
        "if redis.call('get', KEYS[1]) == ARGV[1] then " +
        "return redis.call('del', KEYS[1]) " +
        "else return 0 end";
    
    public boolean tryLock(String key, String value, long expireTime) {
        Boolean result = redisTemplate.opsForValue()
            .setIfAbsent(key, value, Duration.ofSeconds(expireTime));
        return Boolean.TRUE.equals(result);
    }
    
    public boolean unlock(String key, String value) {
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setScriptText(UNLOCK_SCRIPT);
        script.setResultType(Long.class);
        
        Long result = redisTemplate.execute(script, 
            Collections.singletonList(key), value);
        return Long.valueOf(1).equals(result);
    }
    
    public <T> T executeWithLock(String key, long expireTime, 
                                Supplier<T> supplier) {
        String value = UUID.randomUUID().toString();
        
        if (tryLock(key, value, expireTime)) {
            try {
                return supplier.get();
            } finally {
                unlock(key, value);
            }
        } else {
            throw new RuntimeException("获取锁失败");
        }
    }
}

3. 限流实现

@Service
public class RateLimiter {
    
    // 滑动窗口限流
    public boolean isAllowed(String key, int limit, int windowSize) {
        long now = System.currentTimeMillis();
        long windowStart = now - windowSize * 1000L;
        
        String script = 
            "redis.call('zremrangebyscore', KEYS[1], 0, ARGV[1]) " +
            "local count = redis.call('zcard', KEYS[1]) " +
            "if count < tonumber(ARGV[2]) then " +
            "  redis.call('zadd', KEYS[1], ARGV[3], ARGV[3]) " +
            "  redis.call('expire', KEYS[1], ARGV[4]) " +
            "  return 1 " +
            "else " +
            "  return 0 " +
            "end";
        
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(script);
        redisScript.setResultType(Long.class);
        
        Long result = redisTemplate.execute(redisScript,
            Collections.singletonList(key),
            String.valueOf(windowStart),
            String.valueOf(limit),
            String.valueOf(now),
            String.valueOf(windowSize));
        
        return Long.valueOf(1).equals(result);
    }
    
    // 令牌桶限流
    public boolean acquireToken(String key, int capacity, int refillRate) {
        String script = 
            "local key = KEYS[1] " +
            "local capacity = tonumber(ARGV[1]) " +
            "local tokens = tonumber(ARGV[2]) " +
            "local interval = tonumber(ARGV[3]) " +
            "local current = redis.call('hmget', key, 'tokens', 'last_refill') " +
            "local now = tonumber(ARGV[4]) " +
            "local current_tokens = tonumber(current[1]) or capacity " +
            "local last_refill = tonumber(current[2]) or now " +
            "local elapsed = now - last_refill " +
            "local new_tokens = math.min(capacity, current_tokens + math.floor(elapsed / interval) * tokens) " +
            "if new_tokens >= 1 then " +
            "  redis.call('hmset', key, 'tokens', new_tokens - 1, 'last_refill', now) " +
            "  redis.call('expire', key, 3600) " +
            "  return 1 " +
            "else " +
            "  redis.call('hmset', key, 'tokens', new_tokens, 'last_refill', now) " +
            "  redis.call('expire', key, 3600) " +
            "  return 0 " +
            "end";
        
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(script);
        redisScript.setResultType(Long.class);
        
        Long result = redisTemplate.execute(redisScript,
            Collections.singletonList(key),
            String.valueOf(capacity),
            String.valueOf(refillRate),
            String.valueOf(1000), // 1秒的间隔
            String.valueOf(System.currentTimeMillis()));
        
        return Long.valueOf(1).equals(result);
    }
}

总结

Redis的五种核心数据结构是其强大功能的基础,每种数据结构都有其特定的使用场景:

五种核心数据结构总结

使用建议

  1. 根据业务场景选择合适的数据结构
  2. 理解底层实现原理,避免性能陷阱
  3. 合理设置过期时间,避免内存泄漏
  4. 使用Redis内置的原子操作保证数据一致性

性能要点

掌握这五种核心数据结构的特点和使用技巧,就能应对大部分Redis应用场景,构建高性能的缓存系统。


Share this post on:

Previous Post
Redis线程模型深度解析:单线程为何如此高效?
Next Post
MySQL性能调优实战指南:从问题发现到解决的完整流程