分布式缓存中间件Redis入门

617 阅读18分钟

| 作者:江夏

| 知乎:www.zhihu.com/people/1024…

| GitHub:github.com/JiangXia-10…

| CSDN:blog.csdn.net/qq\_4115394…

| 掘金:juejin.cn/user/651387…

| 公众号:1024笔记

本文大概9281字,建议阅读23分钟

1、什么是Redis?

Redis即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、“Key-Value”数据库,并提供多种语言的API;redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。

Redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。

和Memcached类似,Redis支持存储的value类型相对更多,包括sSring(字符串)、List(链表)、Set(集合)、Zset(sorted set --有序集合)和hHash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。

与Memcached区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。

Redis官网:redis.io,

Redis相关中文网站:www.redis.cn

Redis的spring 文档: docs.spring.io/spring-data…

2. 为什么要使用Redis

无论是Redis,还是MySQL、HBase等等,它们都是用来存储数据的地方。但是因为它们各自的设计理念不同,所以它们适用于不同的应用场景。

因为Redis是一种NoSql,所以它也具有Nosql数据库的优势,比如:

1)易扩展

这些类型的数据存储不需要固定的模式,无需多余的操作就可以进行横向的扩展。相对于关系型数据库可以减少表和字段特别多的情况。也无型之间在架构的层面上带来了可扩展的能力

2)大数据量提高性能

3)多样灵活的数据模型。

在面试的时候,常被问比较下Redis与Memcache的优缺点,个人觉得这二者并不适合一起比较,redis:是非关系型数据库不仅可以做缓存还能干其它事情,Memcache:是仅用做缓存。常常让我们对这二者进行比较,主要也是由于Redis最广泛的应用场景就是Cache。

Redis的应用场景:

1、缓存,毫无疑问这是Redis当今最为人熟知的使用场景。再提升服务器性能方面非常有效;

2、排行榜,在使用传统的关系型数据库(mysql oracle 等)来做这个事儿,非常的麻烦,而利用Redis的SortSet(有序集合)数据结构能够简单的搞定;

3、计算器/限速器,利用Redis中原子性的自增操作,我们可以统计类似用户点赞数、用户访问数等,这类操作如果用MySQL,频繁的读写会带来相当大的压力;限速器比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力;

4、好友关系,利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定一些共同好友、共同爱好之类的功能;

5、简单消息队列,除了Redis自身的发布/订阅模式,我们也可以利用List来实现一个队列机制,比如:到货通知、邮件发送之类的需求,不需要高可靠,但是会带来非常大的DB压力,完全可以用List来完成异步解耦;

6、Session共享,以PHP为例,默认Session是保存在服务器的文件中,如果是集群服务,同一个用户过来可能落在不同机器上,这就会导致用户频繁登陆;采用Redis保存Session后,无论用户落在那台机器上都能够获取到对应的Session信息。

7、一些频繁被访问的数据,经常被访问的数据如果放在关系型数据库,每次查询的开销都会很大,而放在redis中,因为redis 是放在内存中的可以很高效的访问

但是对于数据量太大、数据访问频率非常低的业务不适合使用Redis。因为数据量太大会增加成本,访问频率较低的数据,保存在内存中纯属浪费资源。

3. Redis的使用

Linux版本下载redis.io/download。

本版本使用的是最新的稳定版本6.2.4版本。

# wget http://download.redis.io/releases/redis-6.2.4.tar.gz
# tar xzf redis6.2.4.tar.gz
# cd redis-6.2.4
# make

执行完 make 命令后,redis-6.0.8 的 src 目录下会出现编译后的 redis 服务程序 redis-server,还有用于测试的客户端程序 redis-cli,启动redis服务:

# cd src
# ./redis-server

这种方式启动 redis 使用的是默认配置。也可以通过启动参数告诉 redis 使用指定配置文件使用下面命令启动。

# cd src# ./redis-server ../redis.conf

redis.conf 是一个默认的配置文件。可以根据实际需要使用自己的配置文件。

