redis的复习
第一章:关于redis的基本知识
1.1 关于NOSQL型数据库
非关系型数据库:不依赖逻辑关系存储,只是简单的靠key--value存储,大大的提高了数据库的可拓展性
获得了远超sql的性能
1.2 非关系型数据库的应用场景
应用于:高并发读写的环境;海量数据的读写
不能使用的场景:需要事务支持时,最好不要使用非关系型数据库
1.3 reids
- 数据都在内存中,支持持久化,主要用作备份恢复
- 除了支持简单的key-value模式,还支持多种数据结构的存储,比如 list、set、hash、zset等。
- 一般是作为缓存数据库辅助持久化的数据库
第二章:redis的概述
1 Redis是一个开源的key-value存储系统。
2 和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。
3 这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。
4 在此基础上,Redis支持各种不同方式的排序。
5 与memcached一样,为了保证效率,数据都是缓存在内存中。
6 区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。
7 并且在此基础上实现了master-slave(主从)同步。
redis的适应场景
配合关系型数据库作为高速缓存使用:
对于一些高频访问的数据,直接访问关系型数据库会对其造成很大的压力,所以可以将这些被高频访问的数据缓存至redis中;--->作用:降低关系型数据库的I/o压力
在分布式架构中
session的保存和共享是比较麻烦的,redis就是一个很好的解决方案,微服务连接同一个redis,就可以做到session的共享,且还能兼顾性能
redis数据库的相关知识
redis中默认是含有16个库(0~15)当然这是可以通过修改配置来更改的;
使用命令 select
统一密码管理,所有库同样密码。
dbsize查看当前数据库的key的数量
flushdb清空当前库
flushall通杀全部库
redis的默认端口号是6379
注意的是redis是单线程的,但是处理数据的速度并不慢,其原因是采用了--->单线程多路复用的技术;
单线程多路复用的原理: 一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)
第三章:Redis的五大常用数据类型
3.1关于key的基本操作
语法 | 功能 |
---|---|
keys * | 查看当前库所有key (匹配:keys *1) |
exists key | 判断某个key是否存在 |
type key | 查看你的key是什么类型 |
del key | 删除指定的key数据 |
unlink key | 非阻塞删除,仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作 |
expire key 10 | 10秒钟:为给定的key设置过期时间 |
ttl key | 查看还有多少秒过期,-1表示永不过期,-2表示已过期 |
select | 命令切换数据库 |
dbsize | 查看当前数据库的key的数量 |
flushdb | 清空当前库 |
flushall | 清空全部库 |
3.2String数据类型
- String是redis中的最基本的数据类型,一个key对应一个value
- String是二进制安全的,意味着可以保存任何数据类型,比如jpg图片和序列化的对象
- String中value可以保存的大小是512m
3.3 String的常用命令
语法 | 解释 |
---|---|
set |
添加键值对 |
NX:当数据库中key不存在时,可以将key-value添加数据库 | |
XX:当数据库中key存在时,可以将key-value添加数据库,与NX参数互斥 | |
EX:key的超时秒数 | |
PX:key的超时毫秒数,与EX互斥 | |
get |
查询对应键值 |
append |
将给定的 |
strlen |
获得值的长度 |
setnx |
只有在 key 不存在时 设置 key 的值 |
incr |
将 key 中储存的数字值增1,只能对数字值操作,如果为空,新增值为1 |
decr |
将 key 中储存的数字值减1,只能对数字值操作,如果为空,新增值为-1 |
incrby / decrby |
将 key 中储存的数字值增减。自定义步长 |
mset |
同时设置一个或多个 key-value对 |
mget |
同时获取一个或多个 value |
msetnx |
同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。有一个失败则都失败(原子性) |
getrange |
获得值的范围,类似java中的substring,前包,后包 |
setrange |
用 |
setex |
设置键值的同时,设置过期时间,单位秒。 |
getset |
以新换旧,设置了新值同时获得旧值。 |
3.4 String的数据结构
redis中的String底层结构是简单的动态数组;类似于java中的ArraryList;
内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。
- 当字符串长度小于1M时,扩容都是加倍现有的空间;
- 如果超过1M,扩容时一次只会多扩1M的空间。
- 需要注意的是字符串最大长度为512M。
第四章:List数据类型
列表数据类型:单键多值;
底层数据结构是一个单链的双向链表可以从头插入,也可以从尾部插入数据(取数据也同理)
常用命令
语法 | 功能 |
---|---|
lpush/rpush |
从左边/右边插入一个或多个值。 |
lpop/rpop |
从左边/右边吐出一个值。值在键在,值光键亡。 |
rpoplpush |
从 |
lrange |
按照索引下标获得元素(从左到右) |
lrange mylist 0 -1 | 0左边第一个,-1右边第一个,(0-1表示获取所有) |
lindex |
按照索引下标获得元素(从左到右) |
llen |
获得列表长度 |
linsert |
在 |
linsert |
在 |
lrem |
从左边删除n个value(从左到右) |
lset |
将列表key下标为index的值替换成value |
数据结构
redis中的List底层数据结构是一个快速链表:
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。
Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
第五章 Redis 集合(Set)
Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
常用命令
语法 | 功能 |
---|---|
sadd |
将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略 |
smembers |
取出该集合的所有值。 |
sismember |
判断集合 |
scard |
返回该集合的元素个数。 |
srem |
删除集合中的某个元素。 |
spop |
随机从该集合中吐出一个值 |
spop |
随机从该集合中吐出N个值。 |
srandmember |
随机从该集合中取出n个值。不会从集合中删除 。 |
smove |
把集合中一个值从一个集合移动到另一个集合 |
sinter |
返回两个集合的交集元素。 |
sunion |
返回两个集合的并集元素。 |
sdiff |
返回两个集合的差集元素(key1中的,不包含key2中的) |
数据结构
set的底层数据结构是字典,使用Hash实现的
第六章:hash类型
Redis hash 是一个键值对集合。Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
存储的方式有三种
第一种:
单键key---->序列化的对象
缺点就是每一次修改和查询都需要将对象序列化和反序列化---->资源开销很大
第二种:
通过 单key + 多(field+value)的形式进行存储
缺点:会造成数据冗余
第三种:
通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题
常用命令
语法 | 功能 |
---|---|
hset |
给 |
hget |
从 |
hmset |
批量设置hash的值 |
hexists |
查看哈希表 key 中,给定域 field 是否存在。 |
hkeys |
列出该hash集合的所有field |
hvals |
列出该hash集合的所有value |
hincrby |
为哈希表 key 中的域 field 的值加上增量 1 -1 |
hsetnx |
将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在 . |
数据结构
Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。
第七章:Redis 有序集合Zset
Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。
常用命令
语法 | 功能 |
---|---|
zadd |
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。 |
zrange |
升序返回有序集 key 中,下标在 |
zrevrange |
降序返回有序集 key 中,下标在 |
zrangebyscore |
返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。 |
zrevrangebyscore |
同上,改为从大到小排列。 |
zincrby |
为元素的score加上增量 |
zrem |
删除该集合下,指定值的元素 |
zcount |
统计该集合,分数区间内的元素个数 |
zrank |
返回该值在集合中的排名,从0开始。 |
数据结构
SortedSet(zset)是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map<String, Double>,可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。
zset底层使用了两个数据结构
(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。
(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。
第八章:redis的事务
Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。Redis事务的主要作用就是串联多个命令防止别的命令插队。
命令 | 功能 |
---|---|
multi | 开始组队 |
exec | 执行队列中的命令 |
discard | 取消组队 |
从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。组队的过程中可以通过discard取消组队
redis事务出现错误的处理方式
若是在组队期间出现错误,则全部命令取消;(reds在执行命令的时候是知道会不会出错的)
若是在执行期间出现错误,那么除了错误的命令其他都执行;
redis事务的三大特性:
- 单独的隔离操作
- 事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 没有隔离级别的概念
- 队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行
- 不保证原子性
- 事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
第九章:redis的持久化
RDB:定时数据快照 默认方式
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里.
持久化的流程:
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
RDB文件名配置
在redis.conf中配置文件名称,默认为dump.rdb
rdb文件的保存路径,也可以修改。默认为Redis启动时命令行所在的目录下.
可以通过修改该配置,将RDB文件存到系统的制定目录下
dir "/root/myredis/"
优点
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高更适合使用
- 节省磁盘空间
- 恢复速度快
缺点:
- Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
- 虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。
- 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。
AOF:指令日志文件 手动开启
Append Only File 以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
持久化的流程:
(1)客户端的请求写命令会被append追加到AOF缓冲区内;
(2)AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
(3)AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
(4)Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
AOF文件名配置
可以在redis.conf中配置文件名称,默认为 appendonly.aof
AOF文件位置路径
AOF文件的保存路径,同RDB的路径一致。
优点:
- 备份机制更稳健,丢失数据概率更低。
- 可读的日志文本,通过操作AOF稳健,可以处理误操作。
缺点:
- 比起RDB占用更多的磁盘空间。
- 恢复备份速度要慢。
- 每次读写都同步的话,有一定的性能压力。
- 存在个别Bug,造成无法恢复。
第十章redis的主从复制
主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主
主从复制的作用:读写分离,性能扩展容灾快速恢复
原理:
- Slave启动成功连接到master后会发送一个sync命令
- Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令, 在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步
- 全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
- 增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
- 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行
第十一章redis的集群操做
Redis 集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。
Redis 集群通过分区(partition)来提供一定程度的可用性(availability ):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。
集群的好处
- 实现扩容
- 分摊压力
- 无中心配置相对简单
集群的缺陷
- 多键操作是不被支持的
- 多键的Redis事务是不被支持的。lua脚本不被支持
- 由于集群方案出现较晚,很多公司已经采用了其他的集群方案,而代理或者客户端分片的方案想要迁移至redis cluster,需要整体迁移而不是逐步过渡,复杂度较大。