【后端之旅】分布式中间件 Redis 篇

215 阅读19分钟

Redis 全称为 Remote Dictionary Server,是一个开源的基于内存的数据存储系统,主要应用于数据库缓存、消息队列等场景。

为何要使用 Redis

  • 性能极高
  • 数据类型丰富,单键值对最大支持 512MB 大小的数据
  • 简单易用,支持所有主流编程语言
  • 支持数据持久化、主从复制、哨兵模式等高可用特性

如何安装 Redis

Redis 数据类型

  • 基本数据类型

    • String 字符串
      • Redis 的默认格式,而且是二进制安全的
      • 命令窗口默认不支持显示中文,可用 redis-cli --raw 命令重新进入命令行即可修复
    • List 列表
      • 用于存储和操作一组有顺序的数据,类似于数组或链表
    • Set 集合
      • Set 中的元素是无序的
      • List 中的元素是可重复的,Set 中的元素是不可重复的
    • SortedSet 有序集合
      • SortedSet 中的每个元素都会关联一个浮点型的分数,然后按照分数从小到大进行排序
      • SortedSet 中的元素是唯一的,但其关联的分数是可重复的
    • Hash 哈希
      • Hash 即键值对作为元素的集合,其中键是不可重复的
  • 高级数据类型

    • Stream 消息队列
      • Redis 5.0 版本引入的一个新的数据结构
      • 是一个轻量级的消息队列,可解决 Subscribe/Publish 协议的消息无法持久化、无法记录历史消息等问题
    • Geospatial 地理空间
      • Redis 3.2 版本引入的新特性
      • 提供了一种存储地理位置信息的数据结构
      • 支持对地理位置进行各种计算操作
    • HyperLogLog
      • 用于做基数(集合中元素去重后的个数)统计的算法
      • 适用于统计网站访问UV、某个词的搜索次数等不要求绝对精确度的统计
    • Bitmap 位图
      • Bitmap 是 String 的扩展
      • 支持位运算
    • Bitfield 位域
      • Redis 3.2 版本引入的新特性
      • 用于将较多小的整数存储到较大的位图中,使得内存的使用更加高效

Redis 操作命令

