redis随手记

1、redis快的原因:一方面,是因为他是内存数据库,所有操作都在内存上完成,内存的访问速度本身就很快。另一方面是由于它的数据结构。

2、redis数据类型:String、List、Hash、Set、Sorted Set

3、redis底层数据结构:简单动态字符串、双向链表、压缩列表、哈希表、跳表、整数数组

4、数据结构的时间复杂度:哈希表O(1),跳表O(logN),双向链表O(N),压缩列表O(N),整数数组O(N)

5、redis是单线程,主要是指redis的网络IO和键值对读写是有一个线程来完成的,这也是redis对外提供键值存储服务的主要流程。redis的其他功能,比如持久化、异步删除、集群数据同步等,都是用额外的线程执行的。

6、.单线程Redis为什么快?一方面,redis的大部分操作在内存上完成,再加上它采用了高效的数据结构。另一方面,就是redis采用了多路复用机制,使其在网络IO操作中能并发处理大量的客户端请求,实现高吞吐量。

7、redis的持久化机制:AOF日志和RBD快照。

8、1)AOF是后写日志,redis是先执行命令。把数据写入内存,然后才记录日志。可以避免出现记录错误命令的情况。也不会阻塞当前的写操作。
     2)AOF里记录的是redis收到的每一条命令,这些命令以文本形式保存。
     3)为了避免额外的检查开销,redis在向AOF里面记录日志时,不会先对这些命令进行语法检查。所以再实际场景中如果先记日志再执行命令的话,日志中就有可能记录了错误的命令,redis在试用日志恢复数据时,就有可能出错。
     4)AOF的风险:一、如果刚执行完一个命令,还没来得及记日志就宕机了,那么这个命令和相对应的数据就有丢失的风险。二、虽然避免了对当前命令的阻塞,但可能会给下一个操作带来阻塞风险,因为,AOF日志也是再主线程中执行的,如果在把日志文件写入磁盘时吗,磁盘写压力大,就会导致写盘很慢,进而导致后续的操作也无法进行了。
     5)AOF三种写回策略:appendfsync的三个可选值。①Always,同步写回:每个写命令执行完立马同步的将日志写回磁盘;②Everysec,每秒写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;③no,操作系统控制的写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。想要获得高性能,就选择No策略;想要得到高可靠性,就选择Always策略;如果允许数据有一点丢失,有希望性能别受太大影响的话,就选择Everysec策略

     6)小心AOF文件过大带来的性能问题。主要是三个方面:①文件系统本身对文件大小有限制,无法保存过大的文件;②如果文件太大,之后再往里面追加命令记录的话,效率也会变低;③如果发生宕机,AOF中记录的命令要一个个被重新执行,用于故障恢复,如果日志文件太大,整个恢复过程会非常缓慢,就会影响到redis的正常使用。
     7)AOF重写机制。就是在重写时,redis根据数据库的现状创建一个新的AOF文件,就是读取数据库中的所有键值对,然后对每一个键值对用一条命令记录他的写入。旧日志文件中的多条命令在重写后的新日志中变成一条命令。重写过程是由后台子进程bgrewriteaof来完成的,这是为了避免阻塞主线程,导致数据库性能下降。

9、1)RBD,内存快照。就是指内存中的数据在某一个时刻的状态记录。
      2)redis的数据都在内存中,为了提供所有数据的可靠性保证,执行的是全量快照,就是把内存中的所有数据都记录到磁盘中。提供两个命令来生成RBD文件,save和bgsave。save:在主线程中执行,会导致阻塞;bgsave:创建一个子线程,专门用于写入RBD文件,避免了主线程的阻塞,是RBD文件生成的默认配置。
      3)频繁执行全量快照会带来两方面的开销。一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照没做完,后一个又开始做了,容易造成恶性循环。另一方面,bgsave子进程需要通过fork操作从主线程创建出来。fork这个创建过程本身会阻塞主线程,而且主线程的内存越大阻塞时间越长。
      4)增量快照,指做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。
      5)redis 4.0中提出混合使用AOF日志和内存快照的方法。当数据不能丢失时,这个方法是个很好的选择;

10、redis高可靠性,有两层含义:一是数据尽量少丢失,二是服务尽量少中断。

11、redis提供了主从库模式,以保证数据副本的一致,主从库之间采用的是读写分离的方式。读操作:主库、从库都可以接受。写操作:首先到主库执行,然后主库将写操作同步给从库。