启动 redis 服务进程后,就可以使用测试客户端程序 redis-cli 和 redis 服务交互了。比如:

# cd src# ./redis-cli
redis> set key2 1024笔记 
OK
redis> get key2 
"1024笔记 "

Redis官网是没有Windows版本的,所以如果想要下载Windows版本的Redis可以去github上。

Windows版本下载github.com/tporadowski…

去上方的github地址,现在的Redis版本是5.0.10,找到zip结尾的文件,然后下载:

图片

下载之后将zip格式的进行解压:

图片

打开命令行窗口,进入到解压后的目录下,然后执行:

redis-server.exe redis.windows.conf

图片

出现如上图所示的图案,则redis启用成功了。接着另起一个命令行窗口进入到redis的解压目录下,执行命令:

redis-cli.exe -h 127.0.0.1 -p 6379

因为redis是key-value格式的,所以设置键值对:

set key1 jiangxia

通过key取值:

get key1

图片

4. Redis的数据结构

前面说到redis是key-value结构的,所以Redis 键命令用于管理 redis 的键。基本的语法格式为:

command keyname

尝试用的键命令如下:

//在key存在时删除key。
DEL key  
//序列化指定的key,并返回被序列化的值。
DUMP key
//检查给定key是否存在。
EXISTS key
//为给定 key设置过期时间,以秒计。
EXPIRE key seconds
//EXPIREAT的作用和 EXPIRE 类似,都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。
EXPIREAT key timestamp
//设置 key 的过期时间以毫秒计。
PEXPIRE key milliseconds
设置 key 过期时间的时间戳(unix timestamp) 以毫秒计
PEXPIREAT key milliseconds-timestamp
//查找所有符合给定模式( pattern)的 key 。
KEYS pattern
//将当前数据库的 key 移动到给定的数据库 db 当中。
MOVE key db
//移除 key 的过期时间,key 将持久保持。
PERSIST key
//以毫秒为单位返回 key 的剩余的过期时间。
PTTL key
//以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
TTL key
//从当前数据库中随机返回一个 key 。
RANDOMKEY
//修改 key 的名称
RENAME key newkey
//仅当 newkey 不存在时,将 key 改名为 newkey 。
RENAMENX key newkey
//迭代数据库中的数据库键。
SCAN cursor [MATCH pattern] [COUNT count]
//返回 key 所储存的值的类型。
TYPE key

比如:

图片

前面说到Redis支持存储的value类型相对更多,有以下五种:

1.字符串(string)

string类型是一个很基础的数据类型,也是任何存储系统都必备的数据类型。

string 类型是二进制安全的,可以包含任何数据。比如jpg图片或者序列化的对象。string 类型的值最大能存储 512MB。

redis中string类型的使用如下:

图片

使用了 Redis 的 set(设置键值对) 和 get(通过key获取value)命令。键为 key1,value是"jiangxia"。

在遇到数值操作时,redis会将字符串类型转换成数值

图片

Redis的Incr命令将 key 中储存的数字值增1。该命令具有原子性。类似的还有INCRBY(将 key 中储存的数字加上指定的增量值)、DECR(将 key 中储存的数字值减一)、DECRBY(将 key 所储存的值减去指定的减量值‍)。

应用场景:String是最常用的一种数据类型,普通的key/ value 存储都可以归为此类,即可以完全实现目前 Memcached 的功能,并且效率更高。还可以享受Redis的定时持久化,操作日志及 Replication等功能。除了提供与 Memcached 一样的get、set、incr、decr 等操作外,Redis还提供了下面一些操作:

1、获取字符串长度

2、往字符串append内容

3、设置和获取字符串的某一段内容

4、设置及获取字符串的某一位(bit)

5、批量设置一系列字符串的内容

所以常规key-value缓存应用都可以使用这种数据结构。比如常规的计数: 微博数, 粉丝数,点赞数等等

2.字符串列表(list)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

