过年了,给大家伙整点福利。
缓存在我们工作中应用非常广泛,而 Redis 凭借着其优异的性能、丰富的生态、活跃的社区、以及低成本的开发门槛,在众多的缓存框架中,一枝独秀。
本文把 Redis 的核心技术点整理了个脑图,为大家总结下 Redis 相关的功能点以及常见问题。
脑图在文末可下载。
我们通常说的 Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的。
但 Redis 其他功能,比如持久化、异步删除、集群数据同步等,其实都是额外的线程执行的。
所以,严格来说,Redis并不是单线程,但是我们一般把Redis称为单线程高性能。
Redis为什么用单线程?
根本原因是避免多线程模式带来的开销问题。
系统中通常会存在被多线程同时访问的共享资源,比如一个共享的数据结构。 当有多个线程要修改这个共享资源时,为了保证共享资源的正确性,就需要有额外的机制进行保证,而这个额外的机制,就会带来额外的开销。
这就是多线程编程模式面临的共享资源的并发访问控制问题:
在Redis 6.0前,网络请求的解析和数据读写都是由主线程来完成的, 这也是我们称之为单线程的原因。 从Redis 6.0开始,网络请求的解析是由其他线程完成, 然后把解析后的请求交由主线程进行实际的内存读写。
always
机制replication buffer 作用:
主节点开始和一个从节点进行全量同步时,会为从节点创建一个输出缓冲区,这个缓冲区就是复制缓冲区。
当主节点向从节点发送 RDB 文件时,如果又接收到了写命令操作,就会把它们暂存在复制缓冲区中。 等 RDB 文件传输完成,并且在从节点加载完成后,主节点再把复制缓冲区中的写命令发给从节点,进行同步。
对主从同步的影响:如果主库传输 RDB 文件以及从库加载 RDB 文件耗时长, 同时主库接收的写命令操作较多,就会导致复制缓冲区被写满而溢出。 一旦溢出,主库就会关闭和从库的网络连接,重新开始全量同步。 所以,我们可以通过调整 client-output-buffer-limit slave 这个配置项,来增加复制缓冲区的大小,以免复制缓冲区溢出。
repl_backlog_buffer 作用:
主节点和从节点进行常规同步时,会把写命令也暂存在复制积压缓冲区中。 如果从节点和主节点间发生了网络断连,等从节点再次连接后,可以从复制积压缓冲区中同步尚未复制的命令操作。
对主从同步的影响:如果从节点和主节点间的网络断连时间过长,复制积压缓冲区可能被新写入的命令覆盖。 此时,从节点就没有办法和主节点进行增量复制了,而是只能进行全量复制。 针对这个问题,应对的方法是调大复制积压缓冲区的大小 repl_backlog_size
。
总的来说,replication buffer 是主从库在进行全量复制时,主库上用于和从库连接的客户端的 buffer。
而 repl_backlog_buffer 是为了支持从库增量复制,主库上用于持续保存写操作的一块专用 buffer。
replication buffer 不是共享的,而是每个从库都有一个对应的客户端。
repl_backlog_buffer 是一块专用 buffer,在 Redis 服务器启动后,开始一直接收写操作命令,这是所有从库共享的。
根本原因是由于存在内存碎片。
操作系统的剩余内存空间总量足够,但是,应用申请的是一块连续地址空间的 N 字节, 但在剩余的内存空间中,没有大小为 N 字节的连续空间了,那么,这些剩余空间就是内存碎片。
内存碎片是如何形成的?
内存碎片的形成有内因和外因两个层面的原因。
内因:操作系统的内存分配机制
内存分配器的分配策略就决定了操作系统无法做到「按需分配」。 这是因为,内存分配器一般是按固定大小来分配内存,而不是完全按照应用程序申请的内存空间大小给程序分配。
Redis 可以使用 libc
、jemalloc
、tcmalloc
多种内存分配器来分配内存,默认使用 jemalloc
。
拿 jemalloc
来说 , jemalloc
的分配策略之一,是按照一系列固定的大小划分内存空间,例如 8 字节、16 字节、32 字节、48 字节,…, 2KB、4KB、8KB 等。 当程序申请的内存最接近某个固定值时, jemalloc
会给它分配相应大小的空间。
这样的分配方式是为了减少分配次数。
例如,Redis 申请一个 20 字节的空间保存数据,jemalloc
就会分配 32 字节,此时,如果应用还要写入 10 字节的数据, Redis 就不用再向操作系统申请空间了,因为刚才分配的 32 字节已经够用了,这就避免了一次分配操作。
外因:大小不一的键值对和键值对修改删除带来的内存空间变化。
比如,一些键值对被删除了,此时,就会把空间释放出来,形成空闲空间,这些空间是碎片空间,并不是连续的。导致大量的内存碎片生成。
如何判断是否有内存碎片?
查询命令:
INFO memory
有一个 mem_fragmentation_ratio
的指标,它表示的就是 Redis 当前的内存碎片率。
如何清理内存碎片?
自动清理的原理:简单来说就是,一块连续的内存空间分割成好几块不连续的空间时,操作系统就会把数据拷贝到别处。此时,数据拷贝需要能把这些数据原来占用的空间都空出来,把原本不连续的内存空间变成连续的空间。
代价:操作系统需要把多份数据拷贝到新位置,把原有空间释放出来,这会带来时间开销。 因为 Redis 是单线程,在数据拷贝时,Redis 只能等着,这就导致 Redis 无法及时处理请求,性能就会降低。
启用自动内存碎片清理:
config set activedefrag yes
两个参数:
控制清理操作占用的 CPU 时间比例的上、下限:
脑图下载地址
提取码:8uah
关于 Redis,之前也总结了一些文章,这里一并做了汇总,希望大家加深对 Redis 的全面理解,工作使用中也能更加的得心应手。
文章列表:
1、Redis分布式锁的正确打开方式
2、关于缓存异常:缓存雪崩、击穿、穿透的解决方案
3、一文读懂Redis持久化机制
4、面试官:Redis 事务完全保证 ACID 么?
5、解决缓存和数据库双写数据一致性问题
6、Redis 的内存淘汰机制,看这篇就够了。
7、Redis 集群之主从模式
8、Redis 高可用之哨兵机制
9、Redis 高可用之哨兵集群
10、Redis 高可用之切片集群
如果你喜欢我的文章,欢迎关注我的公众号【ShawnBlog】。