Redis-全面解读
1-Redis是什么?为什么使用redis?
Redis采用的是基于内存的采用的是单进程,单线程模型的KV数据库,由C语言编写。
Redis的特点:
--高性能
--高并发
--分布式-高可用
--支持持久化
--数据丰富
2-Redis与memcached的对比
1 、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。
2 、Redis支持数据的备份,即master-slave模式的数据备份。
3 、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部存在内存之中
4、 redis的速度比memcached快很多
5、Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的IO复用模型。
3-Redis为什么这么快?
1、纯粹内存操作;
2、数据结构简单;
3、采用单线程,避免了不必要的上下文切换和竞争条件;
4、使用多路I/O复用模型,非阻塞IO;
【我们的redis-client在操作的时候,会产生具有不同事件类型的socket。在服务端,有一段I/0多路复用程序,将其置入队列之中。然后,文件事件分派器,依次去队列中取,转发到不同的事件处理器中。】

4-Redis使用场景,数据类型,常见命令
》redis的常见使用场景
1、会话缓存(最常用)
2、消息队列,比如支付
3、活动排行榜或计数
4、发布、订阅消息(消息通知)
5、商品列表、评论列表等
》redis 5种数据类型以及命令
Redis一共支持五种数据类:string(字符串)、hash(哈希)、list(列表)、set(集合)和zset(sorted set 有序集合)。
(1)string(字符串)
它是redis最基本的数据类型,一个key对应一个value,需要注意是一个键值最大存储512MB。

(2)hash(哈希)
redis hash是一个键值对的集合, 是一个string类型的field和value的映射表,适合用于存储对象
【string,hash的区别:hash更适合存储对象】

(3)list(列表)
是redis简单的字符串列表,它按插入顺序排序,可以作为消息队列

(4)set(集合)
是string类型的无序集合,也不可重复

(5)zset(sorted set 有序集合)
是string类型的有序集合,也不可重复 sorted set中的每个元素都需要指定一个分数,根据分数对元素进行升序排序,如果多个元素有相同的分数,则以字典序进行升序排序,sorted set 因此非常适合实现排名

》redis服务相关的命令
select #选择数据库(数据库编号0-15)
quit #退出连接
info #获得服务的信息与统计
monitor #实时监控
config get #获得服务配置
flushdb #删除当前选择的数据库中的key
flushall #删除所有数据库中的key
5.Redis事务和锁
》Redis事务
(*)什么是事务?Transaction
事务是一组原子操作,不能再分。要么都成功,要么都失败
事务由一组DML(Data Manipulation Language数据操作语言:insert update delete)语句组成
事务的特性:原子性、一致性、持久性、隔离性
(*)Redis中事务不是真正的事务,本质:将一组操作放入一个队列中,统一执行
(*)Redis事务举例1:从tom---> 100 ---> mike账号
set tom 1000
set mike 1000
multi
decrby tom 100
incrby mike 100
exec
》Redis锁:
watch:如果锁住的值在事务中出现了变化,就会抛出异常
6.redis的6个过期策略以及内存淘汰机制
1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧。
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。
3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。
4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用。不推荐
5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。依然不推荐
6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。不推荐
7.持久化(RDB+AOF)
(1)RDB:默认的持久化方式
(2)AOF:append only file ----> 通过记录日志 appendfsync everysec 每秒记录一次
(3)什么叫重写?rewrite :AOF文件比较大,redis提供了一种AOF文件重写机制,合并类似的代码。
auto-aof-rewrite-percentage 100 日志文件比上次重写的时候大小超过了1倍
auto-aof-rewrite-min-size 64mb 日志文件超过64M
(4)实际持久化方案:RDB+ROF
RDB优缺点:
(*)优点:恢复快
(*)缺点:两次RDB之间,会造成数据的丢失
AOF优缺点:
(*)保证数据的安全
(*)AOF缺点:恢复效率低
8.redis主从复制
主从模型一定存在单点故障问题
(1)实现读写分离:默认:主节点负责写,从节点(s)负责读
(2)实现任务分离:主节点不再负责生产RDB和AOF文件,由从节点产生
9.Redis哨兵Sentinel(实现HA):解决单点故障的问题

10.redis集群cluster
Redis Cluster:分布式存储机制(3.0以后的新特性) -----> 类似HDFS
(1)什么是Redis Cluster?是Redis提供的分布式存储的解决方案
(2)单节点的Redis存储瓶颈
问题1:容量问题
问题2:高并发(写操作)
(3)Redis Cluster:利用分布式特点,去中心化(没有中心节点)
分布式的存储架构

Redis数据类型案例分析:网站统计用户登录的次数
setbit key 偏移量 value(1或者0)
星期一:
setbit monday 10 1 -----> 星期一,用户ID10登录了网站
setbit monday 110 1 -----> 星期一,用户ID110登录了网站
星期天: setbig sunday *****
总结:
(1)把数据存入内存中
(2)非常适合存储:是与非 (1或者0)
11.缓存雪崩
缓存雪崩:原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机
(1)碰到这种情况,一般并发量不是特别多的时候,使用最多的解决方案是加锁排队,伪代码如下:
加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法!
注意:加锁排队的解决方式分布式环境的并发问题,有可能还要解决分布式锁的问题;线程还会被阻塞,用户体验很差!因此,在真正的高并发场景下很少使用!
(2)给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存,实例伪代码如下:
解释说明:
1、缓存标记:记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存;
2、缓存数据:它的过期时间比缓存标记的时间延长1倍,例:标记缓存时间30分钟,数据缓存设置为60分钟。 这样,当缓存标记key过期后,实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存。
关于缓存崩溃的解决方法,这里提出了三种方案:使用锁或队列、设置过期标志更新缓存、为key设置不同的缓存失效时间,还有一各被称为“二级缓存”的解决方法,有兴趣的读者可以自行研究。
12.缓存穿透
缓存穿透:是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)这也是经常提的缓存命中率问题。
缓存穿透解决方案:
(1)采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
(2)如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴!
把空结果也给缓存起来,这样下次同样的请求就可以直接返回空了,即可以避免当查询的值为空时引起的缓存穿透。同时也可以单独设置个缓存区域存储空值,对要查询的key进行预先校验,然后再放行给后面的正常缓存处理逻辑。
13.缓存预热
缓存预热:就是系统上线后,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
缓存预热解决方案:
(1)直接写个缓存刷新页面,上线时手工操作下;
(2)数据量不大,可以在项目启动的时候自动进行加载;
(3)定时刷新缓存;
14.缓存更新
除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:
(1)定时去清理过期的缓存;
(2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。
两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡。
15.缓存降级
当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。
在进行降级之前要对系统进行梳理,看看系统是不是可以丢卒保帅;从而梳理出哪些必须誓死保护,哪些可降级;比如可以参考日志级别设置预案:
(1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;
(2)警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;
(3)错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
(4)严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。

浙公网安备 33010602011771号