找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4664

积分

0

好友

621

主题
发表于 3 天前 | 查看: 21| 回复: 0

1、安装Redis

Redis 6.0在2020年已经发布,但我们这里安装一个更经典的Redis 3.0版本。😂

1.1、在Linux上安装Redis

我们在CentOS上安装Redis。常见的有三种安装方式:

  • yum/apt软件管理软件安装
  • 源码的方式进行安装
  • 容器化安装

我们选择第二种源码安装方式:

  • 1)下载Redis指定版本的源码压缩包到当前目录
    wget http://download.redis.io/releases/redis-3.0.7.tar.gz
  • 2)解压缩Redis源码压缩包
    tar xzf redis-3.0.7.tar.gz
  • 3)建立一个redis目录的软连接,指向redis-3.0.7
    ln -s redis-3.0.7 redis
  • 4)进入redis目录
    cd redis
  • 5)编译(编译之前确保操作系统已经安装gcc)
    make
  • 6)安装
    make install

最后可以执行 redis-cli -v 查看Redis的版本。

1.2、启动Redis

有三种方法启动Redis:默认配置、运行配置、配置文件启动。我们用默认配置的方式启动:

redis-server

Redis 3.0.7 启动日志截图

一般在生产环境会使用配置文件启动的方式,以获得更好的控制和稳定性。

1.3、Redis命令行客户端

Redis服务启动后,使用 redis-cli 来连接并进行操作。

redis-cli -h 127.0.0.1 -p 6379

redis-cli连接成功截图

连接成功后,命令行提示符会变成 127.0.0.1:6379>,表示可以开始执行Redis命令了。掌握这些基础安装和连接操作,是深入学习 Redis 的第一步。

2、Redis基本数据结构

Redis 有 5 种基础数据结构,分别为:string (字符串)、list (列表)、set (集合)、hash (哈希) 和 zset (有序集合)。这五种结构是理解Redis所有高级功能的基石。

Redis五种基本数据结构示意图

2.1、字符串

字符串类型是Redis最基础的数据结构。首先,所有的键(key)都是字符串类型。其次,Redis 所有的数据结构都是以唯一的 key 字符串作为名称,然后通过这个唯一 key 值来获取相应的 value 数据。不同类型的数据结构的差异就在于 value 的结构不一样。

键值对映射关系示意图

除了上图描述简单的字符串,字符串类型的值也可以是复杂的字符串(例如JSON、XML)、数字 (整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过512MB。

字符串类型可存储复杂数据示例

2.1.1、命令

  • 设置值

    set key value [ex seconds] [px milliseconds] [nx|xx]

    下面操作设置键为Hello,值为World的键值对,返回结果为OK代表设置成功:

    127.0.0.1:6379> set Hello World
    OK

    set命令有几个选项:

    • ex seconds:为键设置秒级过期时间。
    • px milliseconds:为键设置毫秒级过期时间。
    • nx:键必须不存在,才可以设置成功,用于添加。
    • xx:与nx相反,键必须存在,才可以设置成功,用于更新。
  • 获取值

    get key

    获取键Hello的值:

    127.0.0.1:6379> get Hello
    "World"

    如果要获取的键不存在,则返回nil(空):

    127.0.0.1:6379> get some
    (nil)
  • 批量设置值

    mset key value [key value ...]

    可以批量对多个字符串进行读写,节省网络耗时开销。下面操作一次性设置4个键值对:

    127.0.0.1:6379> mset a 1 b 2 c 3 d 4
    OK
  • 批量获取值

    mget key [key ...]

    下面操作批量获取了键abcd的值:

    127.0.0.1:6379> mget a b c d
    1) "1"
    2) "2"
    3) "3"
    4) "4"
  • 计数

    incr key

    incr命令用于对值做自增操作,返回结果分为三种情况:

    1. 值不是整数,返回错误。
    2. 值是整数,返回自增后的结果。
    3. 键不存在,按照值为0自增,返回结果为1。
      127.0.0.1:6379>  set age 18
      OK
      127.0.0.1:6379> incr age
      (integer) 19

      除了incr命令,Redis提供了decr(自减)、incrby(自增指定数字)、 decrby(自减指定数字)、incrbyfloat(自增浮点数)。

2.1.2、应用场景

字符串可以说是Redis应用最广泛的数据结构,我们来看一下在实际开发中几个典型的应用场景。

2.1.2.1、缓存功能

下图是比较典型的缓存使用场景,其中Redis作为缓存层,MySQL作为存储层,绝大部分请求的数据都是从Redis中获取。由于Redis具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用。

Redis作为缓存层的架构示意图

2.1.2.2、计数

许多应用都会使用Redis作为计数的基础工具,它可以实现快速计数、查询缓存的功能,同时数据可以异步落地到其他数据源。例如记录文章的阅读次数、视频的播放量等。

2.1.2.3、共享Session

在分布式Web服务中,可以使用Redis来集中存储用户的Session信息,保证用户登录一次即可访问所有服务,实现Session共享。

2.1.2.4、分布式锁

