Redis
Redis 采用单线程为什么还这么快?
Redis是单线程的,主要指的是Redis的网络I/O线程,以及键值的get和set等读写操作都是一个线程完成的。但redis的持久化,集群同步等操作则是由另外的线程完成的。
Redis快的原因:
- Redis的大部分操作都在内存中完成,并且采用了高效的数据结构,比如哈希表和跳表
- 单线程模型避免了多线程之间的竞争,省去了单线程和多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题
- Redis采用I/O多路复用机制处理大量的客户端Socket请求,这让Redis可以高效的进行网络通信
- Redis4.0版本之后,Redis添加了多线程的支持,但这时的多线程主要体现在大数据的异步删除上
- Redis6.0版本之后,新增了多线程I/O的读写并发能力,采用了多个I/O线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis的性能瓶颈有时会出在网络 I/O 的处理上,所以为了提高网络请求处理的并行度,Redis 6.0 对于网络请求采用多线程来处理。但是对于读写命令,Redis 仍然使用单线程来处理。
Redis 如何实现数据不丢失?
Redis的数据持久化:缓存数据库的读写都是在内存中,所以它的性能才会高,但在内存中的数据会随着服务器的重启而丢失,为了保证数据不丢失,要把内存中的数据存储到磁盘,以便缓存服务器重启之后,还能够从磁盘中恢复原有的数据,这个过程就是 Redis 的数据持久化。
数据持久化有三种方式:
RDB 快照(Redis DataBase):将某一个时刻的内存数据,以二进制的方式写入磁盘。它即可以保证可靠性,又能在宕机时实现快速恢复。
- RDB 做快照时会阻塞线程吗?
Redis 提供了两个命令来生成 RDB 快照文件,分别是 save 和 bgsave。save 命令在主线程中执行,会导致阻塞。而 bgsave 命令则会创建一个子进程,用于写入 RDB 文件的操作,避免了对主线
程的阻塞,这也是 Redis RDB 的默认配置。- RDB 做快照的时候数据能修改吗?
如果此时可以执行写操作:意味着 Redis 还能正常处理写操作,就可能出现正在执行快照的数据是已经被修改了的情况;
如果此时不可以执行写操作:意味着 Redis 的所有写操作都得等到快照执行完成之后才能执行,那么就又出现了阻塞主线程的问题。
它利用了 bgsave 的子进程,如果主线程执行读操作,则主线程和 bgsave 子进程互相不影响;如果主线程执行写操作,则被修改的数据会复制一份副本,然后 bgsave 子进程会把该副本数据写入 RDB 文件,在这个过程中,主线程仍然可以直接修改原来的数据
AOF日志(AppendOnly File,文件追加方式):记录所有的操作命令,并以文本的形式追加到文件中。Redis每执行一条指令,成功把数据添加到内存中之后然后再记录日志到文件。
- 好处:只记录执行成功的命令,避免了出现记录错误命令的情况;在命令执行完之后再记录,不会阻塞当前的写操作
- 缺点:数据可能会丢失;可能阻塞其他操作,但因为 AOF 日志也是在主线程中执行,所以当 Redis 把日志文件写入磁盘的时候,还是会阻塞后续的操作无法执行。
混合持久化方式:Redis 4.0 新增了混合持久化的方式,集成了 RDB 和 AOF 的优点,把数据以 RDB 的方式写入文件,再将后续的操作命令以 AOF 的格式存入文件,既保证了 Redis 重启速度,又降低数据丢失风险。
Redis 如何实现服务高可用?
解决数据高可用的手段是 副本,设计高可用的Redis服务有三种方式:主从同步、哨兵模式和 Redis 集群服务
Redis Cluster 是一种分布式去中心化的运行模式,是在 Redis 3.0 版本中推出的 Redis 集群方案,它将数据分布在不同的服务器上,以此来降低系统对单主节点的依赖,从而提高 Redis 服务的读写性能。
Redis Cluster 方案采用哈希槽(Hash Slot),来处理数据和实例之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中,
具体执行过程分为两大步。
1, 根据键值对的 key,按照 CRC16 算法计算一个 16 bit 的值。
2,再用 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。