Redis的核心数据结构介绍和使用,以及Redis高性能原理剖析
Linux环境下Redis的安装 环境搭建 本文以CentOS Linux release 7.9.2009 (Core)为例,演示安装过程。
Redis下载地址:https://redis.io/download/#redis-downloads
因为官网下载下来的是redis源码,不能直接解压使用,需要用gcc编译器进行编译,才会生成可执行文件。
服务器安装gcc编译环境
查看gcc的版本
将下载好的压缩包,复制到服务器的目录中。或者直接使用wget,将压缩包下载到服务器上。
1 wget https://download.redis.io/releases/redis-6.2.12.tar.gz
解压压缩包到当前目录,进入目录,并进行编译
1 2 3 tar -zxvf redis-6.2.12.tar.gz cd redis-6.2.12 make
如果编译期间出错,使用
清除编译生成的文件,处理错误后,再次使用 make 重新编译
配置修改 使用vim修改redis.conf文件
1 2 3 4 5 6 daemonize yes requirepass 123456 bind 0.0.0.0
启动redis
1 2 cd src ./redis-server ../redis.conf
查看redis是否启动
使用redis客户端,连接redis
输入密码,就可以执行redis命令了
Redis基础数据类型 Redis有五种基本数据类型
String 字符串常用操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 存入字符串键值对 SET key value // 获取一个字符串键值 GET key // 删除一个键 DEL key [key ...] // 存入一个不存在的字符串键值对 SETNX key value // 批量存储字符串键值对 MSET key value [key value ...] // 批量获取字符串键值 MGET key [key ...] // 设置一个键的过期时间(秒) EXPIRE key seconds
原子加减 1 2 3 4 5 6 7 8 // 将key中储存的数字值加1 INCR key // 将key中储存的数字值减1 DECR key // 将key所储存的值加上increment INCRBY key increment // 将key所储存的值减去decrement DECRBY key decrement
String应用场景 单值缓存
对象缓存 1 2 3 set user:1 value(json数据) mset user:1:name zhangsan user:1:age 18 mget user:1:name user:1:age
分布式锁 1 2 3 4 5 6 7 8 // 返回1代表加锁成功1 setnx order:1 true // 返回0代表加锁失败 setnx order:1 true // 业务执行完毕释放锁 del order:1 // 加锁并设置过期时间,防止死锁 set order:1 true ex 10 nx
计数器 1 2 3 // 文章阅读次数+1 INCR article:readcount:{文章id} GET article:readcount:{文章id}
session共享 1 spring session + redis实现session共享
分布式序列号 1 2 // redis批量生成序列号提升性能 INCRBY orderId 1
Hash Hash常用操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // 存储一个哈希表key的键值 HSET key field value // 存储一个不存在的哈希表key的键值 HSETNX key field value // 在一个哈希表key中存储多个键值对 HMSET key field value [field value ...] // 获取哈希表key对应的field键值 HGET key field // 批量获取哈希表key中多个field键值 HMGET key field [field ...] // 删除哈希表key中的field键值 HDEL key field [field ...] // 返回哈希表key中field的数量 HLEN key // 返回哈希表key中所有的键值 HGETALL key // 为哈希表key中field键的值加上增量increment HINCRBY key field increment
Hash应用场景 对象缓存 1 2 HMSET user 1:name zhuge 1:balance 1888 HMGET user 1:name 1:balance
优点
同类数据归类整合储存,方便数据管理
相比string操作消耗内存与cpu更小
相比string储存更节省空间
缺点
过期功能不能使用在field上,只能用在key上
Redis集群架构下不适合大规模使用
List List常用操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 将一个或多个值value插入到key列表的表头(最左边) LPUSH key value [value ...] // 将一个或多个值value插入到key列表的表尾(最右边) RPUSH key value [value ...] // 移除并返回key列表的头元素 LPOP key // 移除并返回key列表的尾元素 RPOP key // 返回列表key中指定区间内的元素,区间以偏移量start和stop指定 LRANGE key start stop // 从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待 BLPOP key [key ...] timeout // 从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待 BRPOP key [key ...] timeout
List应用场景 1 2 3 Stack(栈) = LPUSH + LPOP Queue(队列)= LPUSH + RPOP Blocking MQ(阻塞队列)= LPUSH + BRPOP
Set Set常用操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 往集合key中存入元素,元素存在则忽略,若key不存在则新建 SADD key member [member ...] // 从集合key中删除元素 SREM key member [member ...] // 获取集合key中所有元素 SMEMBERS key // 获取集合key的元素个数 SCARD key // 判断member元素是否存在于集合key中 SISMEMBER key member // 从集合key中选出count个元素,元素不从key中删除 SRANDMEMBER key [count] // 从集合key中选出count个元素,元素从key中删除 SPOP key [count]
Set运算操作 1 2 3 4 5 6 7 8 9 10 11 12 // 交集运算 SINTER key [key ...] // 将交集结果存入新集合destination中 SINTERSTORE destination key [key ..] // 并集运算 SUNION key [key ..] // 将并集结果存入新集合destination中 SUNIONSTORE destination key [key ...] // 差集运算 SDIFF key [key ...] // 将差集结果存入新集合destination中 SDIFFSTORE destination key [key ...]
Set应用场景 抽奖小程序 1 2 3 4 5 6 // 点击参与抽奖加入集合 SADD key {userlD} // 查看参与抽奖所有用户 SMEMBERS key // 抽取count名中奖者 SRANDMEMBER key [count] / SPOP key [count]
微博或朋友圈点赞 1 2 3 4 5 6 7 8 9 10 // 点赞 SADD like:{消息ID} {用户ID} // 取消点赞 SREM like:{消息ID} {用户ID} // 检查用户是否点过赞 SISMEMBER like:{消息ID} {用户ID} // 获取点赞的用户列表 SMEMBERS like:{消息ID} // 获取点赞用户数 SCARD like:{消息ID}
集合操作 1 2 3 SINTER set1 set2 set3 -> { c } SUNION set1 set2 set3 -> { a,b,c,d,e } SDIFF set1 set2 set3 -> { a }
zset zset常用操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 往有序集合key中加入带分值元素 ZADD key score member [[score member]…] // 从有序集合key中删除元素 ZREM key member [member …] // 返回有序集合key中元素member的分值 ZSCORE key member // 为有序集合key中元素member的分值加上increment ZINCRBY key increment member // 返回有序集合key中元素个数 ZCARD key // 正序获取有序集合key从start下标到stop下标的元素 ZRANGE key start stop [WITHSCORES] // 倒序获取有序集合key从start下标到stop下标的元素 ZREVRANGE key start stop [WITHSCORES]
zset集合操作 1 2 3 4 // 并集计算 ZUNIONSTORE destkey numkeys key [key ...] // 交集计算 ZINTERSTORE destkey numkeys key [key …]
zset应用场景 排行榜 1 2 3 4 5 6 7 8 9 // 点击新闻 ZINCRBY hotNews:20190819 1 守护香港 // 展示当日排行前十 ZREVRANGE hotNews:20190819 0 9 WITHSCORES // 七日搜索榜单计算 ZUNIONSTORE hotNews:20190813-20190819 7 hotNews:20190813 hotNews:20190814... hotNews:20190819 // 展示七日排行前十 ZREVRANGE hotNews:20190813-20190819 0 9 WITHSCORES
Redis的单线程和高性能 单线程和高性能 Redis是单线程吗?
Redis 的单线程主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。
Redis 单线程为什么还能这么快?
因为它所有的数据都在内存 中,所有的运算都是内存级别的运算,而且单线程避免了多线程的切换性能损耗问题。正因为 Redis 是单线程,所以要小心使用 Redis 指令,对于那些耗时的指令(比如keys),一定要谨慎使用,一不小心就可能会导致 Redis 卡顿。
Redis 单线程如何处理那么多的并发客户端连接?
Redis的IO多路复用 :redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。
1 2 3 4 # 查看redis支持的最大连接数,在redis.conf文件中可修改, 127.0.0.1:6379> CONFIG GET maxclients ##1) "maxclients" ##2) "10000"
其他高级命令 keys keys:全量遍历键 ,用来列出所有满足特定正则字符串规则的key,当redis数据量比较大时,性能比较差,要避免使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 127.0.0.1:6379> set name1 a OK 127.0.0.1:6379> set name2 b OK 127.0.0.1:6379> set name3 c OK 127.0.0.1:6379> set name4 d OK 127.0.0.1:6379> set name5 e OK 127.0.0.1:6379> keys name* 1) "name2" 2) "name4" 3) "name5" 4) "name3" 5) "name1" 127.0.0.1:6379>
scan scan:渐进式遍历键
SCAN cursor [MATCH pattern] [COUNT count]
scan 参数提供了三个参数,第一个是 cursor 整数值(hash桶的索引值),第二个是 key 的正则模式,第三个是一次遍历的key的数量(参考值,底层遍历的数量不一定),并不是符合条件的结果数量。第一次遍历时,cursor 值为 0,然后将返回结果中第一个整数值作为下一次遍历的 cursor。一直遍历到返回的 cursor 值为 0 时结束。
注意:但是scan并非完美无瑕, 如果在scan的过程中如果有键的变化(增加、 删除、 修改) ,那么遍历效果可能会碰到如下问题: 新增的键可能没有遍历到, 遍历出了重复的键等情况, 也就是说scan并不能保证完整的遍历出来所有的键, 这些是我们在开发时需要考虑的。
1 2 3 4 5 6 7 8 9 10 127.0.0.1:6379> scan 0 match name* count 3 1) "5" 2) 1) "name4" 2) "name5" 3) "name2" 127.0.0.1:6379> scan 5 match name* count 3 1) "0" 2) 1) "name3" 2) "name1" 127.0.0.1:6379>
info 查看redis服务运行信息,分为 9 大块,每个块都有非常多的参数,这 9 个块分别是:
Server 服务器运行的环境参数
Clients 客户端相关信息
Memory 服务器运行内存统计数据
Persistence 持久化信息
Stats 通用统计数据
Replication 主从复制相关信息
CPU CPU 使用情况
Cluster 集群信息
KeySpace 键值对统计数量信息
1 2 3 4 5 6 7 8 9 10 11 12 13 connected_clients:2 # 正在连接的客户端数量 instantaneous_ops_per_sec:789 # 每秒执行多少次指令 used_memory:929864 # Redis分配的内存总量(byte),包含redis进程内部的开销和数据占用的内存 used_memory_human:908.07K # Redis分配的内存总量(Kb,human会展示出单位) used_memory_rss_human:2.28M # 向操作系统申请的内存大小(Mb)(这个值一般是大于used_memory的,因为Redis的内存分配策略会产生内存碎片) used_memory_peak:929864 # redis的内存消耗峰值(byte) used_memory_peak_human:908.07K # redis的内存消耗峰值(KB) maxmemory:0 # 配置中设置的最大可使用内存值(byte),默认0,不限制,一般配置为机器物理内存的百分之七八十,需要留一部分给操作系统 maxmemory_human:0B # 配置中设置的最大可使用内存值 maxmemory_policy:noeviction # 当达到maxmemory时的淘汰策略