redis
- 写在前面:
感觉这是24年从0-1最完整的一个笔记了;
基础
- 内存硬盘并行存储运行速度快 c开发 单线程 非关系型数据库
flushdb
删除当前库所有keyflushall
删除所有key
特性
1.源码高质量 运行速度快 c开发 单线程
2.丰富数据类型 字符串;哈希;列表;集合;有序集合
3.功能丰富;计时器---点赞、评论数 key过期功能--购物车订单 消息队列 发布订阅--聊天室
4.支持多语言客户端
5.支持数据持久化 可以混合持久化
6.内置高可用架构 主从 哨兵 集群
部署
mkdir -p /data/soft
mkdir -p /opt/redis_6379/{conf,logs,pid}
cd /data/soft
wget https://download.redis.io/releases/redis-5.0.7.tar.gz
yum install gcc make -y
tar zxvf redis-5.0.7.tar.gz -C /opt/
cd /opt/redis-5.0.7
make MALLOC=libc && make install
#不指定安装目录bin默认在/usr/local/bin
conf:
daemonize yes
bind 127.0.0.1 172.16.50.100
port 6379
pidfile /opt/redis_6379/pid/redis_6379.pid
logfile /opt/redis_6379/logs/redis_6379.log
#bin命令解释:
redis-benchmark 性能测试
redis-check-aof 检查aof数据状态
redis-check-rdb 检查rdb数据状态
redis-cli 客户端登陆状态
redis-sentinel 软链接到server
redis-server 哨兵 启动服务端
常见命令
redis-cli 登陆
redis-server .conf
redis-cli shutdown 关闭redis 直接kill会redis内数据丢失
redis-cli -h ip -a passwd -p port
dbsize 查看key数量
info 查看基本信息
info keyspace 直接加区块名也可以直接查看 (查看各个库数据)
select [0~15] 切换库 (默认登陆0库 每一个库存储自己独立的key)
exists key 查询key有多少个
del key 删除key
ttl name 查看过期倒计时 -1是永久 -2是已过期
EXPIRE key 180 定义key过期时间
type key 查看key类型 (string)
redis-cli --raw -n 15 dbsize 外部指定查询15库
redis-cli --scan --pattern '*2*' 通配符查找有2的key #比keys *安全
config set requirepass password` 改密码命令 改成get查询密码 不过是临时的 永久的还是配置文件为主
数据类型
- 默认16个库 0~15
- 数据类型的区别在于值的表现
字符串(string)
set get 是定义字符串
set name zhaoxi
get name zhaoxi
set key value (set name zhaoxi EX 60 60s后自动删除
set name test 会被覆盖
set name 赵析 支持中文但是不建议 会返回16进制
redis-cli --raw get name 源格式返回数据)
mset name 1 name2 2 name3 3 多个一起定义;多个一起查询同理 mget
incr key 自增 for i in {1..100}; do redis-cli incr dianzan; done
dncr key 自减
incrby key 自定义加多少
decrby key 自定义减多少
使用场景:
- 数据缓存:经典用法,把经常要读取的mysql中的url、字符串等信息存储到redis中,redis作为缓存层,加速数据读取,mysql作为数据持久化层,降低mysql的访问压力;
- 计数器:redis是单线程模式,一个命令结束才会执行下一条命令,因此可以实现计数器的作用,确保多线程访问redis的数据也能确保数据源的正确性;比如点赞、阅读量等;
- 用作网站用户的登录会话存储:存储session,token等信息;
列表(list)
- lpush lrange
- 写入顺序是0-*** lrange key 1 3 是第二个到第四个
lpush name zhaoxi zhangsan
rpush name right 从右推入
lpop name 删除左边第一个并展示数据
rpop name 删除右边第一个并展示数据
del name 删除所有name中value
lindex name 2 展示左边第三个value
lrange name 0 -1 开头-结尾
lpush name 1 2 3
lrange name 0 -1 是3 2 1 先进先出顺序
![[Pasted image 20241014223348.png]]
使用场景:
- 生产消费者模型 lpush写入数据 右边rpop取走数据
集合(set)
- 集合数据类型能天然去重,在集合中查询也特别快
- 集合成员是唯一的 是字符串(string)类型的无序集合,称之为容器的数据类型(可以放东西)
sadd name zhaoxi test
scard name 查看多少个value
smembers name 查看value
sismember name zhaoxi 查看value是否存在 0不存在1存在
set 和 list 区别
- list可以存储重复元素 set天然去重 可以存储订单号 身份证号等
- list有序存储 set无序存储
并集 交集 差集
1.建两个测试key
2. sunion key key2 交集
3. sinter key key2 并集
4. sdiff key key2 差集
#语法 sdiff set1 set2 set1里有的但是set2没有的列出来
使用场景:
- 用户收藏夹 利用set去重功能,实现不会重复收藏,重复点赞等
有序集合(zset)
- 与set不同的是每个元素都会关联一个double类型的分数,redis通过分数来为集合中的成员进行从小到大排序
zadd key 分数 value 分数 value (比set多了个分数)创建有序集合,进行分数添加,也支持一次添加多个
zrange key 0 -1 列出zset元素 默认从小到大 后面跟withscores 携带分数
zcard key列出集合元素个数
zrem key value 删除某成员
zscore key value 查看某成员参数
zrank key value 查看成员索引下标 0开始
zrevrange key 0 -1 从大到小列出成员
zincrby key 分数 value 添加分数
使用场景:
- 排行榜
- 工资排行
- 成绩排行
哈希(hash)
- hash是一个string类型的key-value的映射表,hash特别适合用于存储对象
hset key key1 value1 hset stu name zhaoxi
hget key key1
hgetall key 取出所有
hdel key key1 删除
hmset 定义多个key1 value
hmget 查询多个key1的value
使用场景:
- 用户信息表
![[Pasted image 20241014231512.png]]
redis预热mysql数据
1.docker run -d -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD="zhaoxi" mysql
2.docker exec -it mysql mysql -pzhaoxi
create database test;
create table test.t1(id int,name varchar(50),age int);
insert into test.t1 values(1,'name',18),(2,'ceshi',11),(3,'test',12);
mysql> select * from test.t1;
+------+-------+------+
| id | name | age |
+------+-------+------+
| 1 | name | 18 |
| 2 | ceshi | 11 |
| 3 | test | 12 |
+------+-------+------+
3 rows in set (0.00 sec)
hset hash mysql中的数据
唉没啥用 得用代码把mysql中的数据导入到redis中
持久化
- redis是一个基于内存的数据库,如果服务宕机,内存中的数据就会丢失
- redis持久化方案有四种:RDB、AOF、虚拟内存和DISKSTORE,官方明确支持的就只有RDB和AOF。
RDB持久化
概念:
- RDB就是redis databases缩写 中文名为快照/内存快照
- 优点:数据压缩、恢复速度快 适用于备份、全量复制场景
- 缺点:非实时备份,可能导致数据丢失 每次调用bgsave都需要fork子进程 fork子进程属于重量级操作 频繁执行成本较高 rdb文件是二进制 没有可读性(strings dump文件可以查看 、),aof可以手动修改或者补全 版本兼容问题
- 针对rdb不适合实时持久化问题,redis提供了aof持久化方式
实战:
- 触发方式分为手动触发和自动触发。
- 本质上都是执行了rdb数据快照命令,save和bgsave
- save:阻塞当前redis,直到rdb过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上生产不建议使用。
- bgsave:redis进程执行fork操作创建子进程,rdb持久化过程由子进程负责,完成后自动结束,阻塞只发生在fork阶段,一般时间很短。
手动:
daemonize yes
bind 127.0.0.1 172.16.40.230
port 6379
dir /redis_db/ #注意这个
pidfile /opt/redis_6379/pid/redis_6379.pid
logfile /opt/redis_6379/logs/redis_6379.log
redis-cli bgsave 就保存到/redis_db/下了 dump.rdb 名字不能乱改 否则conf要指定名字
- 这时候redis-cli shutdown 数据就没了 这时候直接启动redis就会被读出来
自动:
- conf配置了rdb参数后以下四个场景会出发持久化
- 主动执行bgsave
- 达到save 900 1 命令操作,900秒后执行bgsave
- 主从复制,默认是sdb数据同步
- 执行debug reload命令触发bgsave操作
- 执行shutdown也会出发
- 执行kill -9不会触发
daemonize yes
bind 127.0.0.1 192.168.32.106
port 6379 pidfile /opt/redis_6379/pid/redis_6379.pid logfile /opt/redis_6379/logs/redis_6379.log dir /redis_db/
save 900 1 #900s内写入一个key时
save 300 10 #300s内写入10个key时
save 60 10000
dbfilename redis_dump.rdb dir /redis_db/
stop-writes-on-bgsave-error yes #持久化出错住进城是否停止写入 rdbcompression yes #是否压缩
rdbchecksum yes #导入时是否检查
- 加入for写入1000个 900 1 不会触发 因为写条件达到了 但是900s还没到 要等到900s dump文件才会生成
- 关于备份 向下兼容 3.x的dump5.x可以 5识别向下兼容 反之5.x的数据导入到3.x不行
AOF持久化
概念
- redis是“写后”日志,redis先执行命令,把数据写入内存,然后记录日志;类似mysql的binlog。(ps:大部分数据库是写前日志,例如mysql,通过写前日志和两端提交,实现数据和逻辑的一致性)
- 优点:安全,最多丢失1s数据,并且日志有可读性。
- 缺点:文件较大,恢复较慢。
参数
- everysec 每个命令执行完日志会写入aof文件的内存缓冲区,每隔一秒把缓冲区的日志写入到磁盘中 宕机会丢失1s内的数据
- always 每个命令执行完日志立即同步到磁盘 性能影响很大 磁盘io扛不住
![[Pasted image 20241020195008.png]]
实战
daemonize yes
bind 127.0.0.1 192.168.32.106
port 6379
pidfile /opt/redis_6379/pid/redis_6379.pid
logfile /opt/redis_6379/logs/redis_6379.log
dir /redis_db/
#rdb
save 5 1000
dbfilename redis_dump.rdb
dir /redis_db/
#aof
appendonly yes
appendfilename "redis_appendonly.aof"
appendfsync everysec
- aof在启动redis时就会生成 如果aof丢失需要rdb恢复需要conf中关闭aof
- rdb和aof结合优先用aof
AOF日志重写机制
- 每条增删都会写到aof中 文件会越来越大 比如 写入10wkey 再删除5w key 就可以只保存5w key的命令 rdb就是这样子 快照 要对aof进行日志瘦身
- 直接输入bgrewriteaof命令就行 文件大小肉眼可见的缩小 但是日志会变成二进制格式的 看不懂了 这个命令重写aof日志文件,以rdb+aof协议格式保存 也达到了日志瘦身的效果
- ![[Pasted image 20241020221300.png]]
- 上图就是bgrewriteaof后的就两行 第二行是rdb类型保存的 再写入就是aof格式的了
- 混合持久化本质上就是日志重写
混合持久化
![[Pasted image 20241020224730.png]]
aof加载流程图
aof-use-rdb-preamble yes
- 我的5.x版本默认开启 但还是建议写入到配置文件中
- 混合日志上方为rdb协议数据 下面是新写入的rdb还没来得及同步的aof可阅读日志
安全
redis标准配置文件解读
bind 127.0.0.1 与下面的port建立socket连接入口
protected-mode yes 开启安全模式
port 6379 socket连接入口
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo yes
save 900 1 ==rdb==
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
配置安全设置
改端口 密码 开启安全模式
bind 0.0.0.0 所有都能连
port 26379
requirepass zhaoxi
protected-mode yes
以指定redis用户运行
useradd -M -s /sbin/nologin redis
chown -R redis.redis /opt/redis_6379
chown -R redis.redis /usr/local/bin
chown -R redis.redis /redis_db
用systemd启动 写个systemd启动redis脚本 百度吧懒得写了
禁用危险命令
配置文件下面加下面这些 本质上就是重命名命令 让redis识别不到
rename-command flushdb asdkjhfkajsdhfuiweahnfiu
rename-command config ajkdslfhkaljsdhfkjas
eg:redis入侵攻击
- 没啥意思 大概是反序列化漏洞 利用redis的aof持久化 把key value 公钥写入到/root/.ssh/下 然后免密登录
主从复制
- redis提供了主从库模式,保证数据副本的一致,读写分离 从是只读的
- 作用:
1.数据冗余
2.故障恢复
3.负载均衡
4.高可用基石
实现:
rsync -avz /opt/redis user@slave1:/opt/redis
rsync -avz /opt/redis user@slave2:/opt/redis
#两台slave conf中添加
replicaof master_ip master_port
redis-server redis.conf
#检查
info replication
主能读写 从只能读
127.0.0.1:6379> info replication
# Replication
role:master !!!!!!
connected_slaves:2 !!!!!!
slave0:ip=192.168.32.195,port=6379,state=online,offset=154,lag=0 !!!!!
slave1:ip=192.168.32.194,port=6379,state=online,offset=154,lag=0 !!!!!!
master_replid:a932d28c553408f2be3ec37126bca90650240413
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:154
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:154
哨兵
(sentinel)
功能:
- 监控
- 自动故障转移
- 配置提供者(集群入口 类似vip)
- 通知
实战:
daemonize yes
守护进程 在后台运行
# 哨兵监听的端口号
port 26379
# 指定要监控的主节点(<master_name> 自定义名称,<master_ip> 为主节
点 IP,<master_port> 为 Redis 端口)
sentinel monitor carl 192.168.32.106 6379 2
# 指定多少毫秒之后认为主节点不可用
sentinel down-after-milliseconds carl 1000
# 哨兵判断主节点不可用之后,多少毫秒之内重新选举主节点
sentinel failover-timeout carl 1000
# 指定有多少个哨兵认为主节点失效时,执行故障转移(至少为 2 个)
sentinel parallel-syncs carl 1
< 记得删除中文 三台机器都要>
daemonize yes
port 26379
sentinel monitor carl 192.168.32.106 6379 2
sentinel down-after-milliseconds carl 1000
sentinel failover-timeout carl 10000
sentinel parallel-syncs carl 1
redis-cli -p 26379 info sentinel 查看哨兵状态 注意是26379
pkill redis-server 别干掉哨兵进程 这时候看哨兵自动切换主节点
![[Pasted image 20241022000657.png]]
- 故障转移成功
sentinel masters
sentinel slaves carl 查看slave的状态
sentinel sentinels carl 查看所有
- 哨兵会根据多个slave机器的配置高低、性能高低,ping pong的相应结果,判断出一个最优的slave 选举为新的master 实现自动的主从切换。
- 先这样吧 主要先入门 明天学集群 20241022 0:14
集群
概念
分布式存储
Redis 集群通过将数据分散存储在多个节点上,解决了单节点内存容量的瓶颈问题。集群中的每个节点负责存储一部分数据,确保系统可以水平扩展(扩展节点以增加存储容量)。
水平扩展
Redis 集群支持水平扩展,意味着你可以通过增加节点的方式,提升集群的存储能力和处理能力。随着需求的增加,集群可以动态增加节点。
数据分片(Sharding)
Redis 集群将数据分片,每个节点只负责一部分哈希槽中的数据。分片的过程通过一致性哈希算法来完成,确保数据均匀分布到各个节点。
- 哈希槽(Hash Slots):Redis 集群使用 16384 个哈希槽,每个键根据哈希值被分配到其中一个哈希槽中。
- 一致性哈希:Redis 使用
CRC16
哈希算法生成键的哈希值,并将其映射到 16384 个哈希槽之一。
高可用性与自动故障转移
Redis 集群提供高可用性,通过主从复制和故障转移实现。当主节点故障时,从节点会自动提升为主节点,继续服务请求,避免集群出现单点故障。
- 主从复制:每个主节点都有至少一个从节点作为备份,数据同步到从节点,确保数据冗余。
- 选举机制:Redis 集群中的节点通过通信检测是否有主节点出现故障,并在必要时发起选举,从节点将被选为主节点。
集群通信协议
Redis 集群节点之间使用 Gossip 协议 进行通信,每个节点定期与其他节点交换信息,检测节点状态、故障等。
- Pong 和 Ping 消息用于节点间的心跳检测,确保集群的状态一致性。
工作原理
Redis 集群节点角色
- 主节点(Master Node):存储实际数据,并处理客户端的读写请求。
- 从节点(Slave Node):复制主节点的数据,当主节点故障时,从节点可以被提升为主节点。
哈希槽分配
Redis 集群将 16384 个哈希槽分配给不同的主节点。当一个键被写入时,Redis 根据键的哈希值决定该键应该存储到哪个主节点上。
读写请求路由
- 客户端连接:Redis 集群使用智能客户端,客户端可以连接任意一个节点,并根据
MOVED
响应消息重新路由请求到正确的节点。 MOVED
响应:如果客户端向错误的节点发送请求,节点会返回MOVED
消息,并告知客户端应该访问哪个节点。
实战
搭建
cluster-enabled yes 启用集群模式。
cluster-config-file nodes.conf 保存集群节点信息。
cluster-node-timeout 5000 节点通信超时时间,单位为毫秒。
cluster-require-full-coverage yes 当部分哈希槽不可用时,是否让集群继续工作。
redis-cli --cluster create 所有参与地址 一般6个 三主三从 --cluster-replicas 1 为每个主分配1个从 0的话就是只有主
集群管理命令
CLUSTER NODES 查看集群中的节点信息。
CLUSTER INFO 获取集群状态信息,如已分配的哈希槽数量、集群状态等。
CLUSTER MEET <IP> <port> 手动将一个新节点加入集群。
CLUSTER FAILOVER 手动将从节点提升为主节点。
数据操作与分布
Redis 集群中的键值操作(如 SET
和 GET
)会根据哈希槽分布到不同的节点上。客户端在执行操作时,不需要关心具体的节点分布,集群会自动路由请求。
例子:
redis-cli -c -p 7000
SET key1 "value1" # 自动分配到对应哈希槽
GET key1 # 通过路由找到存储 key1 的节点
集群的动态扩展
- 添加节点:使用
redis-cli --cluster add-node
添加新的节点到集群中,然后使用rebalance
命令重新分配哈希槽。 - 移除节点:使用
redis-cli --cluster del-node
命令移除集群中的某个节点,确保数据在移除前已经被迁移到其他节点。
故障处理与恢复
- 节点故障:当主节点发生故障时,集群会自动将从节点提升为主节点,继续处理请求。
- 手动恢复:如果某个节点长时间不可用,可以通过重新加入节点或手动迁移数据的方式恢复。
监控 Redis 集群
- 使用
redis-cli --cluster info
查看集群的状态,如节点健康状态、哈希槽分配情况等。 - 使用 Redis 集群的日志和监控工具(如
Redis Sentinel
或外部工具如Prometheus
和Grafana
)监控性能和故障情况。
实战案例:REDIS 集群动态扩容
假设现有 Redis 集群已经部署完毕,包含 3 个主节点和 3 个从节点。我们将添加一个新节点到集群,并重新分配哈希槽。
- 步骤 1:启动新节点
redis-server /path/to/redis-7006.conf - 步骤 2:将新节点添加到集群
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 - 步骤 3:重新分配哈希槽
redis-cli --cluster reshard 127.0.0.1:7000 - 步骤 4:验证新节点的哈希槽分布
redis-cli -c -p 7006
cluster nodes
- -c是客户端连接集群要加的参数 --cluster是要管理集群加的参数