对于所有命令中出现的 stop 而言,-1 表示最后一个元素

  • 基本

    # 启动 Redis 服务
    redis-server
    
    # 本地启动客户端
    redis-cli
    
    # 远程连接 Redis
    telnet 127.0.0.1 6379
    
    # 发起 ping 请求,服务正常会响应 pong
    ping
    
    # 查找所有符合给定模式的 key
    KEYS pattern
    
    # 返回 key 所储存的值的类型
    TYPE key
    
    # 从当前 Redis 中随机返回一个 key
    RANDOMKEY
    
    # 仅当 newkey 不存在时,将 key 改名为 newkey
    RENAMENX key newkey
    
    # 修改 key 的名称
    RENAME key newkey
    
    # 序列化给定 key ,并返回被序列化的值
    DUMP key
    
    # 检查给定 key 是否存在
    EXISTS key
    
    # 退出
    quit
    
  • 字符串

    # 设置键 key 的值为 value
    SET key value
    
    # 获取键 key 的值,返回的就是 value
    GET key
    
    # 删除一个或多个给定键的值
    DEL key [key1 ...]
    
    # 获取键 key 的值(作为字符串)的长度
    STRLEN key
    
    # 设置键 key 的值为 value,同时设定该 key 的超时时间为 seconds 秒
    SETEX key seconds value
    
    # 设置键 key 的值为 value,同时设定该 key 的超时时间为 milliseconds 毫秒
    PSETEX key milliseconds value
    
    # 只有当键 key 不存在的情况下,将 key 的值设置为 value
    # 成功返回 1,失败返回 0
    SETNX key value
    
    # 设置键 key 的值为 value,并返回设置前的旧值。若没有旧值则返回 nil
    GETSET key value
    
    # 如果键 key 存在并且值是⼀个字符串,则把 value 追加到现有值的末尾
    # 如果 key 不存在,则将 key 的值设置为 value
    # 返回追加 value 之后该 value 的⻓度
    APPEND key value
    
    # 从偏移量 offset 开始⽤ value 字符串覆盖键 key 存储的原字符串
    # offset 从 0 开始
    # 返回修改后新的 value 字符串的⻓度
    SETRANGE key offset value
    
    # 返回键 key 存储的字符串的从 start 到 end 之间(包括 start 和 end)的部分
    GETRANGE key start value
    
    # 将键 key 存储的数字值 value 加⼀
    # 若 key 不存在则值先初始化为 0 再加⼀
    # 若 key 存储的值不能被解释为数字,则返回错误
    INCR key
    
    # 将键 key 存储的数字值 value 减⼀
    # 若 key 不存在则值先初始化为 0 再减⼀
    # 若 key 存储的值不能被解释为数字,则返回错误
    DECR key
    
    # 将键 key 存储的数字值 value 加上⼀个 increment 的量
    # 若 key 不存在则值先初始化为 0 再加
    # 若 key 存储的值不能被解释为数字,则返回错误
    INCRBY key increment
    
    # 将键 key 存储的数字值 value 减去⼀个 decrement 的量
    # 若 key 不存在则值先初始化为 0 再减
    # 若 key 存储的值不能被解释为数字,则返回错误
    DECRBY key decrement
    
    # 将键 key 存储的浮点数值 value 加上⼀个 increment 的增量
    # 若 key 不存在则值先初始化为 0 再执⾏加上增量的操作
    # 若 key 存储的值或 increment 不能被解释为浮点数值,则返回错误
    INCRBYFLOAT key increment
    
    # 同时为多个键设置值
    MSET key value [key value ...]
    
    # 返回给定的⼀个或多个键的值
    MGET key [key ...]
    
    # 当所有给定的 key 都不存在时才同时为多个键设置值
    # 只要有⼀个 key 已经存在,那么所有值都不会被继续设置
    MSETNX key value [key value ...]
    
  • 列表

    # 将⼀个或多个元素添加到列表 key 的表头(左侧),多个值则从左⾄右依次插⼊表头
    # 如果列表 key 不存在,则创建⼀个然后执⾏ LPUSH 插⼊操作
    # 如果列表 key 存在但不是列表类型,则返回错误
    LPUSH key element [element ...]
    
    # 当且仅当 key 存在并且是⼀个列表的时候,才执⾏ LPUSH 操作
    LPUSHX key element [element ...]
    
    # 将⼀个或多个元素添加到列表 key 的表尾(右侧),多个值则从左⾄右依次插⼊表尾
    # 如果列表 key 不存在,则创建⼀个然后执⾏ RPUSH 插⼊操作
    # 如果列表 key 存在但不是列表类型,则返回错误
    RPUSH key element [element ...]
    
    # 当且仅当 key 存在并且是⼀个列表的时候,才执⾏ RPUSH 操作
    RPUSHX key element [element ...]
    
    # 将⼀个或 count (Redis 6.2 版本开始支持 count 参数)个元素从列表头⽅向移除并将其返回
    # 如果列表 key 不存在,则返回 nil
    LPOP key [count]
    
    # 将⼀个或 count (Redis 6.2 版本开始支持 count 参数)个元素从列表尾⽅向移除并将其返回
    # 如果列表 key 不存在,则返回 nil
    RPOP key [count]
    
    # 在⼀个原⼦时间内,将 source 列表的尾部元素弹出,并插⼊到 destination 列表的头部,最后返回该元素
    # 如果列表 source 或 destination 不存在,则返回 nil
    RPOPLPUSH source destination
    
    # 移除列表 key 中与 element 相等的 count 个元素,返回被移除的元素的数量
    LREM key count element
    
    # 返回列表 key 的⻓度
    # 如果 key 不存在则返回 0
    # 如果 key 不是列表类型则返回错误
    LLEN key
    
    # 返回列表 key 中索引为 index 的元素(值)
    LINDEX key index
    
    # 将元素 element 插⼊到列表 key 中,位于 pivot 之前(BEFORE)或者之后(AFTER)
    LINSERT key BEFORE|AFTER pivot element
    
    # 将列表 key 中索引为 index 的元素设置为 element
    LSET key index element
    
    # 返回列表 key 中,位于 start 和 stop 之间的元素(包括 start 和 stop)
    LRANGE key start stop
    
    # 只保留列表 key 中索引为 start 和 stop 之间的元素(包括 start 和 stop)
    LTRIM key start stop
    
    # 列表阻塞式(Blocking)弹出,是 LPOP 的阻塞版本
    # 当列表中没有任何元素时阻塞,直到超时(超过 timeout 秒)或发现新的可弹出元素为⽌
    BLPOP key [key ...] timeout
    
    # 列表阻塞式(Blocking)弹出,是 RPOP 的阻塞版本
    # 当列表中没有任何元素时阻塞,直到超时(超过 timeout 秒)或发现新的可弹出元素为⽌
    BRPOP key [key ...] timeout
    
    # 是 RPOPLPUSH 的阻塞版本
    # 当列表 source 中没有任何元素时阻塞,直到超时(超过 timeout 秒)或发现新的可弹出元素为⽌
    BRPOPLPUSH source destination timeout
    
  • 集合

    # 将⼀个或多个元素加⼊到集合 key 中
    # 已存在于集合中的元素将被忽略
    SADD key member [member ...]
    
    # 将⼀个或多个元素从集合 key 中移除
    # 不存在的 member 元素将被忽略
    SREM key member [member ...]
    
    # 返回集合 key 中的所有成员
    # key 不存在时返回空,key 的数据类型不为集合则返回错误信息
    SMEMBERS key
    
    # 判断 MEMBER 是否是集合 key 的成员,是返回 1,不是或 key 不存在返回 0
    SISMEMBER key member
    
    # 移除并返回集合 key 中的⼀个或 count (Redis 3.2 及以上版本可用)个随机元素
    SPOP key [count]
    
    # 和 SPOP 类似,区别在于 SRANDMEMBER 只返回不移除
    SRANDMEMBER key [count]
    
    # 将 member 元素从 source 集合移动到 destination 集合(原⼦性操作)
    SMOVE source destination member
    
    # 返回集合 key 的基数(集合中元素的数量)
    SCARD key
    
    # 增量迭代,是⼀个基于游标的迭代器
    # 类似的命令还有 HSCAN、SSCAN、ZSCAN
    SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
    
    # 返回⼀个集合的全部成员,多个集合则返回交集
    SINTER key [key ...]
    
    # 类似 SINTER,区别是 SINTERSTORE 会保存结果集到 destination 集合中,⽽不是单纯返回
    # 若 destination 存在则将其覆盖,destination 可以是 key 本身
    SINTERSTORE destination key [key ...]
    
    # 返回⼀个集合的全部成员,多个集合则返回并集
    SUNION key [key ...]
    
    # 类似 SUNION,区别是 SUNIONSTORE 会保存结果集到 destination 集合中,⽽不是单纯返回
    # 若 destination 存在则将其覆盖,destination 可以是 key 本身
    SUNIONSTORE destination key [key ...]
    
    # 返回⼀个集合的全部成员,多个集合则返回差集
    SDIFF key [key ...]
    
    # 类似 SDIFF,区别是 SDIFFSTORE 会保存结果集到 destination 集合中,⽽不是单纯返回
    # 若 destination 存在则将其覆盖,destination 可以是 key 本身
    SDIFFSTORE destination key [key ...]
    
  • 有序集合

    # 将⼀个或多个 member 元素及其分数 score 加⼊到有序集合 key 中
    # NX 是仅添加新成员的选项(Redis 3.0.2 版本开始支持)
    # XX 是仅更新已存在成员的选项(Redis 3.0.2 版本开始支持)
    # CH 修改返回值为变更成员的数量(Redis 3.0.2 版本开始支持)
    # INCR 用于递增分数,使用该选项会返回更新后的分数值(Redis 3.0.2 版本开始支持)
    # GT 表示仅更新已经存在的成员的分值,并且新的分值小于之前的分值(Redis 6.2 版本开始支持)
    # LT 表示仅更新已经存在的成员的分值,并且新的分值大于之前的分值(Redis 6.2 版本开始支持)
    ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ..]
    
    # 将⼀个或多个成员从集合 key 中移除
    # 不存在的 member 成员将被忽略
    ZREM key member [member ..]
    
    # 返回有序集合 key 中的成员 member 的分数值(score)
    ZSCORE key member
    
    # 为有序集合 key 的成员 member 的分数值 score 加上⼀个增量 increment
    ZINCRBY key increment member
    
    # 返回有序集合 key 的基数(集合中成员的数量)
    ZCARD key
    
    # 返回有序集合 key 中,分数值 score 在 min 和 max 之间(包括等于)的成员的数量
    ZCOUNT key min max
    
    # 返回有序集合 key 中指定区间内的成员(从⼩到⼤排列)
    # BYSCORE 按照分数查询
    # BYLEX 相同分数按字典序返回
    # REV 使用该参数后,分数降序,相同分数的 member 按字典降序
    # LIMIT offset count 分页查询,仅支持 BYSCORE 或 BYLEX 查询
    # WITHSCORES 参数用于同时返回成员及其分数,没有该参数则只返回成员。但该参数不支持 BYLEX 查询
    ZRANGE key start stop [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
    
    # 返回有序集合 key 中指定区间内的成员(从⼤到⼩排列)
    ZREVRANGE key start stop [WITHSCORES]
    
    # 返回有序集合 key 中所有 score 值在指定区间内的成员(从⼩到⼤排列)
    ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
    
    # 返回有序集合 key 中所有 score 值在指定区间内的成员(从⼤到⼩排列)
    ZREVRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
    
    # 返回有序集合 key 中成员 member 的排名(按照 score 从⼩到⼤排列)
    ZRANK key member
    
    # 返回有序集合 key 中成员 member 的排名(按照 score 从大到小排列)
    ZREVRANK key member
    
    # 移除有序集合 key 中指定排名区间内的所有 member(按照 score 从⼩到⼤排列)
    ZREMRANGEBYRANK key start stop
    
    # 移除有序集合 key 中指定分数区间内的所有 member(按照 score 从⼩到⼤排列)
    ZREMRANGEBYSCORE key min max
    
    # 移除有序集合 key 中指定字典序区间内的所有 member(按照字典序从⼩到⼤排列)
    ZREMRANGEBYLEX key min max
    
    # 返回有序集合 key 中所有字典序在指定区间内的成员(从⼤到⼩排列)
    ZRANGEBYLEX key min max [LIMIT offset count]
    
    # 返回有序集合 key 中指定字典序区间内的所有 member 的数量
    ZLEXCOUNT key min max
    
    # 增量迭代,是⼀个基于游标的迭代器
    # 类似的命令还有 HSCAN、SSCAN、SCAN
    ZSCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
    
    # 返回⼀个或多个有序集合的并集,并存储到 destination 中
    ZUNIONSTORE destination numkeys key [key ...]
    
    # 返回⼀个或多个有序集合的交集,并存储到 destination 中
    ZINTERSTORE destination numkeys key [key ...]
    
  • 哈希

    # 将哈希表 key 中的域 field 的值设置为 value
    HSET key field value [field value ...]
    
    # 当且仅当 field 不存在的时候,将哈希表 key 中的域 field 的值设置为 value
    HSETNX key field value
    
    # 返回哈希表 key 中给定域 field 的值
    HGET key field
    
    # 判断给定域 field 是否存在于哈希表 key 中
    HEXISTS key field
    
    # 删除哈希表 key 中的⼀个或多个指定域 field
    HDEL key field [field ...]
    
    # 返回哈希表 key 中域的数量
    HLEN key
    
    # 返回哈希表 key 中,给定域 field 相关联的值的字符串⻓度
    HSTRLEN key field
    
    # 将哈希表 key 中 field 的值加上增量 increment
    HINCRBY key field increment
    
    # 将哈希表 key 中 field 的值加上浮点数增量 increment
    HINCRBYFLOAT key field increment
    
    # 设置多个 key-value 对(功能同HSET相同,已过时)
    HMSET key field value [field value ...]
    
    # 返回哈希表 key 中⼀个或多个给定域 field 的值
    HMGET key field [field ...]
    
    # 返回哈希表 key 中的所有域
    HKEYS key
    
    # 返回哈希表 key 中所有域的值
    HVALS key
    
    # 返回哈希表 key 中所有的域和值
    HGETALL key
    
    # 增量迭代,是⼀个基于游标的迭代器
    # 类似的命令还有 SCAN、SSCAN、ZSCAN
    HSCAN key cursor [MATCH pattern] [COUNT count]
    
  • # Redis 5.0 版本新增加的数据结构
    # 待整理
    
  • 地理空间

    # Redis 3.2 版本新增加的数据结构
    # 待整理
    
  • HyperLogLog

    # 添加⼀个或者多个元素到 HyperLogLog 中。若 key 不存在则创建⼀个
    PFADD key element [element ...]
    
    # 返回⼀个 key 的近似的基数估算值
    PFCOUNT key [key ...]
    
    # 将⼀个或多个 sourcekey 合并⾄ destkey
    PFMERGE destkey sourcekey [sourcekey ...]
    
    # 来调试 HyperLogLog 值的⼀个内部命令
    PFDEBUG subcommand key
    
  • 位图

    # 设置或者清除偏移量为 offset 的位
    SETBIT key offset value
    
    # 读取偏移量为 offset 的位的值
    GETBIT key offset
    
    # 对⼀个或者多个 key 进⾏位逻辑运算,并将结果存储在 destkey 中
    # operation 可以为 AND | OR | XOR | NOT
    BITOP operation destkey key [key ...]
    
    # 返回第⼀个 bit 位(0 或 1)的位置
    BITPOS key bit [start [end [BYTE|BIT]]]
    
    # 返回从 start 到 end 为⽌的所有设置位(bit 为 1 的位)的数量
    BITCOUNT key [start [end [BYTE|BIT]]]
    
  • 位域

    # Redis 3.2 版本新增加的数据结构
    
    # 将⼀个 String 字符串类型当做⼀个 bit 数组,执⾏任意位域整数运算
    BITFIELD key [GET encoding offset|[OVERFLOW WRAP|SAT|FAIL] [GET encoding offset|[OVERFLOW WRAP|SAT|FAIL] ...]]
    
    # 将⼀个 String 字符串类型当做⼀个 bit 数组,执⾏任意位域整数运算(只读)
    BITFIELD_RO key [GET encoding offset [GET encoding offset ...]]
    
  • 事务

    • Redis 事务不保证原子性
    • 开始事务命令执行后,往后的命令就会被放入到一个队列中,直至遇到触发事务命令或取消事务命令
    • 触发事务命令执行后,队列中的命令会全部执行,不会因为某些命令执行失败而导致其他命令不执行
    • 在事务执行的过程中,其他客户端提交的命令请求,不会被插入到事务的执行命令序列中
    # 开始事务,往后的命令就会被放入到一个队列中,直至遇到触发事务命令或取消事务命令
    MULTI
    
    # ...
    
    # 触发事务
    EXEC
    
    # 取消事务
    DISCARD
    

Redis 持久化

  • RDB(Redis Database)
    • 适用于备份
    • 在指定的时间内,将内存中的数据快照写入磁盘(是某个时间点上数据的完整副本)
    • 可通过 redis.conf 配置文件中的 save 参数来配置
      # 基本格式: save <seconds> <changes> [<seconds> <changes> ...]
      # 每 3600 秒,只要中间出现过一次修改,就在 3600 秒结束时进行一次快照
      save 3600 1
      
    • 可通过命令 save 手动触发快照
    • 快照的缺点是如果服务器在最后一次快照之后的某个时间点宕机,则最后一次快照以后的内容,都会丢失
  • AOF(Append Only File)
    • 执行写命令时,不仅会将命令写入内存,还会将命令写入到一个追加文件中
    • 以日志的形式来记录每一个写操作
    • 重启 Redis 时,就会通过重新执行 AOF 文件中的命令,来在内存中重建整个数据库的内容
    • 开启的方式是在 redis.conf 配置文件中写入以下配置
      appendonly yes
      

Redis 主从复制

  • 一个主节点(master)可以有多个从节点(slave),一个从节点只能有一个主节点
  • 复制操作是单向的,只能由主节点到从节点
  • 主节点不需要修改任何配置,只需修改从节点的配置即可
    • 方式一:通过命令修改
      # 查看当前节点角色
      role
      
      # 配置所属主节点(较新版)
      replicaof host port
      
      # 配置所属主节点(旧版)
      slaveof host port
      
    • 方式二:通过配置文件修改(这里是在一台机器上同时启动主从 Redis 的例子)
      # 把端口号改为从节点的端口号
      port 6380
      
      # 相应的 PIDFILE 也需要修改
      pidfile /var/run/redis_6380.pid
      
      # 相应的 DBFILENAME 也加上端口号
      dbfilename dump-6380.rdb
      
      # 找到对应的 slaveof <masterip> <masterport> 或 replicaof <masterip> <masterport> 以指定主库
      slaveof 172.0.0.1 6379
      
  • 启动从库 redis
    redis-server redis-6380.conf
    

Redis 哨兵模式

* 注意
    - 哨兵本身也是一个进程
    - 在生产环境中一般会使用 3 个哨兵节点(它们会自动选举一个领导者来实施监控)来保证高可用
* 用途
    - 持续监控 Redis 服务是否处于正常状态
    - 某个节点出现问题时通知其他节点
    - 自动故障转移,即在主节点不能工作时将一个从节点升级为新的主节点
* 启动
    - 需添加配置文件 sentinel.conf
        ```conf
        # 指定需要监听的主节点,最后的 1 表示只需要获得一个从节点的同意便可实现故障转移
        sentinel monitor master 127.0.0.1 6379 1
        ```
    - 命令方式
        ```sh
        # 将当前节点启动为哨兵节点
        redis -sentinel
        
        # 启动哨兵节点
        redis-sentinel sentinel.conf
        ```

Redis 数据删除策略

主要操作就是对 key 设置过期时间,在计时到达后删除已过期的 key

# 设置 key 在 seconds 秒后过期
EXPIRE key seconds

# 设置 key 在 milliseconds 毫秒后过期
PEXPIRE key milliseconds

# 设置 key 在到达秒级时间戳 n (如 1758654203)之后过期
EXPIREAT key n

# 设置 key 在到达毫秒级时间戳 n (如 1758654203000)之后过期
PEXPIREAT key n

# 移除 key 的过期时间
PERSIST key

前面学习过的操作命令 SETEX 也有该功能

# 设置键 key 的值为 value,同时设定该 key 的超时时间为 seconds 秒
SETEX key seconds value

查看某个 key 的剩余存活时间可以使用 TTL

# 显示 key 的剩余存活时间,单位为秒
# 返回结果为 -1 表示 key 永不过期
# 返回结果为 -2 表示 key 已过期
TTL key

Redis 数据淘汰策略

当 Redis 的运行内存超过设置的最大内存后,会使用数据淘汰策略来删除符合条件的 key,以保证 Redis 继续正常运行。可在 redis.conf 配置文件中设置最大允许内存

# 在 64 位操作系统中,maxmemory 的默认值是 0,表示没有内存大小限制。即 Redis 不会检查可用内存,直到崩溃
# 在 32 位操作系统中,maxmemory 的默认值是 3G
maxmemory <bytes>

# 设置内存淘汰策略
maxmemory-policy <policy-names>

使用命令

# 查看当前 Redis 的内存淘汰策略
config get maxmemory-policy

# 设置当前 Redis 的内存淘汰策略。通过命令设置的策略会在 Redis 重启后失效
config set maxmemory-policy <policy-names>

内存淘汰策略 policy-names 包括:

  • noeviction - Redis 3.0 之后的默认值。不进行数据淘汰
  • volatile-random - 随机淘汰设置了过期时间的任意键值
  • volatile-ttl - 优先淘汰更早过期的键值
  • volatile-lru - Redis3.0 之前的默认值。淘汰所有设置了过期时间的键值中,最久未使用的键值
  • volatile-lfu - Redis 4.0 后新增。淘汰所有设置了过期时间的键值中,最少使用的键值
  • allkeys-random - 随机淘汰任意键值
  • allkeys-lru - 淘汰整个键值中最久未使用的键值
  • allkeys-lfu - Redis 4.0 后新增。淘汰整个键值中最少使用的键值

Jedis

Redis 的使用方式包括 CLI(Command Line Interface)、API(Application Programming Interface)、GUI(Graphical User Interface)。现在我们使用 jedis-2.9.0.jar 包来实现 Java 代码操作 Redis。

首先,创建一个 RedisUtil 工具类是提供 Redis 连接池。

import redis.clients.jedis.Jedis;  
import redis.clients.jedis.JedisPool;  
import redis.clients.jedis.JedisPoolConfig;  
  
public class RedisUtil {  
    //服务器 IP 地址
    private static String HOST = "0.0.0.0";
    //端口
    private static int PORT = 6379;
    //连接实例的最大连接数
    private static int MAX_ACTIVE = 1024;
    //控制一个 pool 最多有多少个状态为 idle(空闲的) 的 jedis 实例,默认值也是 8
    private static int MAX_IDLE = 200;
    //等待可用连接的最大时间,单位毫秒,默认值为 -1,表示永不超时。如果超过等待时间,则直接抛出 JedisConnectionException
    private static int MAX_WAIT = 10000;
    //连接超时的时间
    private static int TIMEOUT = 10000;
    // 在 borrow 一个 jedis 实例时,是否提前进行 validate 操作;如果为 true,则得到的 jedis 实例均是可用的
    private static boolean TEST_ON_BORROW = true;
    // Jedis Pool 实例
    private static JedisPool jedisPool = null;
  
    /**  
     * 初始化Redis连接池  
     */  
    static {  
        try {
            JedisPoolConfig jpc = new JedisPoolConfig();
            jpc.setMaxTotal(MAX_ACTIVE);
            jpc.setMaxIdle(MAX_IDLE);
            jpc.setMaxWaitMillis(MAX_WAIT);
            jpc.setTestOnBorrow(TEST_ON_BORROW);
            jedisPool = new JedisPool(jpc, HOST, PORT, TIMEOUT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**  
     * 获取Jedis实例  
     */  
    public synchronized static Jedis getJedis() {
        try {
            if (jedisPool != null) {
                Jedis resource = jedisPool.getResource();
                System.out.println("redis 正在运行: " + resource.ping());
                return resource;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**  
     * 释放资源  
     */  
    public static void closeJedis(final Jedis jedis) {  
        if(jedis != null) {
            jedis.close();
        }
    }
}

然后使用该 RedisUtil 来获取 Jedis 实例即可。结束后记得调用关闭方法。

import RedisUtil;
import redis.clients.jedis.Jedis;
import java.util.List;

public class Application {  
    public static void main(String[] args) {  
        Jedis jedis = null;
        try {
            jedis = RedisUtil.getJedis();

            jedis.del("arr");
            jedis.lpush("arr", "1");
            jedis.lpush("arr", "3");
            jedis.lpush("arr", "5");
            jedis.lpush("arr", "7");
            jedis.lpush("arr", "9");

            List<String> arr = jedis.lrange("arr", 0, -1);

            System.out.println(arr);
        } finally {
            if (jedis != null) {
                RedisUtil.closeJedis(jedis);
            }
        }
    }  
}