利用setnx命令(SET if Not eXists)可以实现一个最简单的分布式锁。由于Redis的单线程命令处理机制,如果有多个客户端同时执行setnx key value,根据setnx的特性只有一个客户端能设置成功,所以setnx可以作为分布式锁的一种实现方案。

2.2、哈希

Redis的哈希(hash)和Java语言里面的HashMap类似。在Redis中,哈希类型是指键(key)对应的值(value)本身又是一个键值对结构,形如value={{field1,value1},...{fieldN,valueN}}

哈希结构示意图

2.2.1、命令

  • 设置值

    hset key field value

    下面为user:1添加一对field-value:

    127.0.0.1:6379> hset user:1 name tom
    (integer) 1

    如果设置成功会返回1,反之会返回0。此外Redis提供了hsetnx命令,它们的关系就像setsetnx命令一样,只不过作用域由键变为field。

  • 获取值

    hget key field

    获取user:1name域(属性)对应的值:

    127.0.0.1:6379> hget user:1 name
    “tom”
  • 删除field

    hdel key field [field ...]

    hdel会删除一个或多个field,返回结果为成功删除field的个数:

    127.0.0.1:6379> hdel user:1 name
    (integer) 1
    127.0.0.1:6379> hdel user:1 age
    (integer) 0
  • 批量设置或获取field-value

    hmget key field [field ...]
    hmset key field value [field value ...]

    hmsethmget分别是批量设置和获取field-value:

    127.0.0.1:6379> hmset user:1 name mike age 12 city tianjin
    OK
    127.0.0.1:6379> hmget user:1 name city
    1) “mike”
    2) “tianjin”

2.2.2、应用场景

2.2.2.1、存储对象

hash的field-value结构非常适合用来存储对象,field用来存储属性名称,value用来存储属性值。在一些客户端里也提供了json序列化器,使得操作对象更加方便。

2.3、列表

Redis的列表(list)类似于Java语言里面的LinkedList,同样地list的插入和删除操作非常快,时间复杂度为O(1),但是索引定位很慢,时间复杂度为O(n)。那么,list也可以充当栈和队列的角色。

例如,在list两端的插入和弹出,可以模拟栈的操作:

列表两端操作模拟栈

列表类型有两个特点:第一、列表中的元素是有序的,这就意味着可以通过索引下标获取某个元素或者某个范围内的元素列表。第二、列表中的元素可以是重复的。

2.3.1、命令

列表主要有5种操作类型:

操作类型 操作
添加 rpush lpush linsert
查找 lrange lindex llen
删除 lpop rpop lrem ltrim
修改 lset
阻塞操作 blpop brpop
  • 添加操作
    从右边插入元素:

    rpush key value [value ...]

    下面代码从右向左插入元素cba

    127.0.0.1:6379> rpush listkey c b a
    (integer) 3

    lrange 0 -1命令可以从左到右获取列表的所有元素:

    127.0.0.1:6379> lrange listkey 0 -1
    1) “c”
    2) “b”
    3) “a”

    从左边插入元素使用lpush,原理类似。

  • 向某个元素前或者后插入元素

    linsert key before|after pivot value

    linsert命令会从列表中找到等于pivot的元素,在其前(before)或者后(after)插入一个新的元素value。例如下面操作会在列表的元素b前插入java

    127.0.0.1:6379> linsert listkey before b java
    (integer) 4

    返回结果为4,代表当前列表的长度,当前列表变为:

    127.0.0.1:6379> lrange listkey 0 -1
    1) “c”
    2) “java”
    3) “b”
    4) “a”
  • 查找

    • 获取指定范围内的元素列表:
      lrange key start end

      例如想获取列表的第2到第4个元素:

      127.0.0.1:6379> lrange listkey 1 3
      1) “java”
      2) “b”
      3) “a”
    • 获取列表指定索引下标的元素:
      lindex key index

      例如当前列表最后一个元素为a

      127.0.0.1:6379> lindex listkey -1
      “a”
    • 获取列表长度:
      llen key

      例如,下面示例当前列表长度为4:

      127.0.0.1:6379> llen listkey
      (integer) 4
  • 删除

    • 从列表左侧弹出元素:lpop key
    • 从列表右侧弹出:rpop key
    • 删除指定元素:lrem key count value
  • 修改

    lset key index newValue
  • 阻塞操作
    阻塞式弹出如下:

    blpop key [key ...] timeout
    brpop key [key ...] timeout

    blpopbrpoplpoprpop的阻塞版本,它们除了弹出方向不同,使用方法基本相同。

2.3.2、应用场景

2.3.2.1、消息队列

Redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端使用lpush从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。

Redis消息队列模型示意图

列表可以灵活组合,在不同的场景使用:

  • lpush + lpop = Stack(栈)
  • lpush + rpop = Queue(队列)
  • lpush + ltrim = Capped Collection(有限集合)
  • lpush + brpop = Message Queue(消息队列)

2.4、集合

集合(set)类似Java语言中的HashSet,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素。

集合类型结构图

2.4.1、命令

