Redis

廉价感情. 提交于 2020-03-14 01:50:56

 

 

1Redis是什么????

    是一个由C语言开发的一个开源的(遵从BSD协议)高性能键值对的内存数据库,可以用做数据库、缓存、消息中间件等。

PsBSD开源协议是一个给予使用者很大自由的协议。基本上使用者可以"为所欲为",可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布。

性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS。单进程单线程,是线程安全的,采用 IO 多路复用机制。丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。支持数据持久化。可以将内存中数据保存在磁盘中,重启时加载。主从复制,哨兵,高可用。可以用作分布式锁。可以作为消息中间件使用,支持发布订阅。

 

2、五种数据类型

String Redis 最基本的类型,可以理解成与 Memcached一模一样的类型,一个 Key 对应一个 ValueValue 不仅是 String,也可以是数字。

String 类型是二进制安全的,意思是 Redis String 类型可以包含任何数据,比如 jpg 图片或者序列化的对象。String 类型的值最大能存储 512M

 

Hash是一个键值(key-value)的集合。Redis Hash 是一个 String Key Value 的映射表,Hash 特别适合存储对象。常用命令:hgethsethgetall 等。

 

List 列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边) 常用命令:lpushrpushlpoprpoplrange(获取列表片段)等。

应用场景:List 应用场景非常多,也是 Redis 最重要的数据结构之一,比如 Twitter 的关注列表,粉丝列表都可以用 List 结构来实现。

数据结构:List 就是链表,可以用来当消息队列用。Redis 提供了 List Push Pop 操作,还提供了操作某一段的 API,可以直接查询或者删除某一段的元素。

实现方式:Redis List 的是实现是一个双向链表,既可以支持反向查找和遍历,更方便操作,不过带来了额外的内存开销。

 

Set String 类型的无序集合。集合是通过 hashtable 实现的。Set 中的元素是没有顺序的,而且是没有重复的。常用命令:sddspopsmemberssunion 等。

应用场景:Redis Set 对外提供的功能和 List 一样是一个列表,特殊之处在于 Set 是自动去重的,而且 Set 提供了判断某个成员是否在一个 Set 集合中。

 

Zset Set 一样是 String 类型元素的集合,且不允许重复的元素。常用命令:zaddzrangezremzcard 等。

使用场景:Sorted Set 可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。

当你需要一个有序的并且不重复的集合列表,那么可以选择 Sorted Set 结构。

Set 相比,Sorted Set关联了一个 Double 类型权重的参数 Score,使得集合中的元素能够按照 Score 进行有序排列,Redis 正是通过分数来为集合中的成员进行从小到大的排序。

实现方式:Redis Sorted Set 的内部使用 HashMap 和跳跃表(skipList)来保证数据的存储和有序,HashMap 里放的是成员到 Score 的映射。

而跳跃表里存放的是所有的成员,排序依据是 HashMap 里存的 Score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

Ps:skip List是一种随机化的数据结构,基于并联的链表

3、Redis集成使用

   SpringBoot举例

一、RedisTemplate方式

引用jar包:

spring-boot-starter-data-redis  Spring Boot 2.x 以后底层不再使用 Jedis,而是换成了 Lettuce

commons-pool2 用作 Redis 连接池,如不引入启动会报错。

spring-session-data-redis Spring Session 引入,用作共享 Session

    

        常见使用方法:

            String/对象:getsetdelete

            ListleftPushrightPushrangeremove

            Hashputentriesdeletekeysvalues

            SetaddsizemembersisMemberpopmove

二、Spring Cache

Spring Cache 具备很好的灵活性,不仅能够使用 SPELspring expression language)来定义缓存的 Key 和各种 Condition,还提供了开箱即用的缓存临时存储方案,也支持和主流的专业缓存如 EhCacheRedisGuava 的集成。

 

核心就是三个注解:

@Cacheable(value = "user", key = "#id")

根据方法的请求参数对其结果进行缓存:

