1. redis网站
Redis
Redis文档中心 -- Redis中国用户组(CRUG)
数据库排名网站:DB-Engines - Knowledge Base of Relational and NoSQL Database Management Systems
2. 基础知识
磁盘中的寻址速度是毫秒级,内存中寻址速度是纳秒级,在寻址上,磁盘比内存慢了10w倍
磁盘中,每个扇区是512字节
无论你读多少,操作系统都是最少从磁盘中拿4k
文件变大,磁盘io会成为瓶颈
数据库中有data page,大小是4k,和磁盘的读取大小一致
带宽:数据传输能力的大小
因为磁盘存储检索速度会变慢,内存存储价格比较昂贵,所以出现了缓存的概念,把少量数据存储在缓存中
3. 安装
1)下载
先去官网找到要下载的版本,例如:https://download.redis.io/releases/redis-6.2.7.tar.gz
然后通过wget下载(也可以直接下载)
解压redis安装包
tar -xf redis-6.2.7.tar.gz
进入解压后的文件夹,其中有个README.md文件,可以查看这个文件进行操作
2)编译
make
3)启动
执行src目录下的./redis-server命令,启动redis
./src/redis-server
安装redis到执行目录下
make install PREFIX=/root/redis/redis6
4)配置文件
在/tec/profile文件中,加redis_home
vim /etc/profile
export REDIS_HOME=/opt/redis/redis6
export PATH=$PATH:$REDIS_HOME/bin
重新加载配置文件
source /etc/profile
这样,在任意位置都可以执行redis的命令了
5)添加实例
执行安装目录的utils目录下的install_server命令
./utils/install_server.sh
会出现端口号、文件地址、日志地址让选择,直接回车表示默认
查看redis的状态(redis_6379 可以在/etc/init.d目录中查看)
service redis_6379 status
如果执行发生如下报错,
注释掉 install_server.sh中的相关代码
也可以继续在utils目录下执行install_server命令,启动更多的redis进程(实例)
6)连接redis
到安装路径下的bin目录中,执行
./redis-cli
4. redis相关小知识
redis是单进程、单线程、单实例的
epoll是Linux内核为处理大批量句柄而作了改进的poll
redis-cli:进入redis
redis-cli -h:查看帮助
redis默认有16个库
flushdb、flushall命令可以清库
help @String 查看string相关的命令
redis可以实现发布订阅功能:publish、subscribe
redis可以安装布隆过滤器的插件
5. IO
1.bio:同步阻塞io,read,write系统调用会阻塞,因此需要很多线程处理
2.nio:非阻塞io,同步非阻塞,但是需要循环多次进行系统调用read
3.同步非阻塞:select一次检测多个,循环read,但是需要在内核空间和用户空间来回拷贝
4.epoll:多路复用nio,依然是同步非阻塞io,因为虽然等待事件发生,但是依然需要自己调用read系统调用读取数据,先调用create创建一个注册器,ctl.add,del从注册器上新增或删除连接,wait等待连接产生事件,每次新链接绑定到注册器上,一次系统调用得到需要处理的socket,然后再循环处理有数据读写的socket连接
5.linux没有aio,windows的aio,read调用扔一个buffer到内核空间,内核读取数据到bugffer,完毕后通知用户线程进行操作
6. setNx和setXx
nx:不存在添加
xx:存在才能更新
7. 正反索引
正向的是 0、1、2...
反向的是-1、-2、-3...
8. 二进制安全
redis为了二进制安全,取的是字节流,
计算时,把字节流转换成数字
9. String
string:可以存字符串、数值、bitmap
bitmap的操作:setbit、bitcount、bitpos、bitop
10. List
list:链表,可以当做堆(同向操作)、队列(反向操作)、数组(lindex)、阻塞队列(BLPOP)
ltrim:删除队列两端的数据
11. Set
set可以做交并差集合操作
srandmember key count命令可以产生随机的列表(count是整数去重,负数不去重),可以用于抽奖
12. ZSet
zset:有序的,不可重复的;物理内存左小右大
可以进行交集、并集的集合操作(可以设置权重和聚合操作)
用skipList进行存储
13. 事务
multi:开启事务
discard:取消事务
exec:执行事务
watch:监控事务,如果监控的值被修改,事务不执行
先发送exec命令的先执行
通过管道实现事务
管道:将多个命令一次发送给服务器,降低通信成本
14. 缓存淘汰策略
redis可以设置内存大小,内存满了以后,执行淘汰策略
LRU:最久使用
LFU: 最少使用
15. 过期时间
过期时间不会随着使用延长;
如果重新写值,并且没有给定过期时间,过期时间为-1(没有过期时间)
redis的key也可以定时过期
16. redis淘汰过期key
17. 管道
Linux中,| 是管道的意思,
作为衔接,前一个命令的输出作为后一个命令的输入
管道会触发创建子进程
父进程可以让子进程看到数据(export)
子进程的修改不会破坏父进程
父进程的修改也不会破坏子进程
18. RDB
RDB,通过fork创建子进程并拷贝副本,来将数据写入磁盘,写入的是时点数据;父进程对数据进行修改,子进程看不到父进程的修改;
父子进程的数据是隔离的
save:手动rdb
bgsave:在后台通过fork进行rdb
也可以在配置文件中设置rdb的时间
弊端:不是实时记录数据变化,可能会导致数据丢失
优点:恢复速度较快
19. AOF
缺点:体量大,恢复慢
优点:数据相对完整
4.0以前,会对aof日志进行重写,抵消部分日志,合并部分日志
4.0以后,会将rdb文件写到aof前面,将增量的操作以指令的方式写在后面
20. AKF
X: 增加副本,可以节点单点故障,读写分离
Y: 按照功能业务划分成多个进程
Z: 按照优先级、逻辑再拆分
21. 集群
强一致性可能会破坏可用性
主从:客户端可以访问主,也可以访问从
主备:客户端只访问主,当主挂了以后,备当主
集群一般使用奇数台,节省资源
replicaof:可以追随某个主节点,自己当从节点
redis通过哨兵和自动分区提供高可用
22. 哨兵,Sentinel
用于监控、提醒、自动故障转移
每个哨兵只知道主节点信息,通过发布订阅知道其他哨兵信息
23. 新增redis实例
新增redis实例可以解决数据量大的问题
可以根据业务或者逻辑来区分数据存放哪个redis,但是如果数据已经不能通过业务逻辑来区分的话
可以用hash+取模来决定数据放在哪个redis实例上,但是如果要增加redis实例的话,这种方式需要把所有数据重新算一下,再次存放
可以用一致性哈希算法,根据redis实例和数据来构成哈希环来解决所有数据都需要重新算的问题,但是这种,新增redis实例,会导致部分数据查询不到
也可以通过代理层来解决访问redis实例
可以参考github中的twemproxy
也可以通过预分区的概念来选择访问redis实例(每个节点分几个hash值)
redis的cluster模式就是选用这种预分区的模式来进行redis实例选择,客户端先访问一个redis实例,然后进行hash计算,并且redis实例中有维护其他redis实例hash对应实例表,这样就可以返回这个key对应的是哪台redis实例。然后客户端再去访问对应的客户端
redis的连接成本很高,可以用nginx来解决
数据分布在不同的redis实例上以后,聚合操作、事务很难实现。可以人为的设置相同的前缀,然后用前缀来进行hash计算, {xx}k1,来实现需要进行聚合、事务操作的数据放进同一个redis实例上
24. 击穿
某个热点key过期,导致大量请求到了数据库
解决方案:
1. 设置热点key永不过期
2. 大量请求使用setnx分布式锁,只有获得锁的才能去请求数据库,并且将结果写入redis中,这样其他请求直接访问redis就好了
25. 穿透
大量请求某个不存在的key
解决方案:
1. 将不存在的key写入redis中,值为null
2. 使用布隆过滤器,也可以使用布谷鸟(支持删除的布隆过滤器)
26. 雪崩
大量热点key过期,导致大量请求到了数据库
解决方案:
1. 如果过期时间不是必须是相同的,可以设置随机的过期时间
2. 其他解决方案同击穿
27. 分布式锁
可以用setnx做分布式锁,但是
1. 如果加锁部分执行有问题,一直不释放锁怎么办
2. 加过期时间,过期时间设置多久合适,设置太短会导致业务代码没有执行完,锁就释放了,设置太长可能会导致阻塞住了
3. 使用多线程来监控加锁代码什么时候执行完,这样会增加代码复杂度
28. redis常用的客户端
Jedis:线程不安全
Lettuce:RedisClient ;线程安全的,可以同步
RedisTemplate:StringRedisTemplate可以解决key序列化问题
springboot整合redis时,需要对key和value进行序列化