Redis List 的详细先容

[复制链接]
发表于 2025-9-23 01:51:35 | 显示全部楼层 |阅读模式
Redis List 的详细先容

以下是 Redis List 的详细先容,从底子命令内部编码利用场景三个维度展开:

一、底子命令

Redis List 支持双向利用(头尾插入/删除),适用于队列、栈等场景,以下是核心命令分类:
1. 插入与删除


  • LPUSH / RPUSH:从左侧(头部)或右侧(尾部)插入元素。
    1. LPUSH mylist "A"        # 头部插入 "A",返回列表长度
    2. RPUSH mylist "B"        # 尾部插入 "B",返回列表长度
    复制代码
  • LPOP / RPOP:重新部或尾部移除并返回元素。
    1. LPOP mylist             # 移除头部元素 "A"
    2. RPOP mylist             # 移除尾部元素 "B"
    复制代码
  • LINSERT:在指定元素前/后插入新元素。
    1. LINSERT mylist BEFORE "B" "A"  # 在 "B" 前插入 "A"
    复制代码
  • LREM:删除指定命目的匹配元素。
    1. LREM mylist 2 "A"       # 删除最多2个 "A"
    复制代码
2. 查询与截断


  • LRANGE:获取指定索引范围内的元素。
    1. LRANGE mylist 0 -1      # 获取所有元素
    复制代码
  • LINDEX:获取指定位置的元素。
    1. LINDEX mylist 0         # 返回头部元素
    复制代码
  • LLEN:获取列表长度。
    1. LLEN mylist             # 返回列表元素总数
    复制代码
  • LTRIM:保存指定范围内的元素,别的删除。
    1. LTRIM mylist 0 4        # 仅保留前5个元素
    复制代码
3. 阻塞利用


  • BLPOP / BRPOP:阻塞式弹出元素,适用于消息队列。
    1. BLPOP task_queue 10     # 阻塞10秒等待头部元素
    复制代码

二、内部编码

Redis List 的底层实现根据数据规模动态选择编码方式:
1. listpack(Redis 7.0+)


  • 条件:当全部元素满意以下条件时利用 listpack(一连内存结构):

    • 元素数量 ≤ list-max-listpack-size​(默认 512)。
    • 每个元素的巨细 ≤ list-max-listpack-value​(默认 64 字节)。

  • 特点

    • 内存紧凑,无指针开销,适合小规模数据。
    • 规避了 ziplist 的连锁更新问题(见 Redis 7.0+ 的改进)。

2. quicklist(Redis 3.2+)


  • 触发条件:超出 listpack 容量时主动切换。
  • 结构:由多个 listpack 节点构成的双向链表,均衡内存与利用服从。

    • 每个 listpack 节点存储多个元素。
    • 支持头尾快速插入/删除(时间复杂度 O(1))。

  • 设置调优
    1. list-max-listpack-size -2    # 默认每个 listpack 节点大小 8KB
    2. list-compress-depth 0        # 压缩深度(0 表示不压缩)
    复制代码

三、利用场景

1. 消息队列


  • 生产者:LPUSH​ 插入使命到队列头部。
  • 斲丧者:BRPOP​ 阻塞获取使命,克制轮询。
    1. # 生产者
    2. LPUSH task_queue "task1"
    3. # 消费者
    4. BRPOP task_queue 0          # 0 表示无限阻塞
    复制代码
