简单聊一下Redis
一、Redis概念
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
简单来讲,它是一个非关系型数据库,不会像mysql那样存储关系性极强的数据。
二、Redis持久化
它这个过程类似于session的钝化,钝化是指将session信息存至磁盘中,而Redis的持久化是指将内存数据持久化到硬盘,用持久化文件来恢复数据库数据的功能。
因为不管是哪种数据库,都会有一种数据丢失的可能,Redis的数据是存在内存中的,一旦断电或者宕机,则数据就会丢失,所以Redis有两种形式的持久化,一种是RDB快照(snapshotting),另外一种是AOF(append only-file)。
1.RDB持久化(快照,注重结果,无缓存区)
快照持久化是 Redis 默认采用的持久化方式
手动持久化
save:
1)修改配置文件
daemonize yes
bind 0.0.0.0
port 6380
logfile "6380.log"
dir /usr/local/redis-4.0.11/data/
dbfilename dump-6380.rdb
rdbcompression yes
rdbchecksum no
2)分别开启服务端和客户端后
服务端:
[root@centos-Dubbo ~]# cd /usr/local/redis-4.0.11/src/
[root@centos-Dubbo src]# ./redis-server /usr/local/redis-4.0.11/conf/redis-6380.conf
客户端:
[root@centos-Dubbo ~]# cd /usr/local/redis-4.0.11/src/
[root@centos-Dubbo src]# ./redis-cli -p 6380
127.0.0.1:6380> keys *
(empty list or set)
127.0.0.1:6380> set id 1
OK
127.0.0.1:6380> set username zs
OK
127.0.0.1:6380> set pwd 123456
OK
127.0.0.1:6380> save
OK
此时去到 /usr/local/redis-4.0.11/data/这个目录下
发现生成了三个文件
点开rdb文件
这是经过了一些特殊处理的,但是隐约可以看到username等字段。
bgsave:
删除之前三个文件后,重新测试
127.0.0.1:6380> del username id pwd
(integer) 3
127.0.0.1:6380> keys *
(empty list or set)
127.0.0.1:6380> set id 2
OK
127.0.0.1:6380> set username ls
OK
127.0.0.1:6380> set pwd 123
OK
127.0.0.1:6380> bgsave
Background saving started
两者的区别:save是单线程处理任务,消耗性能小,会阻塞线程,而bgsave服务端会开一个子进程去处理任务,不会阻塞线程但是消耗性能大。
自动持久化
一般我们不会直接用save/bgsave命令生成RDB文件的,Redis支持自动触发RDB持久化机制,配置都在redis.conf文件里面。
1)修改配置文件
daemonize no
bind 0.0.0.0
port 6380
logfile "6380.log"
dir /usr/local/redis-4.0.11/data/
dbfilename dump-6380.rdb
rdbcompression yes
rdbchecksum no
save 5 2
客户端输入命令
127.0.0.1:6380> flushall
OK
127.0.0.1:6380> keys *
(empty list or set)
127.0.0.1:6380> set id 1
OK
127.0.0.1:6380> set id 2
OK
127.0.0.1:6380> set id 1
OK
127.0.0.1:6380> set id2 2
OK
127.0.0.1:6380> set id3 3
OK
127.0.0.1:6380> set id4 4
OK
127.0.0.1:6380> set id5 5
OK
127.0.0.1:6380> shutdown save
shutdown save:关闭服务器并保存指定数据
2.AOF持久化(日志,注重过程,有缓冲区,更消耗性能)
写命令会被记录到日志中,读命令不会被存储到日志中,因为不会更改数据。
两者不兼容,开始aof就必须吧rdb关掉,redis默认持久化方式为rdb。
三种策略
- everysec
- no(系统控制,不推荐)
- always
- 修改配置文件(删除之前的日志文件)
daemonize no bind 0.0.0.0 port 6380 logfile "6380.log" dir /usr/local/redis-4.0.11/data/ appendonly yes --启动aof appendfsync everysec --启用每秒钟写入 appendfilename appendonly-6380.aof --文件名称
- 客户端测试
[root@centos-Dubbo src]# ./redis-cli -p 6380 127.0.0.1:6380> keys * (empty list or set) 127.0.0.1:6380> set id 2023 OK 127.0.0.1:6380> set name zs OK 127.0.0.1:6380> get id "2023" 127.0.0.1:6380> get name "zs" 127.0.0.1:6380> keys * 1) "name" 2) "id"
只有set命令,没有get命令
AOF重写机制
重复写入的话只会保存最后一个数据
手动重写
停止两台服务器并重写启动,删除原有的日志文件
[root@centos-Dubbo src]# ./redis-cli -p 6380
127.0.0.1:6380> clear
127.0.0.1:6380> set age 20
OK
127.0.0.1:6380> set age 30
OK
127.0.0.1:6380> set age 40
OK
127.0.0.1:6380> set age 50
OK
127.0.0.1:6380> bgwriteaof
(error) ERR unknown command `bgwriteaof`, with args beginning with:
127.0.0.1:6380> bgrewriteaof
Background append only file rewriting started
自动重写
修改配置文件
daemonize no
bind 0.0.0.0
port 6380
logfile "6380.log"
dir /usr/local/redis-4.0.11/data/
#dbfilename dump-6380.rdb
#rdbcompression yes
#rdbchecksum no
#save 5 2
appendonly yes
appendfsync everysec
appendfilename appendonly-6380.aof
auto-aof-rewrite-min-size 1 #单位M
3.总结
RDB的优点:
1)RDB内部存储的是Redis在某个时间点的数据快照,非常适合用于【数据】的【全量备份】。
2)RDB是基于数据快照的理念设计的,每一个rdb文件都是一个【已经压缩过的二进制文件】,存储效率较高。
3)由于RDB是将数据全部存储在rdb文件中,即【每个rdb文件都是原始数据】,在恢复【大数据集】时的速度比AOF的恢复速度要快的多。
RDB的缺点:
1)RDB每次拍摄数据快照需要将此次数据快照的所有数据都写入rdb文件,如果频率过高,那么性能势必大大下降。因此RDB无法做到实时持久化(或者换一个方式说,RDB不适合做实时的持久化)。
2)RDB持久化方式并没有缓冲区的概念,如果rdb的进程正在将数据写入到rdb文件,会导致数据库的数据和rdb文件中保存的数据不一致。
3)Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象。
AOF的优点
1)AOF是基于日志形式的理念设计的,AOF将每一个【操作指令的步骤】以日志的方式记录下来,因此同步的频率相对RDB来说可以非常的频繁。AOF适用于数据【实时】同步要求较高的场合。
2)AOF具有【重写机制】,可以有效的整理不必要的指令来压缩aof文件的大小,提升数据恢复的性能。
3)AOF文件【有序】地保存了对数据库执行的所有【写入】操作,这些写入命令被Redis保存到了aof文件上,这些指令让人可以轻松阅读,并且文件易于解析,当你中途不小心执行了flushall 指令,只要aof文件没有被重写,此时【可以编辑aof文件删除 flushall 指令,来恢复数据】
AOF的缺点
对于同等的数据量,AOF 文件的体积通常要大于 RDB 文件的体积。
由于AOF文件保存的是操作的命令,因此恢复起来速度要比RDB慢。
三、Redis的订阅和发布
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
【发布者】并不是直接发送它们的消息给指定的【订阅者】,而是将消息发布到特定的【消息通道】,并且不需要知道订阅者的任何信息。
订阅者可以订阅一个或多个感兴趣的消息通道,同时也只会收到他们感兴趣通道的信息,而不用去关心是谁发布的。
这种发布者与订阅者的【解耦】,使其具备更强的扩展性并得到一个更加动态的网络拓扑。
```
订阅所有以a结尾的频道
例子:psubscribe *a
四、Redis的事务(不常用)
Redis的事务没有隔离级别的概念,也就不存在脏读、不可重复读、幻读等等情况。
Redis在开启事务时,之后执行的所有的操作均会保存到事务队列中。如果执行了 exec 命令,那么Redis将会逐步执行队列中的指令,如果执行 discard 指令,那么将会取消队列中的所有指令。
multi ---开启事务
exec --执行事务
discard ---取消事务
五、Redis分布式锁
在分布式环境下,想要实现多个服务(多个进程)操作同一资源时,保证数据的一致性。可以使用Redis来实现分布式锁。
setnx命令用于在Redis键中设置某些字符串值
如果键成功设置则返回 1 。
如果键未设置则返回 0 。
命令:setnx key value
例子:setnx ticket_lock 1
自动删除:
Redis实现分布式锁解决方案改良版,添加锁的有效时间
命令:expire lock-key second
例子:expire ticket_lock 5
手动删除:
del lock-key(不推荐)
六、Redis中key的三种删除政策
我们知道Redis中的数据都是存储在内存中的,内存空间非常宝贵,当我们对不需使用的数据应该立即删除,我们知道可以使用ttl命令查看数据的过期时间,也可以使用del命令来删除某个key,但是Redis中的数据过期就真的清除了吗???使用del删除的数据就真的删除了吗???
比如数据库执行delete语句时候,只是在语句中加了个is_delete字段,隐藏了这条记录而已,那redis的删除会是一个怎样的情况呢?
在Redis中,【expire设置过期时间】、【del删除】的操作,有三种策略从内存中清除。
1.定时删除
当key设置过期时间的时候,创建一个定时器事件,当key过期时间到达时,由定时器任务立即执行对key的删除操作。
- 优点:节约内存,到时就删除,快速释放掉不必要的内存占用。
- 缺点:CPU压力大,无论CPU此时负载量多高,都会去占用CPU进行key的删除操作,会影响Redis服务器响应时间和吞吐量,是一种比较低效的方式。
2.惰性删除
数据到达过期时间不删除,等下次访问该数据时再删除。
对于过期的key不作任何处理,当获取key时检查key是否过期,过期就删除,否则直接返回。
- 优点:删除key操作只在取出key时发生,只删除当前key,占用CPU少。
- 缺点:当大量key超出过期时间后未被使用,会占用大量内存。
3.定期删除(随机抽取一部分key删除)
定期删除=定期删除+惰性删除
这是一种折中的策略,它结合了上述两种策略的特点。
Redis会周期性轮询Redis库中的时效性数据,采取随机抽取的策略,利用过期数据占比的方式控制删除频度。
这种策略既避免了占用大量CPU资源又避免了出现大量过期键不被清除占用内存的情况。
总结
- 定时删除(对内存清除最有效)
- 不管CPU当前使用率是否紧张,时间到了立马删除,内存压力小,CPU压力大,采用时间换空间策略
- 惰性删除(等到二次访问再删除)
- 等到确切删除的时候再删除,造成内存使用量浪费,CPU压力小,采用空间换时间策略
- 定期删除(采取智能抽取检查)
- 周期性删除,随机抽取一部分key删除,如发现占整体key的比例较大,则重新抽取一部分key删除。之后轮询下一个数据、下一台Redis…
七、Redis主从复制结构
1.概述
实际项目中,一台 Redis 服务器无法阻挡大规模用户访问,往往需要配置【集群】。那问题来了。
如果A用户第一次访问【存】数据到192.168.1.1这台 Redis 服务器中,那么A用户第二次访问时,不一定会访问192.168.1.1这台 Redis 服务器,如何让其它 Redis 服务器保持数据同步呢?
也就是多台服务器数据不一致的问题。
搭建Redis主从复制架构
2.演示
准备主服务器的配置文件
daemonize no
port 6379
dir "/usr/local/redis-4.0.11/data"
appendonly yes
appendfsync everysec
appendfilename "appendonly-6379.aof"
auto-aof-rewrite-min-size 1
准备从服务器的配置文件
daemonize no
port 6380
dir "/usr/local/redis-4.0.11/data"
appendonly yes
appendfsync everysec
appendfilename "appendonly-6380.aof"
auto-aof-rewrite-min-size 1
准备四个窗口
启动主服务器:
cd /usr/local/redis-4.0.11/src/
./redis-server /usr/local/redis-4.0.11/config/redis-6379-master.conf
启动从服务器
cd /usr/local/redis-4.0.11/src/
./redis-server /usr/local/redis-4.0.11/config/redis-6380-slave.conf
开启6379客户端
./redis-cli -p 6379
开启6380客户端
./redis-cli -p 6380
连接主服务器
salveof localhost 6379
断开服务器
slaveof no one