一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
redis 安装
# 安装gcc
yum install gcc
## 下载
cd /usr/local/
wget https://download.redis.io/releases/redis-6.2.6.tar.gz
tar -zxvf redis-6.2.6.tar.gz
cd redis-6.2.6/
make
## 到此已经安装完成
## 备份配置文件
cp redis.conf redis.conf_bak
## 修改配置文件
daemonize yes ## 后台启动
protected-mode no ## 关闭保护模式,开启的话只有本机才可以访问redis
## 注释掉bind 127.0.0.1,bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可
# bind 127.0.0.1
## 启动服务
./src/redis-server ./redis.conf
## 验证是否启动
ps -ef|grep redis
## redis客户端连接
./src/redis-cli
## 退出redis客户端
control+c
redis 数据结构
五种基本数据结构
- 字符串 string
- 哈希 hash
- 列表 list
- 集合 set
- 有序集合 zset
高级数据类型
- 位图 bitmaps
- HyperLogLog
- 地理位置 GEO
这里不做过多说明,后续单独讲解。
String 结构
字符串常用操作
SET key value # 设置字符串键值对
GET key # 获取一个字符串key对应的键值
MSET key value [key value ...] # 批量设置键值对
MGET key [key ...] # 批量获取字符串key对应的键值
SETNX key value # 存入一个不存在的键值对,只有键不存在时才能存入成功
DEL key [key ...] # 删除
EXPIRE key seconds # 设置一个键的过期时间
原子加减
INCR key # 将key中存储的数字加1
DECR key # 将key中存储的数字减1
INCRBY key increment # 将key中存储的值加上increment
DECRBY key decrement # 将key中存储的key减去decrement
String 应用场景
-
单值缓存
SET key value / GET key
-
对象缓存
# 常用命令 SET key value(json) get key # (反序列化) # 批量操作 MSET user:1:name beifeng user:1:age 18 MGET user:1:name user:1:age
-
分布式锁
SETNX lesson:1 true # 返回1代表获取锁成功,0代表获取锁失败 # 执行业务逻辑 DEL lesson:1 # 原子操作,防止程序意外终止而导致死锁 SET lesson:1 true ex 10 nx
-
计数器
# 统计文章阅读数量 incr readcount get readcount
-
web 集群 session 共享
spring session + redis实现session共享
-
分布式系统全局序列号
# 批量获取一批ID,程序内部维护自增逻辑,用完了获取下一批,避免频繁请求redis INCRBY lessonid 1000
hash 结构
hash 常用操作
HSET key field value [field value ...] # 存储一个hash表key的值,支持批量操作
HMSET key field value [field value ...] # 在一个hash表key中批量存储多个键值对
HGET key field # 获取hash表中key对应的filed的键值
HMGET key field [field ...] # 批量获取hash表中key对应的多个filed的键值
HSETNX key field value # 存储一个在hash表中不存在的filed的值
HDEL key field [field ...] # 删除hash表中的filed的键值,支持批量操作
HLEN key # 返回hash表中field的数量
HGETALL key # 返回hash表key中所有的键值
HINCRBY key field increment # hash表中key的field键对应的值加上增量 increment
hash 应用场景
-
对象缓存
HSET user 1:name beifeng 1:age 20 HMGET user 1:name 1:age
-
电商购物车
# 以用户ID为key : 商品ID为field,商品数量为field # 购物车操作:添加商品 hset cart:999 100 1 # 增加商品数量 hincrby cart:999 100 1 # 商品总数 hlen cart:999 # 删除商品 hdel cart:999 100 # 获取购物车所有商品 hgetall cart:999
hash 结构的优缺点
优点
- 同类数据归类整合存储,方便数据管理
- 相比 string 操作消化内存与 cpu 更小
- 相比 string 更节省存储空间
缺点
- 过期功能不能用在 field 上,只能用在 key 上
- redis 集群架构不适合大规模使用
list 结构
list 常用操作
LPUSH key element [element ...] # 将一个或多个值插入到key列表的表头(最左边)
RPUSH key element [element ...] # 将一个或多个值插入到key列表的表位(最右边)
LPOP key [count] # 移除并且返回 key 对应的 list 的第一个元素。[count] 指定弹出的数量
RPOP key [count] # 移除并返回存于 key 的 list 的最后一个元素。[count] 指定弹出的数量
LRANGE key start stop # 返回列表key中指定区间内的元素,区间以偏移量start和stop指定 stop=-1 返回全部
BLPOP key [key ...] timeout # 从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,timeout=0,一直阻塞
BRPOP key [key ...] timeout # 从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,timeout=0,一直阻塞
list 应用场景
-
stack
栈LPUSH+LPOP
-
QUEUE
对列LPUSH+RPOP
-
Blocking MQ
阻塞队列LPUSH+BRPOP
-
微博和公众号的信息流
-
微博消息和公众号消息
# 用户A关注了 V1,V2 等大 V # V1 发微博,消息ID为 6666 LPUSH msg:user-A 6666 # V2 发微博,消息ID为 6667 LPUSH msg:user-A 6667 # A 用户查看最新的消息 LRANGE msg:user-A 0 4
Set 结构
Set常用操作
SADD key member [member ...] # 往集合key中加入元素,元素存在则忽略,若key不存在则新建
SREM key member [member ...] # 从集合key中删除元素
SMEMBERS key # 获取集合key中所有元素
SCARD key # 获取集合key的元素个数
SISMEMBER key member # 判断member元素是否存储在集合key中
SRANDMEMBER key [count] # 从集合key中选出count个元素,元素不从key中删除 ,不指定count默认1个
SPOP key [count] # 从集合key中选出count个元素,元素从key中删除,不指定count默认1个
Set 运算操作
SINTER key [key ...] # 交集运算
SINTERSTORE destination key [key ...] # 将交集运算结果存入新集合destination中
SUNION key [key ...] # 并集运算
SUNIONSTORE destination key [key ...] # 将并集结果存入新集合destination中
SDIFF key [key ...] # 差集运算,以第一个key为基准,减去后面集合的并集
SDIFFSTORE destination key [key ...] # 将差集结果存入新集合destination中
Set 应用场景
-
微信抽奖小程序
# 参与抽奖的人加入集合 SADD key {userlD} # 查看所有参与抽奖的用户 SMEMBERS key # 抽取count名中奖者 SRANDMEMBER key [count] / SPOP key [count]
-
微信微博点赞、收藏、标签
# 点赞 SADD like:{消息ID} 用户ID # 取消点赞 SREM like:{消息ID} 用户ID # 检查用户是否点赞过 SISMEMBER like:{消息ID} 用户ID # 获取点赞的用户列表 SMEMBERS like:{消息ID} # 获取点赞的用户数 SCARD like:{消息ID}
-
集合之间的操作,交集、差集、并集
-
集合操作实现微博微信关注模型
# 蜘蛛侠关注的人 zhizhuxia-set -> {gangtiexia,mieba} # 钢铁侠关注的人 gangtiexia-set -> {meiguoduizhang,heibao,yingyan,mieba} # 奇异博士关注的人 qiyiboshi-set -> {heiguafu,jinganglang,zhizhuxia} # 蜘蛛侠个钢铁侠共同关注的人 --> 取两个集合的交集 SINTER zhizhuxia-set gangtiexia-set -> {mieba} # 蜘蛛侠可能认识的人 SDIFF gangtiexia-set zhizhuxia-set # 蜘蛛侠关注的人也关注他,钢铁侠是否也关注了灭霸 SISMEMBER gangtiexia-set mieba
-
集合操作实现电商商品筛选
SADD brand:huawei P40 SADD brand:xiaomi mi-10 SADD brand:iPhone iphone12 SADD os:android P40 mi-10 SADD cpu:brand:intel P40 mi-10 SADD ram:8G P40 mi-10 iphone12 # 交集 SINTER os:android cpu:brand:intel ram:8G -> {P40,mi-10}
Zset 有序集合结构
Zset 常用操作
ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...] # 往有序集合key中添加带分值的元素
ZCARD key # 返回有序集合key中元素的个数
ZREM key member [member ...] # 删除有序集合key中的元素member
ZSCORE key member # 返回有序集合key中元素member的分值
ZINCRBY key increment member # 为有序集合key中元素member加上increment分值
ZCARD key # 返回有序集合key中元素个数
ZRANGE key min max [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES] # 正序获取有序集合key中分值从min到max的元素
ZREVRANGE key start stop [WITHSCORES] # 倒序获取有序集合key从start下标到stop下标的元素
Zset 集合操作
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] # 并集操作
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] # 交集操作
Zset 集合应用
-
Zset 集合操作实现排行榜
# 点击新闻 ZINCRBY hotNews:20220317 1 乌克兰 # 展示当日排行前十 ZREVRANGE hotNews:20190819 0 9 WITHSCORES # 七日搜索榜单计算 ZUNIONSTORE hotNews:20190813-20190819 7 # 展示七日排行前十 ZREVRANGE hotNews:20190813-20190819 0 9 WITHSCORES
其他高级命令
-
查看redis支持的最大连接数
CONFIG GET maxclients
-
全量遍历键,keys 用来列出所有满足特定正则字符串规则的 key,当 redis 数据量比较大时,性能比较差,要避免使用。
keys * keys match*
-
scan 渐进式遍历键。注意:scan 并非完美无瑕,如果在遍历的过程中有键的变化(增加、修改、删除),那么遍历可能会碰到如下问题
- 新增的键可能没有遍历到
- 遍历出了重复的键的情况
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type] # cursor 整数值,hash桶的索引值 # MATCH pattern key 的正则表达式 # COUNT 一次遍历的key的数量,参考值,底层遍历数量不一定,并不是符合条件的结果数量 # 第一次遍历时 cursor 值为 0,然后将返回结果中第一个整数作为下一次遍历的 cursor。 # 一直遍历到返回的 cursor 值为0时结束。
-
info 查看 redis 服务运行信息,总共9大块
Server 服务器运行的环境参数 Clients 客户端相关信息 Memory 服务器运行内存统计数据 Persistence 持久化信息 Stats 通用统计数据 Replication 主从复制相关信息 CPU CPU 使用情况 Cluster 集群信息 KeySpace 键值对统计数量信息 ####### 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时的淘汰策略
Redis 的单线程和高性能
Redis 是单线程的吗?
redis的单线程主要是指 redis 的网络 IO 和键值对读写由一个线程来完成,这也是 redis 对外提供键值存储服务的主要流程。但 redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实都是由额外的线程执行的。
Redis 的单线程为什么还能这么快?
因为他所有的数据都存储在**内存
**中,所有运算都是内存级别的运算,而且单线程避免了多线程的切换性能损耗问题。
正因为 redis 是单线程,所以要小心使用 redis 指令,对于那些耗时的指令(keys),一定要谨慎操作,一不小心可能会导致 redis 卡顿。
Redis 单线程如何处理那么多的并发客户端链接?
redis 的IO多路复用:redis 利用 epoll 来实现 IO 多路复用,将链接信息和事件放到队列中,依次放到事件分派器,事件分派器将事件分发给事件处理器。