12、replicaof  命令形成主库和从库的关系。
数据同步:
    1)第一阶段,是主从库间建立连接、协商同步的过程,主要是为全量复制做准备。这一步从库发生psync命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。psync命令包含了主库的runID和复制进度offset两个参数。(runID:每个redis实例启动时都会自动生成一个随机ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的runID,所以将runID设为“?”。offset:此时设为-1,表示第一次复制)。主库收到psync命令后,会用FULLRESYNC响应带上两个参数:主库runID和主库目前的复制进度offset返回给从库。(FULLRESYNC响应表示第一次复制采用的全量复制)
    2)第二阶段,主库将所有数据同步给从库。从库收到数据后,在本地完成数据加载。主库执行bgsave命令,生成RBD文件,接着将文件发给从库。从库接受到RBD文件后,会先清空当前数据库,然后加载RBD文件。为了保证主从库的数据一致性,主库会在内存中用专门的replication buffer,记录RBD文件生成后收到的所有写操作。
    3)第三阶段,主库会把第二阶段执行过程中新收到的写命令,再发送给从库。具体操作是,当主库完成RBD文件发送后,就会把此时replication buffer中的修改操作发给从库,从库再重新执行这些操作。

13、网络断了后,再redis 2.8之前,从库会和主库重新进行一次全量复制。从redis 2.8开始,主从库会采用增量复制的方式继续同步。增量复制只会把主从库网络断连期间主库收到的命令,同步给从库。
        主库会把断连期间收到的写操作命令,写入replication buffer,同事也会把这些操作命令也写入repl_backlog_buffer这个缓冲区。repl_backlog_buffer是一个环形缓冲区,主库会记录自己写到的位置,从库则会记录自己已经读到的位置。对主库来说,对应的偏移量就是master_repl_offset。主库接收的新写操作越多,这个值就会越大。从库已复制的偏移量slave_repl_offset也在不断增加。正常情况下,这两个偏移量基本相等。
        主从库的连接恢复后,从库首先会给主库发送psync命令,并把自己当前的slave_repl_offset发给主库。此时,主库只用把master_repl_offset和slave_repl_offset之间的命令操作同步给从库就行。(repl_backlog_buffer是一个环形缓冲区,所以再缓冲区写满后,主库会继续写入,此时就会覆盖之前写入的操作。如果从库读取的速度比较慢,有可能导致从库还未读取的操作被主库新写的覆盖了。这会导致主从库间的数据不一致)

14、哨兵机制。哨兵主要负责的就是三个任务:监控、选主和通知。
    1)监控:是指哨兵进程在运行时,周期性地给所有的主从库发送PING命令,检测他们是否仍然在线运行。如果从库没有在规定时间内响应哨兵的PING命令,哨兵就会把它标记为“下线状态”;同样,如果主库也没有在规定时间内响应哨兵的PING命令,哨兵就会判定主库下线,然就开始自动切换主库的流程。
    2)选主:主库挂了以后,哨兵就需要从很多个从库里,按照一定的规则选择一个从库实例,把它作为新的主库。
    3)通知:哨兵会把新主库的连接信息发给其他从库,让她们执行replicaof命令,和新主库建立连接,并进行数据复制。同时,哨兵会把新主库的连接信息通知给客户端,让他们把请求操作发到新主库上。

15、哨兵对主库的下线判断有“主观下线”和“客观下线”两种。哨兵进程会试用PING命令检测它自己个主、从库的网络连接情况,用来判断实例的状态。如果哨兵发现主库或从库对PING命令的响应超时了,那么就会先把它标记为“主观下线”。
哨兵集群:引入多个哨兵实例一起来判断,就可以避免单个哨兵因为自身网络状况不好而误判主库下线的情况。

16、如何选取新主库?首先,哨兵会按照在线状态、网络状态,筛选过滤掉一部分不符合要求的从库,然后,依次按照优先级、复制进度、ID号大小再对剩余的从库进行打分,只要得分最高的从库出现,就把他选为新主库。

17、redis应对数据量增多的两种方案:纵向扩展和横向扩展。
纵向扩展:升级单个redis实例的资源配置,包括增加内存容量、增加磁盘容量、使用更高配置的CPU。
横向扩展:横向增加当前redis实例的个数,在面向百万、千万级别的用户规模时,横向扩展的redis切片集群会是一个非常好的选择。(切片集群,也叫分片集群,就是指启动多个redis实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保、存。)

18、为什么String类型内存开销大?除了记录实际数据,String类型还需要额外的内存空间记录数据长度、空间使用等信息,这些信息也叫作元数据。

