vlambda博客
学习文章列表

Redis系列文之初识Redis

Redis是目前互联网技术领域里面使用得最为广泛的存储中间件之一了,它的全称为“Remote Dictionary Service”(远程字典服务)的字母缩写。Redis用其超高的性能、完整的文档和丰富的客户端支持,在开源的中间件中广受好评。目前有许多大型公司都在使用,比如腾讯、阿里巴巴、京东、华为、Github等。所以学习和深入Redis对于中高级后端开发者的必要技能。

相信大家在面试之中,应该都会被问到“Redis可以用来做什么?”,那么许多人的第一反应一般都是热点数据缓存,确实热点数据缓存是Redis使用最多的领域。那如果被问到还有呢?大多数人应该会说分布式锁,毕竟在Redis中经常听到类似的问题,都会有分布式锁。

一、初识Redis
1.1 Redis可以用来做什么
Redis提供的功能非常的多,使用范围也很广,我们先简单的列举一下,Redis可以用在哪些地方。

  • 热点数据缓存,例如分布式回话信息Session。
  • 分布式锁。
  • 记录帖子的点赞、评论和点击数。
  • 计数器,去重计数。
  • 排序。
  • 布隆过滤器。
  • 简单MQ、简单限流。
  • 延时队列。
    Redis可以使用的地方当然还有许多,这里只是简单列举了一些用法。对于Redis的安装这里就不演示了。接下来我们先了解一下Redis的基础数据结构。

1.2 Redis基础数据结构
Redis有五种基础数据结构,分别是string(字符串)、list(列表)、hash(字典)、set(集合)和zset(有序集合)。

  • string(字符串)
    字符串是Redis最简单的数据结构,内部为一个字符数组,这一点跟Java中的字符串类似。Redis中所有的数据结构都是以唯一的key字符串作为名称,通过唯一的key定位对应的value值。Redis字符串是动态的字符串,是可以进行修改的,其内部的实现方式类似于Java的ArrayList。 「Redis字符串的长度,当其小于1m的时候,字符串的长度是加倍现有空间的,当长度大于1m的时候,每次扩容只会扩容1m。Redis字符串的最大长度是512m」。下面是字符串的基本操作:
// 单个设置、单个获取
set name Adaxuebiancheng
get name

// 批量设置、批量获取
mset name1 a1 name2 a2
mget name1 name2

Redis系列文之初识Redis

// 设置过期时间
set name test1
expire name 5 # 5秒后过期
setex name 5 test1 #5秒后过期,等价于 set + expire

Redis系列文之初识Redis


  • list(列表)
    Redis里面的list列表的实现,类似于Java中的LinkedList,其为链表,而非数组。特性也与之相差无几。list列表的插入和删除操作非常快,它们的时间复杂度都是O(1),但是查询很慢,时间复杂度为O(n),其为双向链表。当列表弹出最后一个值后,该list列表将被自动删除。list列表可以用来做异步队列使用。下面是他的基本操作:
// 先进先出-队列
rpush names zhangsan lisi wangwu #右边存放
llen names #列表长度
lpop names #左边弹出

Redis系列文之初识Redis


// 先进后出-栈
rpush names zhangsan lisi wangwu #右边存放
rpop names #右边弹出

Redis系列文之初识Redis


// 对于以下时间复杂度为O(n)的命令都应该慎用,
// Redis执行命令是单线程,命令执行时间太长会引发一系列问题
// 相当于java中list的get(int index)
lindex names 1

Redis系列文之初识Redis


// 获取区间元素
lrange names 0 -1

Redis系列文之初识Redis


// 截取数据
ltrim names 1 -1

Redis系列文之初识Redis


Redis的底层不是一个简单linkedlist,严格来说应该称之为“快速链表”(quicklist)的数据结构。最开始的时候Redis是使用的Ziplist,即压缩列表,使用一块连续的内存存储数据。当数据量较大时便会进化成quicklist。也就是将Ziplist使用双向指针再次变成一个链表。

  • hash(字典)
    在Redis中的hash字典类似于Java中的HashMap,它也是无序的,都是存储的键值对数据。且实现结构上与Java的HashMap一样,也是使用数组+链表的方式实现的。不同的是,Redis的value只允许存储字符串,且他们的reHash的方式不同。Redis采用的渐进式的方式起来重新计算hash值的。与list一样,最后一个元素弹出后,数据结构将被自动清除,内存被回收。但值得注意的是hash的存储消耗是要高于单个字符串的,所以怎么使用还需要再三权衡。下面是hash的基本操作:
// 存放
hset names redis huancun
// 获取所有
hgetall names

Redis系列文之初识Redis


// 获取某个key
hget names redis

Redis系列文之初识Redis


// 存放多个
hmset names redis huancun java kaifa

Redis系列文之初识Redis


  • set(集合)
    Redis中的集合呢,在Java中也有类似的实现-HashSet。它的键值对是无序的,也是唯一的。与HashSet类似,其内部是一个特殊的字典,值都为NULL。同样的,当最后一个数据被弹出,数据结构被自动删除,内存被回收。下面是set的一些简单操作:
// 添加
sadd names redis java
// 查看成员
smembers names

Redis系列文之初识Redis


// 查看某个value是否存在
sismember names java #相当于contains(o)

Redis系列文之初识Redis


// 获取集合长度
scard names
// 弹出一个
spop names

Redis系列文之初识Redis


  • zset(有序集合)
    Redis中的zset相当于Java中的SortedSet和HashMap的结合体,它在set的基础上给每一个value赋予了一个score,相当于权重,用于排序,它的内部实现是一种跳表结构(关于跳表我们后续再讨论)。跳表的实现思想有点类似于红黑树的思想,它的最下层数据是最完整的数据,然后往上依次是某个代表数据值,查找时由上而下的定位数据的具体位置。下面是zset的一些基本操作:
// 添加数据
zadd names 1.0 Redis
// 查看数据
zrange names 0 -1

Redis系列文之初识Redis


// 逆序输出
zrevrange names 0 -1

Redis系列文之初识Redis


// 长度
zcard names

Redis系列文之初识Redis


// 获取指定value的score
zscore names Redis

Redis系列文之初识Redis


// 根据区间遍历数据
zrangebyscore names 0 2.0


// 删除数据
zrem names Redis