2. 最新消息排行榜


  • 插入:LPUSH​ 将新消息加入列表头部。
  • 展示:LRANGE 0 9​ 获取最新的 10 条消息。
  • 整理:LTRIM 0 99​ 保存近来 100 条消息。
    1. package com.example.redis.list;
    2. /**
    3. * 描述: 消息绑
    4. *
    5. * @author ZHOUXIAOYUE
    6. * @date 2025/4/17 15:07
    7. */
    8. import redis.clients.jedis.Jedis;
    9. import java.util.List;
    10. public class LatestNewsBoard {
    11.     public static void main(String[] args) {
    12.         // 连接 Redis 服务,默认地址 localhost 和端口 6379
    13.         Jedis jedis = new Jedis("localhost", 6379);
    14.         // 定义 Redis List 的 key
    15.         String listKey = "latest:news";
    16.         for (int x= 0; x < 100; x++) {
    17.             // 模拟插入一条新消息
    18.             String newMessage = "Breaking News: Redis 使用场景持续扩展!"+x;
    19.             // 使用 LPUSH 命令将消息插入到列表头部
    20.             jedis.lpush(listKey, newMessage);
    21.             System.out.println("新消息已插入: " + newMessage);
    22.         }
    23.         // 使用 LLEN 命令获取
    24.         // 数据清理:使用 LTRIM 保留最近 100 条消息
    25.         jedis.ltrim(listKey, 0, 99);
    26.         System.out.println("消息列表已清理,保留最近 100 条记录。");
    27.         // 展示最新 10 条消息:使用 LRANGE 命令获取列表中 0~9 范围内的消息
    28.         List<String> latestMessages = jedis.lrange(listKey, 0, 9);
    29.         System.out.println("最新的 10 条消息如下:");
    30.         for (String message : latestMessages) {
    31.             System.out.println(message);
    32.         }
    33.         // 关闭 Redis 连接
    34.         jedis.close();
    35.     }
    36. }
    复制代码
3. 汗青记载


  • 用户利用日记:LPUSH​ 记载用户举动,LTRIM​ 限制记载数量。
    1. LPUSH user:1001:logs "click_button_A"
    2. LTRIM user:1001:logs 0 99   # 保留最近 100 条日志日志
    复制代码
4. 栈(LIFO)


  • 入栈:LPUSH​,出栈:LPOP​。
    1. LPUSH my_stack "data1"
    2. LPOP my_stack               # 返回 "data1"
    复制代码
5. 数据分片存储


  • 大列表拆分为多个 quicklist 节点,淘汰单节点内存压力。

四、性能与调优建议


  • 优先利用 ​LPUSH​/​RPUSH​+​LTRIM​​:

    • 实现固定长度列表(如最新 100 条消息),克制无穷增长。

  • 克制大范围 ​LRANGE​利用

    • 获取全部数据时,利用 LRANGE 0 -1​ 大概导致阻塞,建议分页或迭代遍历。

  • 公道设置 quicklist

    • 调解 list-max-listpack-size​ 均衡内存与性能(默认 8KB)。
    • 启用压缩(list-compress-depth​)节流内存,但会增长 CPU 开销。


总结


  • 核心上风:支持双向利用、阻塞弹出、动态分片存储
  • 适用场景:消息队列、实时排行榜、利用日记、栈/队列实现。
  • 版本差异

    • Redis 3.2+ 利用 quicklist,替换旧版的 ziplist + linkedlist。
    • Redis 7.0+ 利用 listpack 替换 ziplist,提拔安全性和性能

  • 命令选择:高频写入用 LPUSH​/RPUSH​,阻塞斲丧用 BRPOP​,正确控制用 LTRIM​。

