Redis
Posted miraclemaker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis相关的知识,希望对你有一定的参考价值。
1.快的原因:
- 基于内存进行操作,存取速度很快;因为磁盘是通过磁头的转动读取数据,内存是通过电读取数据,电比磁头转动要快。
- 单线程处理事件,io多路复用,不用考虑上下文切换和锁的问题;
- 有很多种优化过后简单的数据结构
2.为什么要用缓存:
- 高性能:如果数据能从内存直接读取,响应速度就会很快;
- 高并发:响应速度快了,系统相应的qps也会增加很多;
3.redis的功能:
- 缓存:符合高性能,高并发;
- 分布式锁:为业务加上分布式锁,避免冲突;
- 实现复杂业务场景,高活跃的用户的统计,维护排行榜之类的;
4.Redis的数据结构:
- 5种基础数据结构:String,List,Set,Zset,Hash
。String:存放任意类型的数据,最常用;
。List:双向链表,方便操作任一数据;
。Set:存储无序唯一集合,能够做交并差集+随机运算,比如点赞人数,共同关注,随机抽奖;spop,sranmember
。Zset:存储有序唯一集合,能够获取指定元素的排名,比如微信步数,直播间礼物排行榜;zrevrank
。Hash:存放对象,比如用户信息,商品信息,购物车信息;
- 3种特殊数据结构:Hyperloglogs,Bitmap,Geospatial
。Bitmap:存储二级制数字,用来保存那些判断0/1的数据,如签到,是否点赞;getbit
。Hyperloglogs:小空间存储大量数据但是有一定误差,如访问总数,热门统计;
。Geospatial:保存经纬度,底层是根据Zset实现的,如附近的人;
- 存储对象用String还是Hash:
。String存储序列化后的对象,占用空间较少,Hash存储每个对象的字段,占用空间较多;
。如果需要对对象字段有频繁的查询或更新,可以用Hash。绝大部分情况下我们都用String存储;
- String是如何实现的:
。用的不是c语言的字符串,是自己编写的叫SDS,有五种实现类型,Redis会根据字符串长度选取一种
。SDS相对c语言字符串来说,1.由于有属性len、获取长度的时间复杂度为O(1);2.修改时可以查看属性len去避免缓冲区溢出,会分配多余的内存避免多次内存分配;3.c字符串以/0结尾,在二机制文件中存在安全问题。
- Zset如何实现的:数据量少/轻时是压缩列表,多的时候是跳表。
5.Redis单线程模型:
- 介绍:基于Reactor模式开发了文件事件处理器,文件事件处理器是单线程运行的。虽然处理器是单线程的,但是通过IO多路复用,可以实现监听器同时对多个套接字进行监听。
- 为什么这么晚推出多线程:1.Redis的性能瓶颈不在cpu,而在内存和网络;2.多线程推出能够提高网络IO的读写性能,但是提升也不大,并且引入多线程后由于线程的上下文切换和锁的一些问题也会影响性能。
6.Redis内存管理:
- 过期时间:
。作用:1.避免缓存一直存却不删除;2.实现一些和时间有关的功能,如验证码,用户登录的token;
。设置:String自带设置过期时间:setex,其他都是依靠expire命令设置的。
。过期后删除策略:
。惰性删除:取key的时候判断是否过期再删除,对cpu友好;
。定期删除:每过一段时间选取设置过期的key,将已过期的key删除,对内存友好;
。redis两种都采用,但是效果也一般,所以需要内存淘汰机制。
- 内存淘汰机制:
。从设置过期时间的key中,淘汰最近最少使用的,将要过期的,任意的,最不经常使用的;
。内存不足时,淘汰最近最少使用的,任意的,最不经常使用的,拒绝新增;
。我们一般用内存不足时,淘汰最近最少使用的数据。
7.Redis持久化:
- 定义:保证Redis在宕机后能恢复数据,有RDB和AOF两种方法
- RDB(默认):创建快照存储某个时间节点上的版本的压缩数据,默认由子线程执行。
- AOF:将每一步操作记录到缓存中,之后每隔一秒刷新到AOF文件。
。AOF日志是先执行命令再写日志,这样不会阻塞命令的执行,但是宕机后数据会丢失,可能会影响下一条命令的执行。由主线程执行。
。当AOF文件太大时,会重写AOF文件。在此期间,程序维护一个缓冲区记录操作,等新的AOF文件(读取数据库的键值对重写,不会对老AOF文件有读取)完成后,将缓冲池的命令加到AOF文件末尾。
- 两种技术的选择:
。RDB的压缩数据很小,还原时速度很快,但是生成过程繁琐,会占用大量的CPU资源。
。AOF文件可以导出分析,不宕机的时候也可以分析恢复一些数据。但AOF重写时有命令会导致命令被写入两次,占用了大量内存资源。
。现在Redis更新为两者混合使用,重写AOF的时候将RDB直接放到开头。
8.Redis事务:
- 使用:
。MULTI:开启事务,EXEC:结束事务,DISCARD:取消事务,WATCH:监听key;
。先MULTI开启事务,之后输入操作,再EXEC后操作开始执行。WATCH监听的key在同一客户端内不会生效,在其他客户端则不能修改监听的key,无论是事务内还是事务外。
- Redis事务只能防止其他命令插队,只保证隔离性,也就是出错不会回滚。因为开发者们觉得出现问题那就是开发过程有问题,开发过程的问题不应该在生产过程出现。与LUA脚本一样不支持ACID。
9.Redis性能优化:
- 防止出现bigkey,即key对应的value过大或者复合的元素数量太多。
- key集中过期问题:设置随机过期,开启lazy-free功能:采用异步方式延迟释放内存,交给子线程处理
10.Redis问题:
- 缓存穿透:
。定义:请求的大量数据缓存和数据库都没有,对数据库造成很大压力,黑客创造大量非法key请求。
。解决:采用校验参数+布隆过滤器
。布隆过滤器:底层是一个数组,请求来的时候,根据key算出他的哈希码,去数组看数组对应位置是不是1,是0证明没有存在,是1证明大概率存在(因为有哈希冲突)。
- 缓存击穿:
。定义:热点数据存在于数据库中,但是不存在于缓存中,一般是因为过期了。
。解决:查询没有结果就设置一个空值,再去数据库中查询。加分布式互斥锁。
- 缓存雪崩:
。定义:缓存在同一时间大量失效,导致请求落入到数据库上
。解决:设置Redis集群,防止因为一个服务器宕机导致缓存雪崩,设置随机过期时间。
11.Redis集群:
- 集群方案:
。主从模式:一个master节点(读写),多个slave节点(读)。我们需要人工发现master宕机,之后手动选择一个slave变为主节点。
。哨兵模式:主从模式+哨兵集群(检测master节点的健康状态),在哨兵检测到master宕机后,先选取优先级高的slave节点,如果优先级一致就选数据复制的最完全的slave节点。虽然解决了读写分离,但是仍然每一个节点都要存储全部数据。
。Cluster模式:哨兵集群无法解决并发读,并且每个节点都存储着全部数据,分片集群有多个主节点保存不同的数据,master节点互相监测健康状态,请求来的时候会被转发到正确的master节点。
- 主从同步原理:第一次slave请求master是全量同步,master会将RDB发给slave,之后master将命令放入缓冲区,slave持续读取缓存区的数据。
12.Redis缓存一致性:
- 双更:数据库和缓存都更新
。先更新数据库,再更新缓存:a更新数据库后去更新缓存的路上太慢了或者时间片刚好用完,b更新数据库+更新缓存都做完了,a又更新缓存,等于真实数据b失效了。
。先更新缓存,再更新数据库:缓存更新完后,数据库出错回滚了。
- 删除:数据库更新,缓存删除
。先删除缓存,再更新数据库:删除缓存后另一个线程来读会直接到数据库取到快照读的数据后写入缓存,此时数据库不会更新了,缓存会一直保留脏数据到下一次更新。延迟双删:更新完数据库后经过time再删一次缓存
。先更新数据库,再删除缓存:更新数据库的过程中,其他线程查询到旧数据,代价小被允许。用消息队列订阅binlog文件,如果删除缓存失败就重试。
13.分布式事务:
- 一致性:
。强一致性:数据时时刻刻都要保持一致;
。弱一致性:数据更新时,允许部分节点被访问不到;
。最终一致性:数据最终会保持一致;
- BASE理论:基本可用,软状态,最终一致性,核心思想是即便无法做到强一致性,但应该采用适合的方式保证最终一致性。
- 柔性事务:不保证一定能通知成功,但是会最大努力去通知,并提供查询接口去核对。
- 2PC:两阶段提交:
。第一阶段:事务管理器向所有本地资源管理器询问是否都准备好了。
。第二阶段:事务管理器根据反馈,决定步调一致的提交事务或者进行回滚
14.跳表:
- 定义:空间换时间的思想,在有序链表中采用增加索引的方式,将链表的查询复杂度降低为O(logn),一般将上层节点数设置为下层的1/2个,以此类推直到最上层。
- 增删改查:
。新增:底层新增数据后,以随机数的形式决定在1-k层也加上这个新数索引;
。删除:将所有层涉及到这个数的索引都删了;
。修改:所有涉及的数都修改了,并重新调整位置;
。查询:查询的时候从最上层依次向下查,类似于二分查找;
- 与红黑树的对比:1.由于索引只是保存一些数据和指针,没有对象的建立,实际上空间的消耗不大,实现简单;2.跳表范围查询更方便;
- 与b+树的对比:1.b+树相对于跳表更适合海量数据的存储;2.b+树查询多条记录的效率比跳表高
以上是关于Redis的主要内容,如果未能解决你的问题,请参考以下文章
Redis 基础 -- Redis简介CentOS 7 单机安装Redis启动Redis(后台启动Redis 指定配置文件启动Redis 开机自启Redis )Redis客户端(含图形化界面)