数据库
首页 > 数据库> > Redis是如何实现高性能的?

Redis是如何实现高性能的?

作者:互联网

Redis到底有多快?

redis到底有多快,可以通过 redis-benchmark 脚本进行基准测试。redis官方的性能基准测试报告 

Redis为什么这么快?

redis之所以这么快,其实是一个综合性的结果。而能够支持其高性能的主要有以下几个点:

  redis在网络层使用了基于epoll的NIO模型解决了高并发的问题。IO模型的基本理论知识

  redis为了快速的根据key找到value,所以提供了一个全局的hash表来哭诉的获取到对应的value。

  redis中的value其实有8种数据类型,但是比较常用的其实是5种(string、list、hash、set、sorted set | int、bit、[]int)。

对应每一种数据类型,redis的底层实现会根据当前的数据来选择不用的数据结构来进行优化,保证一些常用的操作可以在O(1)的时间内完成,但是实际上一些范围操作只能保证在O(N)以内。

  redis中在获取到所有客户端发来的命令请求后,都是由一个线程来完成网络IO(协议解析)和键值对的读写,避免了在多线程下并发访问共享资源所带来的的一系列开销。

Redis的性能瓶颈常发生于哪些地方?

  既然redis执行命令是单线程执行,那么很容易想到如果当执行命令的线程(主线程),被阻塞了或是执行耗时,那么在该命令之后的所有命令都必须等待当前的命令执行完成之后才会被执行。所以通常来说,redis的性能瓶颈会发生在以下几个地方:

  1.大key的操作:无论是读或写,涉及到大key就必然意味着内存和性能的消耗都是较大的;

  2.使用了复杂度较高的命令:只要是非O(1),其他如O(N)甚至O(logN)的操作[SORT/SUNION/ZUNIONSTORE]只要N足够大,依然会耗费大量的CPU计算时间,尤其是当宿主机有其他服务在抢资源的时候,延时更为严重;

  3.大量的key集中过期:key的过期处理也是由主线程执行,所以大量的key过期时,必然导致主线程在执行过期处理完成之前,无法响应客户端的命令;

  4.内存淘汰机制:内存淘汰也是由主线程自己处理的,当redis的内存被耗尽之后,会根据配置的算法【一般是lru或lfu】进行淘汰一定的key。这种情况下自然也会导致主线程无法快速响应客户端;

  5.AOF的always刷盘机制:always的刷盘机制,也是有主线程完成的,由于是对磁盘的写操作,必然会对主线程产生一定的影响;

  6.fork操作:fork操作是操作系统提供的一个内核API,redis在执行RDB或AOF重写时,会fork一个子线程去完成,并且使用CopyOnWrite的机制节约内存。但是fork出一个子线程的时候需要拷贝一个线程所必要的数据结构以及页表(虚拟内存与物理内存的映射)这个操作主线程必然是阻塞的。相对来说线程的数据结构是相对固定的,但是页表是和实例的大小相关的,实例内存越大,拷贝的页表的耗时也自然更大,延时自然更长;

  7.redis所在实例cpu负载过高:负载过高必然导致cpu的争用,当redis的主线程抢占不到cpu执行权时,就只能自我阻塞;此外有一点需要注意的是,如果将redis的主线程与CPU进行核绑时,在fork操作时,fork出的子线程会继承父线程的核绑特性,子线程会与父线程争用同一个CPU;

  8.redis的并发过高:虽然redis采用的是epoll的非阻塞IO,但本质上仍然是同步IO,读写客户端的数据只能采用单线程的机制,无法利用CPU的多核;此外,当并发过高,网卡的带宽被占光时,在客户端看来主线程也是被阻塞住了,这种场景通常发生在实例所在的服务器有其他服务消耗了大量的带宽,这种情况下只能将某些服务放到其他地方。另一种极端的情况是redis单机的实例的并发就将网卡打爆了,这种情况一般发生在机器硬件的差距上【CPU和内存都强悍,就是网卡差(可能是老机器遗留)】,这种情况可以选择换硬件、亦或是对redis进行水平拓展,如:哨兵、集群分片。

  总的来说其实无非就是三个点:1.主线程等待CPU的执行、2.主线程执行单个命令耗时或是等待某个资源耗时,导致后续的命令被阻塞、3.主线程能处理,但是数据传输拉胯,导致客户端的请求进来慢或响应客户端的数据出去慢。但是CPU不够的情况下是相对少见【因为也就一个主线程可能在不间断的执行,而其他线程都是间歇性执行】,更多的是内存和网络IO上的瓶颈。

 

标签:主线,Redis,redis,如何,高性能,线程,内存,CPU,客户端
来源: https://www.cnblogs.com/zhenjungan/p/16492437.html