利用案例 :

  • 博客信息展示 列表
    1. package com.example.redis.list;
    2. /**
    3. * 描述:
    4. *
    5. * @author ZHOUXIAOYUE
    6. * 每篇文章使用哈希结构存储(字段:title、timestamp、content),文章的 key 格式为 "article:{id}"。
    7. * 每个用户有自己的文章列表,列表 key 格式为 "user:{id}:articles",列表中存储文章 id,利用 LPUSH 添加文章(最新的在列表头部)。
    8. * 分页获取用户文章列表,示例中获取用户 id=1 的前 10 篇文章(即列表索引 0~9),再根据文章 id 获取对应的文章详细信息。
    9. * @date 2025/4/17 16:35
    10. */
    11. import redis.clients.jedis.Jedis;
    12. import java.util.Map;
    13. import java.util.HashMap;
    14. import java.util.List;
    15. import java.util.ArrayList;
    16. public class UserArticlesPagination {
    17.     // 定义文章类
    18.     static class Article {
    19.         private String id;
    20.         private String title;
    21.         private String timestamp;
    22.         private String content;
    23.         public Article(String id, String title, String timestamp, String content) {
    24.             this.id = id;
    25.             this.title = title;
    26.             this.timestamp = timestamp;
    27.             this.content = content;
    28.         }
    29.         public String getId() {
    30.             return id;
    31.         }
    32.         public String getTitle() {
    33.             return title;
    34.         }
    35.         public String getTimestamp() {
    36.             return timestamp;
    37.         }
    38.         public String getContent() {
    39.             return content;
    40.         }
    41.     }
    42.     // 添加文章,将文章哈希存储,并将文章 id 插入到用户的文章列表中
    43.     public static void addArticle(Jedis jedis, String userId, Article article) {
    44.         // 定义文章的 key 格式: article:{id}
    45.         String articleKey = "article:" + article.getId();
    46.         Map<String, String> articleMap = new HashMap<>();
    47.         articleMap.put("title", article.getTitle());
    48.         articleMap.put("timestamp", article.getTimestamp());
    49.         articleMap.put("content", article.getContent());
    50.         // 使用 HMSET 存储文章哈希
    51.         jedis.hmset(articleKey, articleMap);
    52.         // 将文章 id 添加到用户文章列表中,列表 key 格式: user:{id}:articles
    53.         String userArticlesKey = "user:" + userId + ":articles";
    54.         // 使用 LPUSH 保证最新文章位于列表头部
    55.         jedis.lpush(userArticlesKey, article.getId());
    56.     }
    57.     // 分页获取用户的文章列表,并返回文章详情集合
    58.     public static List<Map<String, String>> getUserArticles(Jedis jedis, String userId, int page, int pageSize) {
    59.         String userArticlesKey = "user:" + userId + ":articles";
    60.         // 计算起始和结束索引(分页从 1 开始)
    61.         int start = (page - 1) * pageSize;
    62.         int end = start + pageSize - 1;
    63.         // 获取文章 id 列表
    64.         List<String> articleIds = jedis.lrange(userArticlesKey, start, end);
    65.         List<Map<String, String>> articles = new ArrayList<>();
    66.         // 根据文章 id 获取文章详情
    67.         for (String articleId : articleIds) {
    68.             String articleKey = "article:" + articleId;
    69.             Map<String, String> articleData = jedis.hgetAll(articleKey);
    70.             // 如果文章数据存在,则加入结果列表
    71.             if (!articleData.isEmpty()) {
    72.                 articles.add(articleData);
    73.             }
    74.         }
    75.         return articles;
    76.     }
    77.     public static void main(String[] args) {
    78.         // 连接 Redis 服务,默认地址 localhost 与端口 6379
    79.         Jedis jedis = new Jedis("localhost", 6379);
    80.         // 假设用户 id 为 "1",添加几篇文章测试
    81.         String userId = "1";
    82.         Article article1 = new Article("101", "Redis 入门", "2023-10-01 10:00:00", "Redis 是一个键值存储系统...");
    83.         Article article2 = new Article("102", "Redis 高级特性", "2023-10-02 11:30:00", "Redis 支持多种数据结构...");
    84.         Article article3 = new Article("103", "Redis 实战案例", "2023-10-03 14:20:00", "通过案例来掌握 Redis 应用...");
    85.         addArticle(jedis, userId, article1);
    86.         addArticle(jedis, userId, article2);
    87.         addArticle(jedis, userId, article3);
    88.         // 分页获取用户文章列表:获取第一页,页面大小为 10
    89.         List<Map<String, String>> articles = getUserArticles(jedis, userId, 1, 10);
    90.         System.out.println("用户 " + userId + " 的文章列表:");
    91.         for (Map<String, String> articleData : articles) {
    92.             System.out.println("标题:" + articleData.get("title") + ", 时间:" + articleData.get("timestamp"));
    93.             System.out.println("内容:" + articleData.get("content"));
    94.             System.out.println("--------------------------");
    95.         }
    96.         // 关闭 Jedis 连接
    97.         jedis.close();
    98.     }
    99. }
    复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表