zoukankan      html  css  js  c++  java
  • 为什么redis是单线程的以及为什么这么快?

    转自:https://www.cnblogs.com/jichi/p/12790478.html

    官网的说法


    我们先来认真看一下官网的说法。翻译过来大意如下:
    CPU并不是您使用Redis的瓶颈,因为通常Redis要么受内存限制,要么受网络限制。例如,使用在一般Linux系统上运行的流水线Redis每秒可以发送一百万个请求,因此,如果您的应用程序主要使用O(N)或O(log(N))命令,则几乎不会使用过多的CPU 。
    但是,为了最大程度地利用CPU,您可以在同一服务器上启动多个Redis实例,并将它们视为不同的服务器。在某个时候,单个实例可能还不够,因此,如果您要使用多个CPU,则可以开始考虑更早地分片的某种方法。
    但是,在Redis 4.0中,我们开始使Redis具有更多线程。目前,这仅限于在后台删除对象,以及阻止通过Redis模块实现的命令。对于将来的版本,计划是使Redis越来越线程化。
    既然redis的瓶颈不是cpu,那么在单线程可以实现的情况下,自然就使用单线程了。

    自己的解读

    我们知道redis是基于内存的。那么我们接下来要了解一个问题多线程cpu和内存直接操作差多少?
    多线程操作就是使用多个cpu模拟多个线程,对redis进行操作。这样会造成一个巨大的问题,就是cpu的上下文切换问题。cpu的上下文切换的效率比直接在内存中进行读取差的很多。redis使用单个cpu绑定一个内存,针对内存的处理就是单线程的,这样避免了上下文的切换,所以非常的快。
    一次cpu的切换时间大约是1500ns。从内存中读取1mb的连续数据,耗时大约是250us。如果1mb的数据被多个线程读取了1000次。那么就是有1000次时间的上下文切换。于是就是1500ns*1000=1500us。结果显而易见。1500us和250us差的还是很多的。
    那么redis采取单线程还避免了很多问题。如果redis使用多线程来进行,那么就要考虑多线程带来的数据安全问题,如果我们在操作redis的list,hash等数据结构的时候。多线程就可能存在数据不安全的情况,这是就要加锁。一旦加锁就影响了程序的执行速度。

    磁盘读取和内存读取的区别

    【IOPS(Input/Output Operations Per Second)是一个用于计算机存储设备(如硬盘(HDD)、固态硬盘(SSD)或存储区域网络(SAN))性能测试的量测方式】
    【吞吐量是指对网络、设备、端口、虚电路或其他设施,单位时间内成功地传送数据的数量(以比特、字节、分组等测量)】
    内存是一个 IOPS 非常高的系统,因为我想申请一块内存就申请一块内存,销毁一块内存我就销毁一块内存,内存的申请和销毁是很容易的。而且内存是可以动态的申请大小的。
    磁盘的特性是:IPOS很低很低,但吞吐量很高。这就意味着,大量的读写操作都必须攒到一起,再提交到磁盘的时候,性能最高。为什么呢?
    如果我有一个事务组的操作(就是几个已经分开了的事务请求,比如写读写读写,这么五个操作在一起),在内存中,因为IOPS非常高,我可以一个一个的完成,但是如果在磁盘中也有这种请求方式的话,
    我第一个写操作是这样完成的:我先在硬盘中寻址,大概花费10ms,然后我读一个数据可能花费1ms然后我再运算(忽略不计),再写回硬盘又是10ms ,总共21ms
    第二个操作去读花了10ms, 第三个又是写花费了21ms ,然后我再读10ms, 写21ms ,五个请求总共花费83ms,这还是最理想的情况下,这如果在内存中,大概1ms不到。
    所以对于磁盘来说,它吞吐量这么大,那最好的方案肯定是我将N个请求一起放在一个buff里,然后一起去提交。
    方法就是用异步:将请求和处理的线程不绑定,请求的线程将请求放在一个buff里,然后等buff快满了,处理的线程再去处理这个buff。然后由这个buff 统一的去写入磁盘,或者读磁盘,这样效率就是最高。
    对于慢速设备,这种处理方式就是最佳的,慢速设备有磁盘,网络 ,SSD 等等。

    为什么单核cpu绑定一块线程内存效率最高

    我们不能任由操作系统负载均衡,因为我们自己更了解自己的程序,所以我们可以手动地为其分配CPU核,而不会过多地占用CPU”,默认情况下单线程在进行系统调用的时候会随机使用CPU内核,为了优化Redis,我们可以使用工具为单线程绑定固定的CPU内核,减少不必要的性能损耗!
    redis作为单进程模型的程序,为了充分利用多核CPU,常常在一台server上会启动多个实例。而为了减少切换的开销,有必要为每个实例指定其所运行的CPU。
    Linux 上 taskset 可以将某个进程绑定到一个特定的CPU。你比操作系统更了解自己的程序,为了避免调度器愚蠢的调度你的程序,或是为了在多线程程序中避免缓存失效造成的开销。

    redis的多线程情况

    一个redisserver运行的时候,不是单线程的,比如进行rdb备份的时候,就是fork出了一个子进程来进行实现。
    可以通过 ps -ef | grep redis 来查看到redis的进程pid。
    再使用ps -T -p pid 来查看当前pid下面的线程数。

    ps命令的“-T”参数表示显示线程(Show threads, possibly with SPID column.)“SPID”栏表示线程ID,而“CMD”栏则显示了线程名称。

    redis的内存模式为什么比数据库磁盘块

    磁盘数据库的形式,当我们找数据的时候,先找到索引,通过索引然后关联到磁盘的数据。如果使用内存的方式,可以直接从内存中读取数据。减少了硬盘的io。不受硬盘的读取速度影响。

    redis的单线程到底有多快


    redis的每秒查询次数可以达到10w+。但是随着连接数的增加,每秒的查询数会进行减少。通一个服务器多个连接数导致。

    为什么内存读取比硬盘快

    两种的方式不同。内存是一种半导体的存储器,是ram。内存中的数据是电,一旦断电内存中的数据就会消失。内存没有机械结构。
    硬盘是一种机械结构。查找数据的时候,磁盘要运动到想应的位置。磁头读取磁盘里的数据。

    redis单线程的优势和劣势

    优势

    代码更清晰,处理逻辑更简单。
    不用去考虑各种锁的问题,不存在加锁、释放锁操作,没有因为可能出现死锁而导致的性能消耗。
    不存在“多进程或者多线程导致的切换”而消耗CPU。

    劣势

    无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善。

    redis的多路io复用

    redis 采用网络IO多路复用技术,来保证在多连接的时候系统的高吞吐量。
    多路-指的是多个socket网络连接,复用-指的是复用一个线程。多路复用主要有三种技术:select,poll,epoll。epoll是最新的、也是目前最好的多路复用技术。
    采用多路I/O复用技术:其一,可以让单个线程高效处理多个连接请求(尽量减少网络IO的时间消耗)。其二,Redis在内存中操作数据的速度非常快(内存里的操作不会成为这里的性能瓶颈)。主要以上两点造就了Redis具有很高的吞吐量。
    采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求。

    redis为什么是单线程及为什么快的总结

    1、Redis是纯内存数据库,一般都是简单的存取操作,线程占用的时间很多,时间的花费主要集中在IO上,所以读取速度快。
    2、Redis使用的是非阻塞IO、IO多路复用,使用了单线程来轮询描述符,将数据库的开、关、读、写都转换成了事件,减少了线程切换时上下文的切换和竞争。
    3、Redis采用了单线程的模型,保证了每个操作的原子性,也减少了线程的上下文切换和竞争。
    4、Redis避免了多线程的锁的消耗。
    5、Redis采用自己实现的事件分离器,效率比较高,内部采用非阻塞的执行方式,吞吐能力比较大。

  • 相关阅读:
    【故障处理】ORA-12162: TNS:net service name is incorrectly specified (转)
    android studio 编程中用到的快捷键
    java时间格式串
    android Error occurred during initialization of VM Could not reserve enough space for object heap Could not create the Java virtual machine.
    linux安装vmware
    x1c 2017 安装mint18的坑——grub2
    x1c2017 8G版 win linux的取舍纠结记录
    python的try finally (还真不简单)
    kafka+docker+python
    json文件不能有注释
  • 原文地址:https://www.cnblogs.com/alexzhang92/p/12806776.html
Copyright © 2011-2022 走看看