Redis 学习笔记
- 什么是Redis
redis 是Remote Dictionary Server(远程数据服务)的缩写,由意大利人——antirez(Salvatore Sanfilippo)开发的一款内存高速缓存数据库,该软件使用C 语言编写,它的数据模型为key-value 键值对的形式。它支持丰富的数据结构(类型),比如String、list、hash、set、sorted set。可持久化,保证了数据安全(不容易丢失)。
一、缓存:使用缓存减轻数据库的负载
1、应用场景:在开发网站的时候如果有一些数据在短时间内不会发生变化,而他们还要被频繁访问,为了提高用户的请求速度和降低网站的负载,就把这些数据放到一个读取速度更快的介质上(或者是通过较少的计算量就可以获得该数据),该行为就称为对该数据的缓存。该介质可以是文件、数据库、内存(常用于做数据缓存)。
2、缓存形式:
①数据缓存:经常会用在页面的具体数据里边
②页面缓存(smarty):经常会用在CMS(content manage system) 内存管理系统里边
-
redis 和 memcahce 比较
①redis 不仅仅支持简单的key/value 类型的数据,同时还提供 list、set、zset、hash 等数据结构的存储。
②redis 支持数据的备份,即master-slave(主——从)模式的数据备份
③redis 支持数据的持久化,可以将内存中的数据异步保存在磁盘中,重启的时候可以再次加载进行使用
④redis 单个value 的最大限制是1 GB,memcache 只能保存1M 的数据。 -
Redis 的CAP 原理
① 一致性(consistency):
② 可用性(availability):
③ 分区容错性(partition tolerance):
CAP 理论核心:一个分布式系统不可能同时很好的兼容一致性、可用性和分区容错性这三个需要,最多只能同时良好的满足两个。因此,根据CAP 原理将NoSQL 数据库分成了满足 CA 原则、CP 原则和AP 原则这三大类:
1、CA:单点集群,满足强一致性,可用性的系统,通常在可扩展性上不太强大(传统关系型数据库:MySQL、SQL server、oracle)
2、CP:满足一致性,分区容忍性的系统,通常性能不是很高
3、AP:满足可用性,分区容忍性的系统,通常可能对一致性要求低一些(非关系型数据库:redis、memcaceh、MongoDB)
- Redis 零碎知识介绍
1、单进程
——单进程模型来处理客户端的请求,对读写等事件的响应是通过对epoll 函数的包装来做到的,Redis 的实际处理速度完全依赖主进程的执行效率
——epoll 是Linux 内核为处理大批量文件描述符而作了改进的epoll,是Linux 系统下多路复用IO 接口select/poll 的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU 利用效率
2、数据库数:Redis 默认情况下有16个数据库,类似于数组下标从0 开始,初始默认使用零号库
3、Select 命令切换数据库
4、Ddsize:查看当前数据库的key 数量
5、Flushdb:清空当前库
6、Flushall:清空全部库
7、统一密码管理,16个库都是使用同样的密码,要么都ok,要么都连不上
8、Redis 索引都是从0 开始的
9、Redis 的默认端口号:6379
- Redis 常用的五大数据类型
① String(字符串):可以是字符串或数字(整型、浮点型)
② Hash(哈希):类似java 里的Map,一个对象里面有许多对键值对
③ List(链表):可以存储多个字符串,有顺序,而且可以双向存储
④ Set(集合):采用hash 表结构存储,不可重复,无顺序,每个元素的都是字符串
⑤ Zset(sorted set:有序集合):采用hash 表结构存储,有顺序(通过元素中的一个浮点数进行排序),元素不可重复(元素中的浮点数可以重复)
数据类型 | 应用场景 |
---|---|
String | 比如说,我想知道什么时候封锁一个IP地址。可以采用Incrby命令 自增value的值 |
Hash | 存用户信息【id, name, age】 |
List | 实现最新消息的排行,还可以利用List 的push 命令,将任务存在list 集合中,同时使用另一个命令,将任务从集合中取出来【pop】。Redis-list 数据类型来模拟消息队列。【电商中的秒杀活动就可以采用这种方式实现】 |
Set | 特殊之处:可以自动排重。比如说微博中将每个人的好友存在集合(Set)中,这样求两个人的共同好友的操作时候,我们只需要求出集合的交集即可 |
Zset | 以某一个条件为权重,进行排序。京东:商品详情的时候,都会有一个综合排名,还可以按照价格进行排序 |
Redis 键(key)操作命令:
#案例1:查看当前库中所有的key
——keys *;
#案例2:判断key=k1 的键是否存在
——exists k1;
#案例3:把key=k1 的键移到4 号库中
——move k1 4
#案例5:给key=k3 的键设置20秒的过期时间
——expire k3 20
#案例6:查看key=k3 的键的存活时间
#案例7:查看key=k3 的键的数据类型
——type k3
1、String(字符串)
——string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。
——string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
——string类型是Redis最基本的数据类型,一个redis中字符串value最多可以是512M
操作指令:
#案例1:在当前库设置一个String类型的key/value 数据
——set k1 chaoyou
——set k2 123
#案例2:在当前库中获取指定key 的数据
——get k1 ##"chaoyou"
#案例3:在当前库中删除指定key 的数据
——del k1
#案例4:在当前库中给指定的key 拼接数据
——append k1 abc ##"chaoyouabc"
#案例5:在当前库中查看指定key 的数据长度
——strlen k1 ##10
#案例6:在当前库中给指定key 的数据自增1
——incr k2 ##"124"
#案例7:在当前库中给指定key 的数据自减1
——decr k2 ##"123"
#案例8:在当前库中给指定key 的数据自增指定的步长数(3)
——incrby k2 3 ##"126"
#案例9:在当前库中给指定key 的数据自减指定的步长数(3)
——decrby k2 3 ##"123"
#案例10:在当前库中给指定key 的数据中截取指定范围(index:2~4)的数据
——getrange k1 2 4 ##"aoy"
#案例11:在当前库中给指定key 的数据中设置指定范围(起始位:2)的数据
——setrange k1 2 123 ##"ch123ou"
#案例12:在当前库中给指定key 的数据设置存活时间(秒),并动态设置value
——setex k1 10 xiaojiuwo ##"xiaojiuwo"(存活时间内的值,过后该key/value 被回收)
#案例13:在当前库设置一个String类型的key/value 数据,并且在创建前先判断该key 是否存在,若存在则不创建(set if not exist)
——setnx k6 xiaojiuwo ##"ch123ou"
——setnx k7 xiaojiuwo ##"xiaojiuwo"
#案例14:在当前库中同时设置多对String 类型的key/value 数据
——mset k8 asdf k9 zxcv k10 qwer
#案例15:在当前库中同时获取多个指定key 的数据
——mget k8 k9 k10 ##"asdf"、"zxcv"、"qwer"
#案例16:在当前库设置多个String类型的key/value 数据,并且在创建前先判断这些key 是否存在,若存在则不创建(set if not exist)
——msetnx k8 asdf k9 zxcv k10 qwer
#案例17:在当前库设置一个String类型的key/value 数据,并且返回该key 的旧值
——getset k8 123456 ##"asdf"
2、Hash(哈希)
——Redis hash 是一个键值对集合。
——Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
——类似Java里面的Map<String,Object>
操作指令:
#案例1:删除hash 结构中的某个【些】字段
——hdel key field1【field2......】
#案例2:判断hash 结构中是否存在field 字段
——hexists key field
#案例3:获取所有hash 结构中的键值
——hgetall key
#案例4:指定给hash 结构中的某个字段加上一个整数
——hincrby key field increment
#案例5:指定给hash 结构中的某个字段加上一个浮点数
——hincrbyfloat key field increment
#案例6:返回hash 中的所有键
——hkeys key
#案例7:返回hash 中键值对的长度
——hlen key
#案例8:返回hash 中指定的键的值,可以是多个
——hmget key field1【field2.......】
#案例9:hash 结构设置多个键值对
——hmset key field1 value1 【field2 value2 ........】
#案例10:在hash 结构中设置键值对
——hset key field value
#案例11:当hash 结构中不存在对应的键,才设置值
——hsetnx key field value
#案例12:获取hash 结构中所有的值
——hvals key
3、List(链表:查询慢,增、删快)
——Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。
——它的底层实际是个链表(类似于java 的 LinkedLIst)
操作指令:
#案例1:在当前库中创建一个List 类型的key/value数据
——lpush list01 1 2 3 4 5 6(左边的数据先入列表)
——rpush list02 1 2 3 4 5 6(右边的数据先入列表)
——lpush list03 1 1 1 2 2 2 3 3 3 3 4 4 4
#案例2:在当前库中遍历指定key 的列表数据
——lrange list01 0 -1(全列表遍历)
——lrange list02 2 4(遍历index:2~4的数据)
#案例3:在当前库中在指定key 的列表中推出一个数据(出栈)
——lpop list01(从list01 列表的左边推出一个数据) ##"6"
——rpop list01(从list01 列表的右边推出一个数据) ##"1"
#案例4:在当前库中指定key 的列表中,按指定的索引下标获取值
——lindex list01 2 ##"3"
#案例5:在当前库中获取指定key 的数据长度
——llen list01 ##5
#案例6:在当前库中指定key 的列表中,删除指定值个数,并返回删除的个数
——lrem list03 2 3 ##2
#案例7:在当前库中指定key 的列表中,截取指定范围的数据在赋值给该key
——ltrim list01 2 4 ##2、3、4
#案例8:在当前库中指定key 的列表中,把第一个列表的最后一个数据截取出来,并放到第二个列表的首部
——rpoplpush list01(1 2 3 4 5)list02(3 4 5 6) ##5 3 4 5 6
#案例9:在当前库中指定key 的列表中,按指定的索引下标设置值
——lset list01(1 2 3 4 5 6) 2 a ##1 2 a 4 5 6
#案例10:在当前库中指定key 的列表中,在指定数据的前后插入值
——linsert list01(1 2 a 4 5 6) before a java ##1 2 java a 4 5 6
——linsert list01(1 2 a 4 5 6) after a mysql ##1 2 a after 4 5 6
性能总结:
它是一个字符串链表,left、right都可以插入添加;
如果键不存在,创建新的链表;
如果键已存在,新增内容;
如果值全移除,对应的键也就消失了。
链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了。
4、Set(集合)
——Redis的Set是string类型的无序集合。它是通过HashTable实现实现的,
操作指令:
#案例1:给键为key 的集合增加成员
——sadd key member1 【member2 ........】
#案例2:统计键为key 的集合成员数
——scard key
#案例3:找出两个集合的差集
——sdiff key1 [key2]
#案例4:先按sdiff 命令的规则,找出key1 和 key2 两个集合的差集,然后将其保存到des 集合中
——sdiffstore des key1 [key2]
#案例5:求key1 和key2 两个集合的交集
——sinter key1 [key2]
#案例6:先按sinter 命令的规则,找出key1 和key2 两个集合的交集,然后保存到des 中
——sinterstore des key1 [key2]
#案例7:判断 member 是否键为key 的集合的成员
——sismember key member
#案例8:返回集合所有成员
——smembers key
#案例9:将成员member 从集合src 迁移到集合des 中
smove src des member
#案例10:随机弹出集合的一个元素
——spop key
#案例11:随机返回集合中一个或者多个元素,count 为限制返回总数,如果count 为负数,则先求其绝对值
srandmember key [count]
#案例12:移除集合中的元素,可以是多个
——srem key member1 【member2 .......】
#案例13:求两个集合的并集
——sunion key1 [key2]
#案例14:先执行sunion 命令求出并集,然后保存到键为des 的集合中
——sunionstore des key1 key2
5、zset(sorted set:有序集合)
——Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
——不同的是每个元素都会关联一个double类型的分数。
——redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。
- Redis 持久化
1)、RDB(Redis DataBase)——在指定的时间间隔内将内存中的数据集快照写入磁盘,
也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。(备份、恢复都快)
含义:Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到
一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。
整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能
如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感、数据精度不高,那RDB方
式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
fork:fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程
2、AOF(Append Only File)——以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
1、RDB——快照(snapshotting),备份当前瞬间Redis 在内存中的数据记录
优点:恢复重启是比较快速的,只要把之前备份好的快照复制过来,然后重新启动Redis 系统会自动恢复数据
缺点:当Redis 需要备份的数据量很大的时候,启用快照备份可能会造成Redis 系统的卡顿,这是因为在备份快照的时候主进程要fork 出一个与自己一样的副本作为自己的子进程,而这一过程需要时间,在备份快照期间如果出现意外会造成最后一次快照的所有修改。
启动快照的三个条件:
① save 900 1 ##当在900秒内执行过1次写命令时,启用快照备份
② save 300 10 ##当在300秒内执行过10次写命令时,启用快照备份
③ save 60 10000 ##当在60秒内执行过10000次写命令时,启用快照备份
禁用快照:
① save '' ##只要不设置任何save指令,或者给save传入一个空字符串参数也可以
bgsave命令(stop-writes-on-bgsave-error yes/no):bgsave,它是一个异步保存命令,也就是系统将启动另一个进程,把Redis 的数据保存到对应的数据文件中,它和save 命令最大的不同是它不会造成阻塞用户端的写入,就是在执行bgsave 命令的时候,允许客户端继续读/写操作。在默认的情况下,如果Redis 执行bgsave 失败后,Redis 将停止接受写操作,这样是为了让用户知道系统出现了问题,如果后台保存进程重新启动工作了,Redis 也将自动允许写操作。
Redis配置文件中AOF 的配置:
①# 这里是是否在备份存到磁盘的时候启用压缩功能节约CPU资源
——rdbcompression yes
②# 10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能
—— rdbchecksum yes
③# 设置快照备份保存的文件,也是数据恢复时的文件
——dbfilename dump.rdb
2、AOP——追加文件(Append-Only-File),在一定的触发条件下将Redis 执行过的写指令依次保存到Redis 的【appendonly.aof】文件中。
优点:它只是追加写入指令,所以一般不会造成Redis 卡顿
缺点:在Redis 需要恢复数据的时候需要把【appendonly.aof】文件中之前执行的写指令在重新执行一遍来达到恢复数据的目的,因为AOF 是追加写命令备份,所以【appendonly.aof】文件会很大,执行很慢。
AOF启动/修复/恢复:
①正常恢复:
去Redis 配置文件中把appendonly no,改为yes
将有数据的aof文件复制一份保存到对应目录(config get dir)
恢复:重启redis然后重新加载
②异常恢复:
去Redis 配置文件中把appendonly no,改为yes
备份被写坏的AOF文件
redis-check-aof --fix进行修复(去掉不符合语法的语句)
恢复:重启redis然后重新加载
AOF文件的rewrite:
①AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,
只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof
②AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),
遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
③Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于 64M时触发
Redis配置文件中AOF 的配置
①# 设置AOF 追加写命令备份
——appendonly no
②# 设置追加写命令备份的文件
——appendfilename "appendonly.aof"
③# 设置AOF 追加写命令备份的策略
——appendfsync always ##与Redis执行写命令同步进行追加写命令备份(安全性强,性能弱)
——appendfsync everysec(默认) ##设置每秒钟对Redis 的写命令进行追加备份,出现意外会丢失最后一秒的写命令追加备份(安全性、性能均良好)
——appendfsync no ##自定义对Redis 的写命令进行追加备份(安全性弱,性能强)
④# 是否允许在特定追加写命令备份期间进行读/写操作
——no-appendfsync-on-rewrite no
⑤# 设置触发重写AOF 文件的条件,100 表示为上一次重写文件的100%
——auto-aof-rewrite-percentage 100
⑥# 设置触发重写AOF 文件的条件,重写文件必须大于64MB
——auto-aof-rewrite-min-size 64mb
⑦# 设置Redis 启用AOF 文件恢复数据的时候自动忽略最后一条可能存在问题的指令
——aof-load-truncated yes
3、RDB 和 AOF 并存
Redis 的执行策略:在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,
因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
备份方式 | 备份文件 | 备份速度 | 恢复速度 | 安全性/完整性 | 系统优先选择 | |
---|---|---|---|---|---|---|
RDB | 快照 | dump.rdb | 要fork子进程要——慢 | 直接用fork的子进程恢复——快 | 会造成最后一次的快照备份失败——低 | 备份数据不实时——false |
AOF | 追加写命令 | appdenonly.aof | 只追加写命令——快 | 重新执行写命令——慢 | 只丢失一秒的写命令备份——高 | 备份数据更实时——true |
- Redis 事务
含义:可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会被序列化,按照顺序地串行化(事务隔离级别)执行而不会被其它命令插入,不许加塞。
1)、redis 事务的相关命令:
① discard:取消事务,放弃执行事务块内的所有命令
② exec:执行所有事务块内的命令(包括所有的watch 锁)
③ multi:标记一个事务块的开始
④ unwatch:取消watch 命令对所有key 的监视
⑤ watch key 【key…】:监视一个(或多个)key,如果在事务执行之前这个(或这些)key 被其他命令所改动,那么事务将被打断
2)、Redis 只是部分支持事务
① 命令语法错误:正常执行的时候遇到了一些命令的语法错误的时候Redis会立即检测出错误,并会按照事务原则对该事务进行回滚操作
② 数据结构错误:在运行时发现了一些逻辑上或者数据结构不搭配的错误就不支持事务了,只是把错误的语句报错,其余的正常执行。
3)、悲观锁:悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁
4)、乐观锁:乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号(version)等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量(乐观锁策略:提交版本必须大于记录当前版本才能执行更新)
5)、执行流程
开启事务:【~# multi】
入队:【将多个执行命令入队到同一个事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列中】
执行:【~# exec】触发事务执行,把队列中的全部命令一起执行
6)、事务特性
① 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
② 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,
也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题
③ 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
7)、事务的执行流程
1、在事务执行之前监控键值对【~# watch k1, k2, .....】把监控的键值对的值(旧值)保存到当前线程的副本中
2、开启事务【~# multi】
3、各种操作命令进入队列等待执行【~# set k1 v1.......】
4、执行事务【~# exec】
a:拿出被监控的【所有键值对】的旧值和当前值进行比较是否一致
否:表明有别的线程调用过此键值对,则当前线程回滚事务
是:表明没有别的线程调用此键值对执行事务
b:撤销事务前的所有监控
注意:Redis 事务采用CAS(compare and swap——比较与交换)去执行的时候有一个缺陷,就是A线程监控了键值对的数据,但是B线程调用了键值对之后,有可能对数据进行了相关操作之后又修改为A线程监控的数据。然后A线程事务执行的时候检查被监控键值对数据是否与旧值一致时发现一样的也可以通过,但实际上键值对数据已经被B线程操作了(这就是ABA问题)。
- Redis 流水线(pipelined)
含义:没有任何附加条件的场景下使用队列批量执行一系列的命令,从而提高系统性能,这就Redis 的流水线技术
功能:现在中Redis 的读写速度是十分快的(大概8~10万次/s),而在读/写操作的时候可能会存在网络通信延时的现象。往往是这样造成了系统的瓶颈。
- Redis 发布订阅
含义:类似于银行卡消费的时候,银行方面往往是通过短信、邮箱或微信等方式通知用户这笔交易的信息,这就是一种发布订阅模式。
条件:银行系统即为发布者,用户即为订阅者
① 发布:要有消息源【~# PUBLISH CCTV3 ‘chaoyou’】
② 订阅:要有订阅者【~# SUBSCRIBE CCTV3】
流程图:
演示案例:
10. Redis 超时命令
含义:类似于Java 虚拟机一样它提供了自动GC(垃圾回收)机制,来保证Java 程序中已经过时不再使用的对象能及时地从堆内存中释放掉内存资源,从而保证内存空间可用。Redis 是基于内存,而内存相对于一个系统来说是最宝贵的资源。它很有限,所以对于Redis 的键值对的回收也是一件非常重要的事情。
特点:当内存不足的时候Redis 会触发自动垃圾回收机制,还可以使用del 命令自己手动删除一些key/value,所以Redis 的回收机制就显得更加的灵活了。
缺点:当垃圾回收的时候有可能某个key/value 非常大(比如:hash 数据里面存在几千万的键值对),在系统并发的时候执行了回收就可能会产生系统停顿,因此选择适当的回收机制和时间将有利于系统性能的提高。
回收特点:一般我们希望回收的是那些已经超时的键值对,而不是那些没有超时的键值对,所以Redis 可以给对应的键值对设置存活时间,这个存活时间完了就是超时了。
命令 | 说明 | 备注 |
---|---|---|
persist key | 持久化key,取消超时时间 | 移除key 的超时时间 |
ttl key | 查看key 的超时时间 | 以秒计算,-1代表没有超时时间,如果不存在key 或key 已经超时则为-2 |
expire key seconds | 设置超时时间戳 | 以秒为单位 |
expireat key timestamp | 设置超时时间点 | 用uninx 时间戳确定 |
pptl key milliseconds | 查看key 的超时时间戳 | 用毫秒为单位 |
pexpire | 设置key 超时的时间 | 以毫秒为单位 |
Pexpireat key stamptimes | 设置超时时间点 | 以毫秒为单位的uninx 时间戳 |
Redis 提供两种方式回收那些超时的键值对
① 定时回收:指在某一个约定的时间点触发一段代码,回收超时的键值对
② 惰性回收:指当一个超时的键,被再次调用get 命令访问时,将触发Redis 将其从内存中清空。
各自优缺点:
定时回收:可以在某个时间点完全把全部超时键值对的内存回收,但是在这个时间可能会造成系统停顿
惰性回收:可以指定要回收的键值对,但是会执行多一次get 命令。
- Redis 主从复制
含义:也就是我们所说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主
思想:
① 在多台数据服务器中,只有一台主服务器,而主服务器只负责写入数据,不负责让外服应用程序读取数据(必须保证dump*.rdb 文件可写性)
② 存在多台从服务器,从服务器不负责写入数据,只负责同步主服务器的数据,并让外部应用程序读取数据。
③ 主服务器在写入数据后,即刻将写入数据的命令发送给从服务器,从而使得主从数据同步
④ 外部应用程序可以随机读取一台从服务器的数据,这样就分摊了读取数据的压力
⑤ 当从服务器不能工作的时候,整个系统将不受影响;当主服务器不能工作的时候,可以方便地在从服务器中选出一台作为主服务器
原理:
① slave启动成功连接到master后会发送一个sync命令
② Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,
在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步
③ 全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
④ 增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
⑤ 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行
一、修改配置文件细节
1、拷贝多个redis.conf文件(至少三个)【~# cp redis.conf /文件夹/文件名.conf】
2、开启 daemonize yes
3、设置pid 文件
4、指定端口号
5、设置各自的log 文件
6、设置各自的dump.rdb 文件
二、一主二从(一个主机两个从机)
1、启动Redis 服务器【~# redis-server /文件夹/文件名.conf】【redis-cli -p 端口号】
2、设置主从服务器原则【~# info replication】——查看主从库情况命令
① 配从(库)不配主(库)【~# slaveof 主库IP 端口号】
② 只要从库连接了主库就会把主库的全部数据copy 过来
③ 读写分离:所以从库只能读不能写,而主库读写都可以,但是一般主库是用来写操作的
④ 主库出现意外断电了,从库只能原地待命等待主库开启连接又恢复
⑤ 每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件
三、薪火相传(链式连接首部是主库)
含义:上一个Slave可以是下一个slave的Master,Slave同样可以接收其他
slaves的连接和同步请求,那么该slave作为了链条中下一个的master,
可以有效减轻master的写压力
注意:中途变更转向:会清除之前的数据,重新建立拷贝最新的
缺点:数据在备份的时候会加长路径消耗
四、反客为主(在薪火相传的基础上【~# salveof no one】)
含义:使当前数据库停止与其他数据库的同步,转成主数据库
五、哨兵模式
含义:反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
作用:
① 通过发送命令,让Redis 服务器返回检测其运行状态,包括主服务器和从服务器。
② 当哨兵检测到master 宕机,会自动(failover)将slave 切换成master,然后通过发布订阅模式通知到其他的从服务器,修改配置文件,让它们切换主机。
failover(故障切换):假设主机宕机,哨兵1检测到这个结果,当时系统并不会马上进行failover 操作,而仅仅是哨兵1主管地认为主机已经不可用了,这个现象被称为主观下线。当后面的哨兵检测也检测到了主服务器不可用,并且有了一定数量的哨兵都认为主服务器不可用,那么哨兵之间就会形成一次投票,投票的结果有一个哨兵发起,进行failover 操作,在failover 操作的过程中切换成功后,就会通过发布订阅方式,让其他哨兵把自己监控的服务器实现切换主机,这个过程称为客观下线。
搭建哨兵模式:
①一主二从:调整结构,6379带着80、81(配置快照文件可参照上面的——修改配置文件细节)
②创建哨兵:自定义的/myredis目录下新建sentinel.conf文件,名字绝不能错
③配置哨兵:sentinel monitor 被监控数据库名字(自己起名字) 127.0.0.1 6379 1(数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机)
④启动哨兵:redis-sentinel /myredis/sentinel.conf
多哨兵监控模式
Redis 学习笔记到此就完毕了