2.4.1.1、集合内操作
  • 添加元素
    sadd key element [element ...]

    无法添加重复元素,添加重复元素会返回0

  • 删除元素
    srem key element [element ...]
  • 计算元素个数
    scard key
  • 从集合随机弹出元素
    spop key
2.4.1.2、集合间操作
  • 求多个集合的交集
    sinter key [key ...]
  • 求多个集合的并集
    suinon key [key ...]
  • 求多个集合的差集
    sdiff key [key ...]

集合交并差运算示例图

2.4.2、应用场景

2.4.2.1、标签

集合类型比较典型的使用场景是标签(tag)。例如一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同喜好的标签,这些数据对于用户体验以及增强用户黏度比较重要。

2.4.2.2、共同关注

可以利用交集的运算,实现社交社区用户的“共同关注”功能。理解了这些集合操作,对于解决实际场景中的分类、关联性问题大有裨益,你可以在 云栈社区 的算法板块找到更多关于集合运算的巧妙应用。

2.5、有序集合

有序集合(zset)可能是Redis提供的最为特色的数据结构。它类似于Java的SortedSet和HashMap的结合体,一方面它是一个set,保证了内部value的唯一性,另一方面它可以给每个value赋予一个score,代表这个value的排序权重。

有序集合结构示意图

有序集合提供了获取指定score和元素范围查询、计算成员排名等功能,合理的利用有序集合,能在实际开发中解决很多问题。

有序集合中的元素不能重复,但是score可以重复,就和一个班里的同学学号不能重复,但是考试成绩可以相同。

2.5.1、命令

2.5.1.1、集合内
  • 添加成员
    zadd key score member [score member ...]

    下面操作向有序集合user:rank添加用户李四和他的score250

    127.0.0.1:6379> zadd user:ranking 250 李四
    (integer) 1
  • 计算成员个数
    zcard key
  • 计算某个成员的score
    zscore key member
  • 计算成员的排名
    zrank key member
    zrevrank key member
  • 删除成员
    zrem key member [member ...]
2.5.1.2、集合间的操作
  • 交集
    zinterstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]
  • 并集
    zunionstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]

2.5.2、应用场景

有序集合比较适合用于需要排行的地方。

2.5.2.1、用户点赞统计

可以用于统计博客、视频网站等作品的点赞数,可以根据点赞数对作品进行排行。

3、基本数据类型内部编码

通过上面的介绍,我们已经了解了五种基本数据结构。既然是数据结构,就一定有内部的组成,就比如Java中的String由char或者byte数组组成。我们这里简单了解一下Redis五种基本数据结构的内部编码,这对于理解性能和内存优化至关重要。

Redis数据结构和内部编码对应关系图

3.1、字符串

字符串类型的内部编码有3种:

  • int:8个字节的长整型。
  • embstr:小于等于39个字节的字符串。
  • raw:大于39个字节的字符串。

3.2、哈希

哈希类型的内部编码有两种:

  • ziplist(压缩列表):当哈希类型元素个数小于hash-max-ziplist-entries配置(默认512个)、同时所有值都小于hash-max-ziplist-value配置(默认64字节)时,Redis会使用ziplist作为哈希的内部实现。ziplist使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。
  • hashtable(哈希表):当哈希类型无法满足ziplist的条件时,Redis会使用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,而hashtable的读写时间复杂度为O(1)。

3.3、列表

列表类型的内部编码有两种。

  • ziplist(压缩列表):当列表的元素个数小于list-max-ziplist-entries配置(默认512个),同时列表中每个元素的值都小于list-max-ziplist-value配置时(默认64字节),Redis会选用ziplist来作为列表的内部实现来减少内存的使用。
  • linkedlist(链表):当列表类型无法满足ziplist的条件时,Redis会使用linkedlist作为列表的内部实现。

3.4、集合

集合类型的内部编码有两种:

  • intset(整数集合):当集合中的元素都是整数且元素个数小于set-max-intset-entries配置(默认512个)时,Redis会选用intset来作为集合的内部实现,从而减少内存的使用。
  • hashtable(哈希表):当集合类型无法满足intset的条件时,Redis会使用hashtable作为集合的内部实现。

3.5、有序集合

有序集合类型的内部编码有两种:

  • ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplist-entries配置(默认128个),同时每个元素的值都小于zset-max-ziplist-value配置(默认64字节)时,Redis会用ziplist来作为有序集合的内部实现,ziplist可以有效减少内存的使用。
  • skiplist(跳跃表):当ziplist条件不满足时,有序集合会使用skiplist作为内部实现,因为此时ziplist的读写效率会下降。

这里只是简单地了解一下Redis数据结构的内部编码。理解这些底层实现,有助于我们在开发中做出更优的数据结构选择和数据模型设计。未来如果有机会,可以通过阅读源码来更深入地了解Redis基本数据结构的内部原理。


参考:
【1】:《Redis开发与运维》
【2】:掘金小册 《Redis 深度历险:核心原理与应用实践》




上一篇:RPC与RESTful架构选型指南:从协议到架构深度对比
下一篇:Redis高性能揭秘:从内存模型到I/O多路复用的深度解析
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-7 19:21 , Processed in 0.783376 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表