Redis中的list在底层实现上并不是数组,而是链表,也就是说对于一个list来在头部和尾部插入一个新元素,其时间复杂度是常数级别的,比如用Lpush在10个元素的list头部插入新元素,和在上千万元素的list头部插入新元素的速度应该是相同的。虽然list有这样的优势,但同样有其弊端,那就是,链表型list的元素定位会比较慢,而数组型list的元素定位就会快得多。lists的常用操作包括Lpush、Rpush、Lrange等。我们可以用Lpush在list的左侧插入一个新元素,用Rpush在list的右侧插入一个新元素,用Lrange命令从lists中指定一个范围来提取元素。列表相关基本命令如下:

//移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BLPOP key1 [key2 ] timeout
//移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOP key1 [key2 ] timeout
//从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它;如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOPLPUSH source destination timeout
//通过索引获取列表中的元素
LINDEX key index
//在列表的元素前或者后插入元素
LINSERT key BEFORE|AFTER pivot value
//获取列表长度
LLEN key
//移出并获取列表的第一个元素
LPOP key
//将一个或多个值插入到列表头部
LPUSH key value1 [value2]
//将一个值插入到已存在的列表头部
LPUSHX key value
//获取列表指定范围内的元素
LRANGE key start stop
//移除列表元素
LREM key count value
//通过索引设置列表元素的值
LSET key index value
//对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
LTRIM key start stop
//移除列表的最后一个元素,返回值为移除的元素。
RPOP key
//移除列表的最后一个元素,并将该元素添加到另一个列表并返回
RPOPLPUSH source destination
//在列表中添加一个或多个值
RPUSH key value1 [value2]
//为已存在的列表添加值
RPUSHX key value

比如:

图片

应用场景:Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如常见的微博的关注列表,粉丝列表等都可以用这种数据结构来实现。List的另一个应用就是消息队列,可以利用List的push操作,将任务存在List中,然后工作线程再用pop操作将任务取出进行执行。Redis还提供了操作List中某一段的api,可以直接查询,删除List中某一段的元素。使用sorted set甚至可以构建有优先级的队列系统。

3.字符串集合(set)

redis的集合,是一种无序的集合,集合中的元素没有先后顺序。

集合相关的操作也很丰富,如添加新元素、删除已有元素、取交集、取并集、取差集等。集合相关的命令如下:

//向集合添加一个或多个成员
SADD key member1 [member2]
//获取集合的成员数
SCARD key
//返回第一个集合与其他集合之间的差异。
SDIFF key1 [key2]
//返回给定所有集合的差集并存储在 destination 中
SDIFFSTORE destination key1 [key2]
//返回给定所有集合的交集
SINTER key1 [key2]
//返回给定所有集合的交集并存储在 destination 中
SINTERSTORE destination key1 [key2]
//判断 member 元素是否是集合 key 的成员
SISMEMBER key member
//返回集合中的所有成员
SMEMBERS key
//将 member 元素从 source 集合移动到 destination 集合
SMOVE source destination member
//移除并返回集合中的一个随机元素
SPOP key
//返回集合中一个或多个随机数
SRANDMEMBER key [count]
//移除集合中一个或多个成员
SREM key member1 [member2]
//返回所有给定集合的并集
SUNION key1 [key2]
//所有给定集合的并集存储在 destination 集合中
SUNIONSTORE destination key1 [key2]
//迭代集合中的元素
SSCAN key cursor [MATCH pattern] [COUNT count]

比如:

图片

应用场景:Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。Set 就是一个集合,集合的概念就是一堆不重复值的组合。利用Redis提供的Set数据结构,可以存储一些集合性的数据。

4.有序字符串集合(zset,sorted set)

Redis不但提供了无需集合(set),还很体贴的提供了有序集合(sorted sets)。有序集合中的每个元素都关联一个序号(score),这便是排序的依据。

很多时候,我们都将redis中的有序集合叫做zsets,这是因为在redis中,有序集合相关的操作指令都是以z开头的,比如zrange、zadd、zrevrange、zrangebyscore等等。常见命令如下:

