一.概述
1.什么是redis
redis是一个高性能的运行在内存中的非关系型数据库,由c语言编写.
2.redis优缺点
优点
①.读写性能优异,读的速度可以达到110000次/s 写的速度可以达到81000次/s.
②.支持数据持久化 支持AOF与RDB两种持久化方案.
③.支持事务
④.数据类型丰富,除了String,hash,set,zset,list等常规的类型外,还有HyperLogLog,Geo,bitmaps
⑤.支持主从复制,可以进行读写分离
缺点
①.数据库容量受到物理内存的限制.
②.在线扩容比较难
③.持久化可能会丢失数据
3.为什要用redis/缓存
高性能
由于redis是运行在内存中的,所以相对从mysql中获取数据而言,从redis中获取数据会快很多.
高并发
redis对并发的支持时远高于mysql的,它读的速度可以达到11万次每秒,写可以达到8万次每秒
4. redis为什么那么快
①.完全基于内存,绝大部分的操作都是内存操作 .
②.数据结构简单,对数据的操作也简单.
③.采用单线程,避免了不必要的上下文切换和竞争,也没有cpu切换带来的时间消耗.
④.使用了I/O多路复用模型,非阻塞IO;
5.redis应用场景
计数器:
对string进行自增自减操作,可以实现计数器的功能.redis这种内存型的数据库读写性能非常高,很适合存储频繁读写的计数器.
缓存:
将热点数据放到内存中,提高热点数据的读取速度,最快响应用户请求.
会话缓存
存储会话信息,
分步式锁
可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
排行榜
zset可以实现有序操作,从而实现排行榜功能
共同好友
set可以实现求交集,并集
二.数据类型
字符串(Strings) key:value
APPEND key value 追加一个值到key
DECR KEY 整数原子减1
DECR KEY INCREMENT -n
GET KEY 获取KEY的值
SET KEY VALUE 设置一个值
INCR KEY 整数原子+1
INCRBY KEY INCREMENT +n
MGET KEY 获得所有Key的值
SETNX KEY VALUE 设置一个值 当他不存在的时候设置成功
散列(hashes) key {FIELD :valeu;...;FIELD :value}
HSET KEY FIELD VALUE 设置字段的值
HMSET KEY FIELD VALUE FILED VALUE 设置多个字段的值
HSETNX KEY FIELD VALUE 如果不存在filed字段 设置成功
HGET KEY FIELD 获取字段的值
HGETALL KEY 获取全部字段的值
HKEYS KEY 获取全部的字段
HDEL KEY FIELD FIELD.. 删除一个或者多个字段
HEXISTS KEY FIELD 判断key中是否存在字段field
HLEN KEY 获取字段的数量
列表(lists) key {value;...;value}
LPUSH KEY VALUE 从队列的左边入队一个或多个元素
LPUSHX KEY VALUE 当队列存在时,从队列的左边入队一个元素
RPUSH KEY VALUE 从队列的右边入队一个元素
RPUSHX KEY VALUE 当队列存在时,从队列的右边入队一个元素
LPOP KEY 从队列的左边出队一个元素
RPOP KEY 从队列的右边出队一个元素
BLPOP KEY TIMEOUT 删除,并获得该列表中的第一个元素 或阻塞,直到有一个可用
BRPOP KEY TIMEOUT 删除,并获得该列表中的最后一个元素,或阻塞,直到有一个可用
LREM KEY COUNT VALUE 从列表中删除元素
集合(sets) key {value1;...;valuen}
SADD KEY VALUE 添加元素到集合
SCARD KEY 获得集合里面的元素的数量
SDIFF A B A-A交B
SDIFFSTORE C A B C=A-A交B
SINTER A B A交B
SINTERSTORE C A B C = A交B
SUNION KEY KEY 添加多个set元素(合并)
SUNIONSTORE C A B C = A+B(合并)
SISMEMBER KEY MEMBER 判断member是不是key的成员
SMEMBERS KEY 获取集合里面的所有成员
SREM KEY MEMBER 从集合里面删除某个元素
有序集合(zset)
位图(bitmaps)
基于最小单位bit进行存储,非常省空间
SETBIT KEY OFFSET VALUE 给key的offset位置设置值 这个value只能是0或者1
GETBIT KEY OFFSET 获取值
BITCOUNT KEY START END 统计start与end之间的1的个数 包含start与end
超过1会报错
使用场景: 在线状态/签到打卡/活跃统计
基数统计(hyperloglogs) 容错0.8%的错误率
PFADD KEY ELEMENT ...添加元素
PFCOUNT KEY 统计元素的基数数量(不重复的数据的数量)
PFMERGE KEY KEY1 KEY2 1和2的合并基数
应用场景: 网站访问量
地理空间(geospatial) 底层zset 所以它可以使用zset的命令(如删除)
GEOADD KEY jingdu weidu name 添加地理位置
GEOPOST KEY NAME 返回地理空间的经纬度
GEODIST KEY MEMBER1 MEMBER2 KM 返回两个地址位置之间的距离单位km
GEORADIUS KEY JINDU WEIDU 200 KM 返回指定位置半径为200km内的所有单位
三.持久化
RDB
redis默认的持久化方式,按照一定的规则,fock子进程将内存数据已快照的形式保存到硬盘中,默认产生的数据文件是dump.rdb
优点:
1.通过fock子进程来处理所有的持久化工作,主进程不需要进行任何的io操作,保证了redis的性能
2.rdb文件在恢复大数据集时速度比aof恢复的速度快.
缺点:
1.可能会丢失数据
AOF Append Only File
它的原理是将每次操作写命令append到单独的日志文件中 当redis重启的时通过重新执行这个日志文件中的命令达到数据恢复的目的.
当2种方式同时开启时,数据恢复会优先使用aof
优点:
1.可以配置每一条写操作都写入aof日志文件.及时中途宕机,也可以通过redis-check-aof来解决数据一致性的问题,简单理解就是可以实现不丢失数据.
2.aof提供的rewrite机制,可以去掉重复的操作,它的原理是:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。
缺点:
aof文件大 恢复数据慢
aof重写机制
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
这两个配置的意思是aof文件大于64mb 后会触发bgrewriteaof 然后每次文件达到之前的2倍大小都会再触发一次 bgrewriteaof不是新建一个aof文件 而是根据数据从新生成一份aof文件 替换掉原来的aof文件 新生成的aof文件只保留了数据的最终状态,
比如你set了同一个key 一千次 在原来的aof文件中会有一千次set 而在bgrewriteaof后 只有最后一次操作的命令 这样可以去掉前面999次没有意义的操作
四.过期键的删除策略
定时过期 : 每个key都创建一个定时器,到期立即清理,但是会占用大量的cpu资源去处理过期的数据
惰性过期 : 当访问一个key的时候才会去判断key是否已过期,过期则清除.可能存在过期key不会被访问而导致内存占用.
定期过期 : 每隔一段时间清理一次
redis使用了惰性过期与定期过期
五.内存相关
内存淘汰策略: 指内存不足时 怎么处理已存在数据
永久有效的key的策略:
1.noeviction 写入报错
2.allkey-lru: 移除最近最少使用的key
3.allkey-random : 随机移除某个key
设置了过期时间的key的策略:
1.volatile-lru : 移除最近最少使用 根据此项可以实现商城的热点数据
2.volatile-random : 随机移除
3.volatile-ttl 移除即将过期的key
六.线程模型
redis是单线程的.
七.事务
redis事务不保证原子性 但是单条命令是保证原子性的.
redis事务没有隔离级别的概念.只有发起执行的时候才会执行.
编译型异常: 命令入队时出错, 所有的命令都不会执行
运行时异常: 命令入队没出错,但是exec的时候出错,报错的不执行 其余的都执行
multi 开启事务
exec 执行所有multi之后的命令
discard 丢弃所有multi之后的命令
watch 锁定key 直到执行了multi/exec命令
unwatch 取消事务命令
watch 实现乐观锁 在开启事务之前使用watch监控要修改的key 如果在事务exec之前key被修改,则事务执行失败.
八.缓存异常
缓存击穿 : redis中没有,数据库中有 一般是大量用户请求同一个数据,大家又同时去数据库查,引起数据库压力过大.
解决方案:
1.热点数据设置永不过期
2.加互斥锁
缓存穿透 : 数据库和redis中都没有,
1.接口层添加校验,比如id都是大于0的 在街口层拦截掉id小于零的请求
2.缓存取不到,数据库也取不到,可以在redis中添加这个数据 value为null并设置过期时间
3.使用布隆过滤器
缓存雪崩 : redis中没有,数据库中有,这种情况一般是key大面积的过期,很多数据都需要去数据库查,导致数据库压力过大,服务崩掉.
1.解决key同时过期的问题,设置过期时间劲量分散.
缓存预热
此方法目的就是将数据提前缓存到缓存中,比如秒杀活动的商品数据.