Key:缓存的 Key,可以为空,如果指定要按照 SPEL 表达式编写,如果不指定,则按照方法的所有参数进行组合。Value:缓存的名称,必须指定至少一个(如 @Cacheable (value='user')或者 @Cacheable(value={'user1','user2'})Condition:缓存的条件,可以为空,使用 SPEL 编写,返回 true 或者 false,只有为 true 才进行缓存。

 

@CachePut(value ="user", key = "#user.id")

根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用。参数描述见上。

@@CacheEvict(value="user", key = "#id")

根据条件对缓存进行清空:

Key:同上。Value:同上。Condition:同上。allEntries:是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存。beforeInvocation:是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存。缺省情况下,如果方法执行抛出异常,则不会清空缓存。

 

定义接口类,在实现类的查 删方法上增加如上注释即可

 

 

4、缺点之一:

缓存和数据库一致性的问题:分布式环境下非常容易出现缓存和数据见数据一致性问题,针对这一点,如果项目对缓存的要求是强一致性的,那么就不用使用缓存。

只能采取合适的策略来降低缓存和数据库间数据不一致的概率,而无法保证两者间的强一致性。

合适的策略包括:

    合适的缓存更新策略

    更新数据库后及时更新缓存

    缓存失败时增加重试机制

5、Redis雪崩、穿透、击穿

雪崩:如果key值失效时间一致,缓存中大量数据同时失效,缓存中无法同时处理这些请求,将请求转移至数据库,数据库也无法同时处理大数据量请求导致数据库崩溃。

方案:

a、key的失效时间加一个随机数setRediskey, value, time+Math.random()*10000;保证数据不会同一时间失效

b、Redis集群部署的话,将热点数据分布到不同的redis库中

c、设置热点数据永不过期,有更新操作更新缓存即可

 

 

穿透:数据库id都是从1开始,如果发起id=-1或者id无限大的不存在数据,不停的攻击数据库,严重会击垮数据库

方案:在接口层增加校验,比如用户鉴权,参数做校验,不合法的校验直接 return,比如 id 做基础校验,id<=0 直接拦截。

      Redis 里还有一个高级用法布隆过滤器(Bloom Filter)这个也能很好的预防缓存穿透的发生。

它的原理也很简单,就是利用高效的数据结构和算法快速判断出你这个 Key 是否在数据库中存在,不存在你 return 就好了,存在你就去查 DB 刷新 KV return

 

击穿:针对摸一个key值进行数据的大量访问,当这个 Key 在失效的瞬间,持续的大并发直接落到了数据库上,就在这个 Key 的点上击穿了缓存。

方案:设置热点数据永不过期,或者加上互斥锁就搞定了。

 

6、Redis单线程还这么快?

a、完全基于内存,绝大部分请求是纯粹的内存操作、非常迅速

b、数据存储结构类似于hashMap,查找和操作的时间复杂度是O(1)

c、采用单线程,避免了不必要的上下文切换和竞争条件,不存在多线程导致的cpu切换,不用考虑各种锁的问题,不存在加锁释放锁操作,没有死锁问题导致的性能损耗

d、使用多路复用IO模型,非阻塞IO

7、RedisMemcached区别

a、存储方式上:MC会把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis有部分数据存在硬盘上,这样能保证数据的持久性。

b、数据支持类型上:mc只支持简单的key-value,而Redis支持五种数据类型

c、底层模型不同:它们之间底层实现方式以及客户端之间的通信应用协议不一样。Redis直接构建了VM机制,因为一般系统调用系统函数的话,会浪费一定的时间去移动和请求。

d、Value的大小:Redis可以达到1GB,而MC只有1MB

 

8、Redis淘汰策略:

Lru: less recently used 最近最少使用

LFU:least frequency use 通过统计访问频率,将访问频率最少,最不经常用的ky淘汰

a、volatile-lru 从已设置过期时间的kv集中对最近最少使用的数据淘汰

b、Allkeys-lru 从所有数据中对最近最少使用的数据淘汰

c、Volatile-random 从已设置过期时间的kv集中随机选择数据淘汰

d、Allkeys-random 从所有数据随机淘汰

e、Volatile-ttl 从已设置过期时间的数据中对剩余时间短(time to live)的数据淘汰

f、Noeviction 不淘汰策略,若超过最大内存,返回错误信息

g、volatile-lfu

h、allkeys-lfu

9、Redis持久化

RDB快照形式是直接把内存中的数据保存到一个 dump 的文件中,定时保存,保存策略。

默认 Redis 是会以快照"RDB"的形式将数据持久化到磁盘的一个二进制文件 dump.rdb

工作原理简单说一下:当 Redis 需要做持久化时,Redis fork 一个子进程,子进程将数据写到磁盘上一个临时 RDB 文件中。

当子进程完成写临时文件后,将原来的 RDB 替换掉,这样的好处是可以 copy-on-write

RDB 的优点是:这种文件非常适合用于备份:比如,你可以在最近的 24 小时内,每小时备份一次,并且在每个月的每一天也备份一个 RDB 文件。

这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。RDB 非常适合灾难恢复。

RDB 的缺点是:如果你需要尽量避免在服务器故障时丢失数据,那么RDB不合适你。

 

AOF:把所有的对 Redis 的服务器进行修改的命令都存到一个文件里,命令的集合。Redis 默认是快照 RDB 的持久化方式。

 

Redis 重启的时候,它会优先使用 AOF 文件来还原数据集,因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。你甚至可以关闭持久化功能,让数据只在服务器运行时存。

使用 AOF 做持久化,每一个写命令都通过 write 函数追加到 appendonly.aof 中,配置方式如下:

appendfsyncyesappendfsync always #每次有数据修改发生时都会写入AOF文件。appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。

AOF 可以做到全程持久化,只需要在配置中开启 appendonly yes。这样 Redis 每执行一个修改数据的命令,都会把它添加到 AOF 文件中,当 Redis 重启时,将会读取 AOF 文件进行重放,恢复到 Redis 关闭前的最后时刻。

我顿了一下,继续说:使用 AOF 的优点是会让 Redis 变得非常耐久。可以设置不同的 Fsync 策略,AOF的默认策略是每秒钟 Fsync 一次,在这种配置下,就算发生故障停机,也最多丢失一秒钟的数据。

缺点是对于相同的数据集来说,AOF 的文件体积通常要大于 RDB 文件的体积。根据所使用的 Fsync 策略,AOF 的速度可能会慢于 RDB

 

10、主从复制

主从配置结合哨兵模式能解决单点故障问题,提高 Redis 可用性。

从节点仅提供读操作,主节点提供写操作。对于读多写少的状况,可给主节点配置多个从节点,从而提高响应效率。

 

11、哨兵

主从复制会存在以下问题:

一旦主节点宕机,从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。主节点的写能力受到单机的限制。主节点的存储能力受到单机的限制。原生复制的弊端在早期的版本中也会比较突出,比如:Redis 复制中断后,从节点会发起 psync。此时如果同步不成功,则会进行全量同步,主库执行全量备份的同时,可能会造成毫秒或秒级的卡顿。

 

Redis Sentinel(哨兵)主要功能包括主节点存活检测、主从运行情况检测、自动故障转移、主从切换。

Redis Sentinel 最小配置是一主一从。Redis Sentinel 系统可以用来管理多个 Redis 服务器。

该系统可以执行以下四个任务:

监控:不断检查主服务器和从服务器是否正常运行。

通知:当被监控的某个 Redis 服务器出现问题,Sentinel 通过 API 脚本向管理员或者其他应用程序发出通知。

自动故障转移:当主节点不能正常工作时,Sentinel 会开始一次自动的故障转移操作,它会将与失效主节点是主从关系的其中一个从节点升级为新的主节点,并且将其他的从节点指向新的主节点,这样人工干预就可以免了。

配置提供者:在 Redis Sentinel 模式下,客户端应用在初始化时连接的是 Sentinel 节点集合,从中获取主节点的信息。

 

 

 

 

 

学习记录:

https://baijiahao.baidu.com/s?id=1660009541007805174&wfr=spider&for=pc

https://www.jianshu.com/p/56999f2b8e3b

https://blog.csdn.net/dreamhai/article/details/80642010

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!