19、redis有一种底层数据结构,叫压缩列表(ziplist)是一种非常节省内存的结构。
压缩列表的构成:表头有三个字段zlbytes、zltail和zllen,分别表示列表长度、列表尾的偏移量,以及列表中的entry个数。压缩列表尾还有一个zlend,表示列表结束。
压缩列表之所以能节省内存,就在于它是用一系列连续的entry保存数据。每个entry包含:①prey_len:表示前一个entry的长度。②encoding:表示编码方式。③len表示自身长度。④content保存实际数据。

20、redis用来实现简单的事物的命令为MULTI和EXEC命令。MULTI命令:表示一系列原子性操作的开始。收到这个命令后,redis就知道,接下来再收到的命令需要放到一个内部队列中,后续一起执行,保证原子性。EXEC命令:表示一系列原子性操作的结束。一旦redis收到了这个命令,就表示所有要保证原子性的命令操作都已经发送完成了。此时,redis开始执行刚才放到内部队列中的所有命令操作。

21、redis缓存时,基本有三个操作:应用读取数据时,先读取redis;发生缓存缺失时,需要从数据库读取数据;发生缓存缺失时,还需要更新缓存。按照redis缓存是否接受写请求,分为只读缓存和读写缓存。
读写缓存:
        有同步直写(写请求发给缓存的同时,也会发给后端数据库进行处理,等到缓存和数据库都写完数据,才给客户端返回)和异步写回(所有写请求都先在缓存中处理,等这些增改的数据要被从缓存中淘汰出来时,缓存将他们写回后端数据库)两种策略。其中,同步只写策略优先保证数据可靠性,而异步写回策略优先提供快速响应。

22、内存淘汰策略:
    1)noeviction策略:一旦内存被写满,再有请求来时,redis不在提供服务,而是直接返回错误。
    2)volatile-ttl:在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删除,越早过期的越先被删除。
    3)volatile-random:在设置了过期时间的键值对中,进行随机删除。
    4)volatile-url:使用LRU算法筛选设置了过期时间的键值对。
    5)volatile-lfu:使用LFU算法选择设置了过期时间的键值对。
    6)allkeys-random:从所有键值对中随机选择并删除数据。
    7)allkeys-lru:使用LRU算法在所有数据中进行筛选。
    8)allkeys-lfu:使用LFU算法选择设置了过期时间的键值对。

23、在实际应用redis缓存时,会遇到一些异常问题:缓存中的数据与数据库不一致;缓存雪崩;缓存击穿;缓存穿透。
缓存中数据与数据库不一致:

缓存雪崩:指大量的应用请求无法在redis缓存中进行处理,紧接着,应用将大量请求发送到数据库层,导致数据库层的压力激增。
        导致缓存雪崩的原因:1)缓存中有大量数据同时过期。解决办法,①首先可以避免给大量的数据设置相同的过期时间。②服务降级(当业务应用访问的是非核心数据时,暂时停止从缓存中查询这些数据,而是直接返回预定义信息、空值或是错误信息。当业务应用访问的是核心数据时,仍然允许查询缓存,如果缓存缺失也可以继续通过数据库读取)。2)redis缓存实例发生故障宕机了。解决办法:①在业务系统中实现服务熔断(在发生缓存雪崩时,为了防止引发连锁的数据库雪崩和整个系统的崩溃,在业务应用调用缓存接口时,缓存客户端并不把请求发给redis缓存实例,而是直接返回,等到redis缓存实例重新恢复服务后,再允许应用请求发送到缓存系统。)或请求限流机制(在业务系统的请求入口前端控制每秒进入系统的请求数,避免过多的请求被发送到数据库)。②构建redis缓存高可靠集群

缓存击穿:指针对某个访问非常频繁的热点数据的请求,无法在缓存中进行处理。访问该数据的大量请求全部发送到了后端数据库,导致数据库压力激增,影响数据库处理其他请求。常发生在热点数据过期失效的时候。
        解决办法:对于访问频繁的热点数据不设置过期时间

缓存穿透:指要访问的数据既不在redis缓存中,也不在数据库中,导致请求在访问缓存时发生缓存缺失,再去访问数据库是发现数据库中也没有要访问的数据。
        解决办法:1)缓存空值或缺省值。2)使用布隆过滤器快速判断数据是否存在,减轻数据库压力。3)在请求入口的前端进行请求检测

24、缓存污染:在一些场景下,有些数据被访问的次数非常少,甚至只会被访问一次。当这些数据服务完访问请求后,如果继续存留在缓存中的话只会白白占用缓存空间。
        LFU策略会从两个维度来筛选并淘汰数据:1)数据访问的时效性。2)数据的被访问次数。

25、redis提供两种方法保证并发访问的正确性:锁和原子操作

你可能感兴趣的:(redis随手记)