//向有序集合添加一个或多个成员,或者更新已存在成员的分数
ZADD key score1 member1 [score2 member2]
//获取有序集合的成员数
ZCARD key
//计算在有序集合中指定区间分数的成员数
ZCOUNT key min max
//有序集合中对指定成员的分数加上增量 increment
ZINCRBY key increment member
//计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 destination 中
ZINTERSTORE destination numkeys key [key ...]
//在有序集合中计算指定字典区间内成员数量
ZLEXCOUNT key min max
//通过索引区间返回有序集合指定区间内的成员
ZRANGE key start stop [WITHSCORES]
//通过字典区间返回有序集合的成员
ZRANGEBYLEX key min max [LIMIT offset count]
//通过分数返回有序集合指定区间内的成员
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT]
//返回有序集合中指定成员的索引
ZRANK key member
//移除有序集合中的一个或多个成员
ZREM key member [member ...]
//移除有序集合中给定的字典区间的所有成员
ZREMRANGEBYLEX key min max
//移除有序集合中给定的排名区间的所有成员
ZREMRANGEBYRANK key start stop
//移除有序集合中给定的分数区间的所有成员
ZREMRANGEBYSCORE key min max
//返回有序集中指定区间内的成员,通过索引,分数从高到低
ZREVRANGE key start stop [WITHSCORES]
//返回有序集中指定分数区间内的成员,分数从高到低排序
ZREVRANGEBYSCORE key max min [WITHSCORES]
//返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
ZREVRANK key member
//返回有序集中,成员的分数值
ZSCORE key member
//计算给定的一个或多个有序集的并集,并存储在新的 key 中
ZUNIONSTORE destination numkeys key [key ...]
//迭代有序集合中的元素(包括元素成员和元素分值)
ZSCAN key cursor [MATCH pattern] [COUNT count]

比如:

图片

应用场景:Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如微信公众号文章的发布时间可以作为score来存储,这样获取时就是自动按时间排好序的。

5.哈希(hash)

哈希是从redis-2.0.0版本之后才有的数据结构。它是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。hashes存的是字符串和字符串值之间的映射,比如一个用户要存储其全名、姓氏、年龄等等,就很适合使用哈希。常见命令如下:

//删除一个或多个哈希表字段
HDEL key field1 [field2]
//查看哈希表 key 中,指定的字段是否存在。
HEXISTS key field
//获取存储在哈希表中指定字段的值。
HGET key field
//获取在哈希表中指定 key 的所有字段和值
HGETALL key
//为哈希表 key 中的指定字段的整数值加上增量 increment 。
HINCRBY key field increment
//为哈希表 key 中的指定字段的浮点数值加上增量 increment 。
HINCRBYFLOAT key field increment
//获取所有哈希表中的字段
HKEYS key
//获取哈希表中字段的数量
HLEN key
//获取所有给定字段的值
HMGET key field1 [field2]
//同时将多个 field-value (域-值)对设置到哈希表 key 中。
HMSET key field1 value1 [field2 value2 ]
//将哈希表 key 中的字段 field 的值设为 value 。
HSET key field value
//只有在字段 field 不存在时,设置哈希表字段的值。
HSETNX key field value
//获取哈希表中所有值。
HVALS key
//迭代哈希表中的键值对。
HSCAN key cursor [MATCH pattern] [COUNT count]

比如:

图片

应用场景:由于hash的特性,所以hash数据结构可以用来存储部分变更数据,比如用户信息对象数据。

关于Redis更多的命令可以参考:redis.io/commands。

5. 总结

本文主要就介绍了以下什么是redis、redis的数据结构以及其简单使用。redis其实在日常的生产中使用到的机会还是很大的。所以学会redis也是提高自身硬实力的一种重要方式,这样才能在面试中取得好成绩。当然这篇文章只是简单的介绍了一些偏于理论的知识,关于redis的使用后面应该还会分一些篇幅还进行介绍。

如果你觉得本文不错,就点个关注,获取后续更多文章,然后点赞分享给更多的人吧!

如果你觉得文章有不足之处,或者更多的想法和理解,欢迎指出讨论!

公众号.jpg 相关推荐:

公众号.jpg

图片