据说学习需要带着问题和思考去研究。让我们以做题的方式来学习Redis。1、什么是Redis?Redis是一个高性能的键值数据库;作者来自意大利西西里岛的SalvatoreSanfilippo;Redis采用ANSIC语言编写,遵守BSD开源协议;Redis支持网络,可以基于内存,分布式,也可以用来实现一个简单的消息队列;提供丰富的数据结构:字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sortedsets)。2.说Redis是单线程模型,什么意思?单线程并不意味着Redis中的所有操作都由一个线程完成;核心功能,如:网络IO和数据读写由一个线程进行处理;其他一些辅助功能,如:持久化、集群间的数据同步,由单独的线程处理;所以Redis的单线程并不是“真正的”单线程。3、数据读写处理为什么不用多线程?多线程虽然可以提高系统的吞吐量,但是线程切换会有开销;多线程并发处理共享资源,必然会使用各种锁,如果有锁,就会有等待释放锁的过程,但是会降低吞吐率;处理多线程带来的各种问题会使系统变得复杂,复杂的系统容易出问题。4、为什么用单线程,速度却很快?Redis的运行是基于内存的。与磁盘相比,在速度上具有先天优势;Redis具有高效的数据结构,如:哈希表、跳表;多路复用机制可以并发处理大量请求,实现高吞吐量。5、单线程处理的瓶颈是什么?如果有耗时操作,后续请求需要等待;单个值的内容过多,增、取、删都需要时间;使用复杂的命令,例如:SORT/SUNION/ZUNIONSTORE;采集数据很大,全量查询。当并发量很大时,虽然使用了IO多路复用机制,但是从内核缓冲区复制数据的操作仍然是同步操作,会造成性能瓶颈。6、Redis6.0调整为多线程的原因?上面说了,6.0之前的版本是网络IO和数据读写在一个线程中完成;随着硬件性能的提升,Redis的性能瓶颈有时会出现在网络IO处理方面,也就是说单个主线程处理网络请求的速度跟不上底层网络硬件的速度,而且读写操作和网络IO都在同一个主线程,势必会有影响;所以在Redis6.0中,网络IO由多个IO线程并行处理,可以充分利用服务器的多核资源,提高网络读写操作;Redis数据的读写处理仍然是在单个主线程中完成。7、Redis如何做持久化?Redis实现持久化有两种方式:AOF日志和RDB快照;AOF日志命令执行成功后记录日志;命令执行后记录日志,不会阻塞当前写入。操作。命令执行后,日志未记录前会down掉,数据会丢失;AOF日志在主线程中执行,存在IO瓶颈时阻塞后续操作的风险;当数据量比较大的时候,恢复很慢。配置项(appendfsync)Always,同步回写磁盘:每次执行写命令后,立即将日志同步回写到磁盘;everysec,每秒写回磁盘:每次执行写命令后,先将日志写入AOF文件buffer的内存缓冲区每秒写入磁盘;不是,操作系统控制回写到磁盘:每次执行写命令后,首先将日志写入AOF文件的内存缓冲区,这由操作系统决定何时将缓冲区内容写回磁盘。相对于AOF,RDB快照是记录某一时刻的数据,数据恢复是直接将RDB文件读入内存,速度非常快;生成RDB文件有两种方式:save:在主线程中执行,会造成阻塞;bgsave:创建一个专门写RDB文件的子进程,避免阻塞主线程,这也是RedisRDB文件生成的默认配置。子进程由主线程fork产生,可以共享主线程的所有内存数据。RDB快照的间隔不能设置得太短,因为Redis频繁的全量快照会造成性能问题:上一个快照还没有完成,下一个快照就开始了,对磁盘造成压力;bgsave的子进程虽然不会阻塞主线程,但是创建过程会阻塞,频繁创建也会造成性能问题。解决上述问题的一种方法是使用增量快照;在Redis4.0中提出了AOF日志和RDB快照混合的方法:RDB快照的间隔可以设置的比较大,不会影响主线程的运行;在快照区间内,可以使用AOF日志来记录所有的操作。当进行下一次全量RDB快照时,AOF日志将被清除;通过aof-use-rdb-preambleyes设置它。8、常说的缓存雪崩、击穿、穿透是什么?雪崩、崩溃、穿透的最终结果是请求压力会转移到数据库,导致系统崩溃,但场景不同;Avalanche有大量不同的请求无法命中Redis,所有的请求都流向了数据库,数据库的压力急剧增加;雪崩的原因可能是大量缓存键同时过期。在大细分并发的情况下,对于一个特定的请求,缓存中的数据不存在,导致请求到数据库,导致数据库压力过大;原因通常是Key已过期;与avalanche相比,breakdown是针对单个Key。穿透缓存穿透是指请求的数据不在Redis缓存中,也不在数据库中。访问缓存时,找不到数据,会请求数据库,但在数据库中找不到对应的数据;并发量比较大的时候,数据库会承受很大的压力;渗透的原因可能有两种:误操作导致Redis和数据库中的数据都被删除;恶意攻击。9、如何解决雪崩、击穿、击穿引起的问题?雪崩缓存数据过期时间随机设置,防止大量数据同时过期;如果缓存数据库是分布式部署的,则将热点数据均匀分布在不同的缓存数据库中;当发生雪崩时,可以通过服务降级来处理。Breakdown将热数据设置为永不过期。接口层渗透验证,直接过滤恶意请求;使用布隆过滤器快速判断数据是否存在;缓存空值或默认值。10、如何设计缓存的淘汰机制?业务数据不断增长,不可能将所有数据都存储在Redis缓存中,而且内存的价格远高于磁盘。因此,有必要设计淘汰机制;缓存的淘汰是按照一定的策略从缓存中删除不太重要的数据;Redis共有8种淘汰策略,Redis4.0之前有6种,4.0之后新增了2种,如下图:volatile-ttl:根据过期时间,先过期的数据先删除;在设置了过期时间的数据中,按照LRU算法删除数据;volatile-lfu:在设置了过期时间的数据中,按照LFU算法删除数据;allkeys-lru:在所有数据中,按照LRU算法删除数据;allkeys-random:在所有数据中,进行随机删除;allkeys-lfu:在所有数据中,按照LFU算法进行数据删除;默认情况下,当Redis使用的空间超过maxmemory设置的大小时,不会淘汰数据,即执行的noeviction策略,如果满了,有写请求时会报错;如果业务中有明显的热数据和冷数据,优先采用allkeys-lru策略,将热数据保留在缓存中;如果业务中没有明显的冷热数据,可以使用volatile-random或者allkeys-random。11、如何保证缓存中的数据与数据库中的数据一致?缓存和数据库的一致性是指当缓存中有数据时,缓存中的数据和数据库中的数据相同,当没有数据时,数据库中的是最新的;在做增删改查时,更新缓存有两种方式:直接向数据库中添加新的,删除修改时先更新缓存,再同步或异步更新数据库;直接向数据库中添加新的,删除和修改时先更新数据库,然后删除相应的缓存。以上操作都涉及到两个,操作Redis和操作数据库。当其中一个成功,另一个失败时,会出现数据不一致;解决不一致问题:通过消息队列异步处理操作,并设置重试机制保证最终的一致性;使用分布式事务保证操作Redis和数据库这两个操作在一个事务中。12、Redis的使用规范是什么?Redis单个实例的内存大小不宜设置过大。建议设置为2~6GB。如果设置过大,RDB快照、AOF日志恢复、主从集群数据同步等都需要时间。很长,阻塞正常请求的处理;从集合中获取全量数据时,时间复杂度为O(n),所以这个n不宜太大;单个key的值不宜过大,即使是最新的6.0版本,在读的时候写这部分还是单线程的,读大的值会耗时,造成拥塞;根据具体业务特点设计淘汰策略;使用高效的序列化和压缩方法处理缓存数据,进一步提升性能;生产环境中禁止使用KEYS、FLUSHALL、FLUSHDB等操作。数据量大时,耗时长,会阻塞主线程;有时为了排查错误,会使用MONITOR命令进行监控,这也会严重影响性能;Redis的知识远不止这些,本文总结了一些我认为比较重要的点,希望对大家有所帮助!
