redis的数据类型与两种持久化的了解
redis
1. redis入门概述
1.1 redis是什么?
1.reids:remote dictionary server(远程字典服务器)
2.redis是完全开源免费的,用C语言编写的,遵守bsd协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行并支持持久化的nosql数据库,是当前最热门的nosql数据库之一,也被人们称为数据结构服务器
3.redis与其他key-value缓存产品有以下三个特点:
- a.redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
- b.redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储
- c.redis支持数据的备份,即master-slave模式的数据备份
1.2 redis可以做什么
1.内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
2.取最新N个数据的操作,如:可以将最新的10条评论的id放在redis的list集合里面
3.模拟类似于httpSession这种需要设定过期时间的功能
4.发布、订阅消息系统
5.定时器、计数器
1.3 redis怎么玩?
1.数据类型、基本操作和配置
2.持久化和复制,rdb/aof
3.事务的控制
4.复制
2.常用五大数据类型简介
2.1 redis五大数据类型
- String 字符串
- redis最基本的类型,可以理解成与memcached一模一样的类型。一个key对应一个value
- string是二进制安全的,意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象
- 一个redis中字符串value最多可以是512M
- Hash 哈希,类似Java里的Map
- 是一个键值对集合
- 是一个string类型的field和value的映射表,hash特别适合用于存储对象
- 类似Java里面的Map<String,Object>
- .List 列表
- 是简单的字符串列表,按照插入顺序排序。可以添加一个元素导列表的头部(左边)或者尾部(右边)
- 底层实际上是个链表
- Set 集合
- string类型的无序集合,通过hashTable实现的。无序无重复
- Zset(sorted set) 有序集合
- 一样也是string类型元素的集合,且不允许重复的成员
- 不同的是每个元素都会关联一个double类型的分数
- redis正是通过分数来为集合中的成员进行从小到大的排序
- zset的成员是唯一的,但分数(score)可以重复
2.2 redis键(key)
1.keys * :查看所有的键
2.exists key的名字 :判断某个key是否存在
3.move key db :当前库就没有了,被移除了
4.expire key 秒钟: 为给定的key设置过期时间
5.ttl key:查看还有多少秒过期 -1表示永不过期 -2表示已过期(终结,表示移除系统)
6.type key : 查看你的key是什么类型
2.3 redis字符串(String)
1.单值单value
2.set/get/del[删除]/append[在原本的key上添加数值]/strlen[获取key的长度]
3.incr(增,每次只能增加一)/decr(减,每次只能减一)/incrby(递增)/decrby(递减) 一定要是数字才能进行加减
4.getrange/setrange
a.getrange:获取指定区间范围内的值,类似与between....and的关系
- 从0到-1表示全部
b.setrange:设置指定区间范围内的值,格式是setrange key值 具体值
5.setex(set with expire)键秒值/setnx(set if not exist)
6.mset/mget/msetnx(一个不成功全部不成功) m:more 其实也就是可以设置获取多个
7.getset(先get在set)
2.4 redis列表(List)
1.单值多value
2.lpush/rpush/lrange
a.lpush list01 1 2 3 4 5 添加的顺序从左边开始 也就是读出来是5 4 3 2 1 先进后出
b.rpush list02 1 2 3 4 5 添加的顺序从右边开始 也就是读出来是1 2 3 4 5 先进先出
c.lrang list01 0 -1 读取全部 后面的0 -1其实就是读取的范围
3.lpop/rpop
a.lpop list01 结果是5 从栈顶
b.rpop list02 结果是5 从栈底
4.lindex:按照索引下标获得元素(从上到下)
a.lindex list01 索引
5.llen:长度
6.lrem key 删n个value
a.lrem list01 2 3[代表的意思就是删2个3]
7.ltrim key 开始index 结束index:截取指定范围的值后在赋值给key
a.ltrim list01 0 4[截取索引0到索引4]
8.rpoplpush 源列表 目的列表
a.rpoplpush list01 list02[从list01得尾部 到 list02的头部]
9.lset key index value
a.lset list01 1 x [将list01的索引为1的位置的值替换成x]
10.linsert key before/after 值1 值2
a.linsert list01 before x Java [在x前面加个java]
b.linsert list01 after x Oracle[在x后面加个Oracle]
11.性能总结
a.它是一个字符串链表,left/right都可以插入添加
b.如果键不存在,创建新的链表
c.如果键已存在,新增内容
d.如果值全部移除,对应的键也就消失了
e.链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了
2.5 redis集合(set)
1.sadd/smembers/sismember
a.sadd set01 1 1 2 2 3 3[这个时候只是进去了1 2 3]
b.smenbers set01 [查看这个集合]
c.smenbers set01 1[查看这个集合中是否有要查找的值]
2.scard:获取集合里面的元素个数
a.scard set01
3.srem key value 删除集合中的元素
a.srem set01 1
4.srandmenber key 某个整数(随机出几个数)
a.srandmenber set01 3[随机出来3个]
5.spop key 随机出栈
a.spop set01
6.smove key1 key2 在key1里某个值 作用是将key1里的某个值赋给key2
a.smove set01 set02 5 [将5移到set02中去]
7.数学集合类
a.sdiff 差集
- sdiff set01 set02
b.sinter 交集
- sinter set01 set02
c.sunion 并集
- sunion set01 set02
2.6 redis哈希(hash)
1.KV模式不变,但V是一个键值对
2.hset/hget/hmset/hmget/hgetall/hdel
a.hset user id 11
b.hget user id
c.hmset custom id 11 name lili
d.hmget custom id name
e.hgetall custom [相当于拿到全部的]
f.hdel user id[删除了id]
3.hlen:获取到这个键的长度
4.hexists key 在key里面的某个值的key
a.hexists user id
5.hkeys/hvals
a.hkeys custom [所有的键]
b.hvals custom [所有的值]
6.hincrby/hincrbyfloat
a.hincrby custom id 2 [ id+2]
b.hincrbyfloat custom score 0.5 [ +小数]
7.hsetnx
a.hsetnx custom email [email protected][不存在往里存]
2.7 redis集合zset(sorted set)
1.zadd/zrange
a.zadd zset01 60 v1 70 v2 80 v3
b.zrange zset01 0 -1 [出现的是 v1 v2 v3]
c.zrange zset01 0 -1 withscores[v1 60 v2 70 v3 80]
2.zrangebyscore key 开始score 结束score
a.zrangebyscore zset01 60 90[出现60-90之间的]
b.zrangebyscore zset01 (60 (90 [高于60,小于90]
c.zrangebyscore zset01 60 90 limit 2 2[从第二位开始截取两位,其实就类似于分页]
3.zrem key 某score下对应的value值,作用是删除元素
a.zrem zset01 v1
4.zcard/zcount key score 区间/zrank key values 值 作用是获得下标值/zscore key 对应值 作用是获得分数
a.zcard zset01
b.zcount zset01 60 80 [60-80之间有几个]
c.zrank zset01 v1[拿到v1的下标]
d.zscore zset01 v2[拿到v2的分数]
5.zrevrank key values值 作用是逆序获得下标值
a.zrevrank zset01 v3[这时候v3在第一位,也就是逆序了]
6.zrevrange
a.zrevrange zset01 0 -1 [反转]
7.zrevrangebyscore key 结束score 开始score
a.zrevrangebyscore zset01 80 60[逆序]
3. 持久化之RDB[redis database]
3.1 rdb是什么?
1.在指定得时间间隔内将内存中得数据集快照写入磁盘,也就是行话讲的snapshot快照,它恢复时是将快照文件直接读到内存里
2.redis会单独(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,带持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何io操作的,这就确保了极高的性能
3.如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那rdb方式要比aof方式更加的高效。
4.rdb的缺点是最后一次持久化后的数据可能丢失
3.2 fork
1.fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量,环境变量,程序计数器等)
2.数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程
3.3 rdb保存的是dump.rdb文件
3.3.1 配置文件的位置
- 首先找到快照snapshot的位置
a.save 900 1 15min内改过一次就记录
b.save 300 10 5min内改过十次就记录
c.save 60 10000 1min内改过一万次就记录 - 做备份文件得图片如下图所示:
- 禁用rdb持久化得图片如下所示:
- 想要立马改动,有持久化的操作,那就就用:save命令
a.save [这样就可以]
3.4 如何触发rdb快照
- 配置文件中默认的快照配置
- 冷拷贝后重新使用[主机和备机一定要用两台]
- 拷贝的命令:cp dump.rdb dump_new.rdb
- 命令save或者事bgsave
- save:save时只管保存,其他不管,全部阻塞
- bgsave:redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。可以通过lastsave命令获取最后一次成功执行快照的时间
- 执行flushall命令,也会产生dump.rdb文件,但文件里面是空的,无意义
3.5 如何恢复
1.将备份文件(dump.rdb)移动到redis安装目录并启动服务即可
2.config get dir获取目录
3.6 优势与劣势
3.6.1 优势
1.适合大规模的数据恢复
2.对数据完整性和一致性要求不高
3.6.2 劣势
1.在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改
2.fork的时候,内存中的数据就被克隆了一份,大致2倍的膨胀性需要考
3.7 如何停止
1.动态所有停止rdb保存规则的方法:redis -cli config set save “”
4. 持久化之AOF[append only file]
4.1 aof是什么
1.以日志得形式来记录每个写操作[重点]
2.将redis执行过得所有写指定记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启得话就根据日志文件得内容将写指令从前到后执行一次以完成数据的恢复工作
4.2 AOF的配置文件appendonly.aof
1.cat appendonly.aof[可以看到自己之前的操作]
2.修复错误的aof文件
- a.redis-check-aof --fix appendonly.aof
4.3 rewrite
4.3.1 rewrite是什么?
1.aof采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当aof文件的大小超过所设定的阙值时,redis就会启动aof文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof
4.3.2 重写原理
1.aof文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后在rename),遍历新进程的内存中数据,每条记录有一条的set语句
2.重写aof文件的操作,并没有读取类似旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点像。
4.3.3 触发机制
1.redis会记录上次重写时得aof大小,默认配置时当aof文件大小时上次rewrite后大小的一倍且文件大于64M时触发
4.4 优势和劣势
4.4.1 优势
1.每秒同步:appendfsync always 同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好
2.每修改同步:appendfsync everysec 异步操作 每秒记录 如果一秒内宕机 有数据丢失
3.不同步:appendfsync no 从不同步
4.4.2 劣势
1.相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
2.aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同
5. 两种持久化怎么进行选择
1.RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
2.AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来执行这些命令来恢复原始的数据,AOF命令以redis协议追加每次写的操作到文件末尾,redis话可以对AOF文件进行后台重写,使得AOF文件的体积不至于过大
3.只做缓存:如果你希望你的数据在服务器运行的时候存在,你也可以不用任何的持久化
4.同时开启两种持久化的方式
- 如果是在数据库宕机的时候,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常的情况下AOF文件保存的数据集要比RDB文件保存的数据要完整
- RDB的数据不是实时的,同时使用两台服务器重启也只会找AOF文件。这个时候就需要想想是不是只需要AOF文件?其实建议是不要的,因为RDB是更适合用来做备份数据库(AOF一直在变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着可以做一个万一的手段。[怕AOF文件出现了问题]
5.性能建议
- RDB文件只用作后备用途,建议只在slave上持久化RDB文件,而且只要15分钟备份一次就够了,也就是只保留save 900 1这条规则
- 如果开启AOF文件,好处是在最恶劣的情况下也只会丢失不超过两秒的数据,启动脚本简单,只要加载自己的AOF文件就可以了,代价就是带来了持续的IO。二是 AOF rewrite的最后将rewrite过程中产生的数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少 AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小时重写可以改到适当的数值
- 若是不开启AOF文件,仅靠master-slave replication 实现高可用性也可以。能省掉一大笔io也减少了rewrite时带来的系统波动。代价也就是如果master和slave同时挂掉,会丢失十几分钟的数据,启动脚本也要比较两个master和slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构