精华内容
下载资源
问答
  • 一.Redis高并发和快速原因 1.redis是基于内存的,内存的读写速度非常快; 2.redis是单线程的,省去了很多上下文切换线程的时间; 3.redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,...

    一.Redis的高并发和快速原因

    1.redis是基于内存的,内存的读写速度非常快;

    2.redis是单线程的,省去了很多上下文切换线程的时间;

    3.redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。

     

    二.为什么Redis是单线程的

    1.官方答案

    因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。

    2.性能指标

    关于redis的性能,官方网站也有,普通笔记本轻松处理每秒几十万的请求。

    3.详细原因

    1)不需要各种锁的性能消耗

    Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除

    一个对象。这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。

    总之,在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。

    2)单线程多进程集群方案

    单线程的威力实际上非常强大,每核心效率也非常高,多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。

    所以单线程、多进程的集群不失为一个时髦的解决方案。

    3)CPU消耗

    采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。

    但是如果CPU成为Redis瓶颈,或者不想让服务器其他CUP核闲置,那怎么办?

    可以考虑多起几个Redis进程,Redis是key-value数据库,不是关系数据库,数据之间没有约束。只要客户端分清哪些key放在哪个Redis进程上就可以了。

    回到顶部

    三.Redis单线程的优劣势

    1.单进程单线程优势

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

    2.单进程单线程弊端

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

    3.IO多路复用技术

    redis 采用网络IO多路复用技术来保证在多连接的时候, 系统的高吞吐量。

    多路-指的是多个socket连接,复用-指的是复用一个线程。多路复用主要有三种技术:select,poll,epoll。epoll是最新的也是目前最好的多路复用技术。

    这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。

     

    四.Redis高并发快总结

    1. Redis是纯内存数据库,一般都是简单的存取操作,线程占用的时间很多,时间的花费主要集中在IO上,所以读取速度快。

    2. 再说一下IO,Redis使用的是非阻塞IO,IO多路复用,使用了单线程来轮询描述符,将数据库的开、关、读、写都转换成了事件,减少了线程切换时上下文的切换和竞争。

    3. Redis采用了单线程的模型,保证了每个操作的原子性,也减少了线程的上下文切换和竞争。

    4. 另外,数据结构也帮了不少忙,Redis全程使用hash结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如,跳表,使用有序的数据结构加快读取的速度。

    5. 还有一点,Redis采用自己实现的事件分离器,效率比较高,内部采用非阻塞的执行方式,吞吐能力比较大。

    展开全文
  • 一、Redis为什么快 纯内存K-V操作 数据库的工作模式按存储方式分为了磁盘数据库和内存数据库。Redis将数据存储在内存中,并且绝大多数命令都不会受到磁盘 IO 速度的限制,所以速度极快。此外,Redis内部采用了 ...

    一、Redis为什么快

    • 纯内存K-V操作

      数据库的工作模式按存储方式分为了磁盘数据库和内存数据库。Redis将数据存储在内存中,并且绝大多数命令都不会受到磁盘 IO 速度的限制,所以速度极快。此外,Redis内部采用了 HashMap 这种数据结构,从根本上获得了优势,因为 HashMap 无论是查找和操作的时间复杂度都是O(1)

    • 采用了多路复用的I/O机制

      Redis是单线程的,但它底层使用了多路复用 I/O 机制。多路 /O 复用模型是指利用select、poll、epoll 同时监察多个流的 I/O 事件,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒。程序会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法避免了大量的无用操作。

    • 数据结构简单,操作节省时间

      在 Redis 中,有以下五种常用的数据结构:

      • String:字符串类型,通常用作缓存、计数器和分布式锁等;
      • List:链表类型,用作队列、微博关注人时间轴列表等;
      • Hash:可以用于存储用户信息、hash表等;
      • Set:集合类型,用于去重、赞、踩、共同好友等;
      • Zset:有序集合,用于访问量排行榜、点击量排行榜等。

      此外,Redis对数据结构做了很多优化,诸如压缩表、对短数据进行压缩存储、跳表等,都加快了读取速度。

    二、为什么Redis是单线程的

    Redis是单线程的! 这一点是毋庸置疑的(好吧,Redis 6.0 网络读写部分是多线程的)。那为什么Redis使用单线程呢?而且还能有这么快的响应速度。

    Redis is single threaded. How can I exploit multiple CPU / cores?

    It’s not very frequent that CPU becomes your bottleneck with Redis, as usually Redis is either memory or network bound. For instance, using pipelining Redis running on an average Linux system can deliver even 1 million requests per second, so if your application mainly uses O(N) or O(log(N)) commands, it is hardly going to use too much CPU.

    However, to maximize CPU usage you can start multiple instances of Redis in the same box and treat them as different servers. At some point a single box may not be enough anyway, so if you want to use multiple CPUs you can start thinking of some way to shard earlier.

    You can find more information about using multiple Redis instances in the Partitioning page.

    However with Redis 4.0 we started to make Redis more threaded. For now this is limited to deleting objects in the background, and to blocking commands implemented via Redis modules. For future releases, the plan is to make Redis more and more threaded.

    上面这段文字来自官网,解释说明了 Redis 的瓶颈并不在线程,也不在获取CPU资源,而往往是网络带宽和计算机的内存大小,这也就是 Redis 使用单线程的原因。

    当然啦,单线程对于多线程来说并不能提高CPU利用率,但是单线程也有其优点嘛:

    • 省去上下文切换

      上下文不难理解,就是CPU寄存器和程序计数器。主要作用就是存放没有被分配到资源的线程,多线程操作的时候,不是每一个线程都能够直接获取到CPU资源的,我们之所以能够看到我们电脑上能够运行很多的程序,是应为多线程的执行和CPU不断对多线程的切换。但是总有线程获取到资源,也总有线程需要等待获取资源,这个时候,等待获取资源的线程就需要被挂起,也就是我们的寄存。这个时候我们的上下文就产生了,当我们的上下文再次被唤起,得到资源的时候,就是我们上下文的切换。

    • 避免竞争资源

      竞争资源相对来说比较好理解,CPU对上下文的切换其实就是一种资源分批,但是在切换之前,到底切换到哪一个上下文,就是资源竞争的开始。在 Redis 中由于是单线程的,所以所有的操作都不会涉及到资源的竞争。

    • 避免锁的消耗

      对于多线程的来讲,不能回避的就是锁的问题。如果说多线程操作出现并发,有可能导致数据不一致,或者操作达不到预期的效果。这个时候我们就需要锁来解决这些问题。当我们的线程很多的时候,就需要不断的加锁,释放锁,该操作就会消耗掉很多的时间。

    那么如何发挥多核 CPU 的性能呢?

    • 具体可以通过在单机开多个 Redis 实例来完善!

    此外,Redis 用单线程实现但是还能保持高效率的原因,就是I/O多路复用:

    Redis 采用网络 I/O 多路复用技术来保证在多连接的时候,系统的高吞吐量。

    其中多路是指多个 socket 连接,复用是指复用一个线程。多路复用主要有三种技术:select、poll、epoll。

    采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗)。

    在这里插入图片描述

    三、Redis在数据结构方面的优化

    Redis 在数据结构方面做的优化有很多,这里就简单地介绍几个。

    1. 字符串的优化

    虽然 Redis 是用 C 语言编写的,但 Redis 中的字符串并没有沿用 C 语言中的字符串。因为 C 语言里面的字符串的标准形式是以 NULL (即0x\0)结尾的,要获取以 NULL 结尾的字符串长度使用的是 strlen 标准库函数,这个函数的时间复杂度是 O(n),这对 Redis 可不友好,所以 Redis 中的字符串是一种被称为 SDS (Simple Dynamic String)的结构体来保存字符串。

    struct SDS<T> {
        T capacity;     // 数组容量
        T len;          // 数组长度
        byte flags;     // 特殊标志位
        byte[] content; // 数组内容
    }
    

    所以 SDS 中直接使用一个变量来标志字符串的长度,所以提升了效率。

    除此之外,SDS还会有一个预分配的操作,这一点类似于 Java 语言的 ArrayList 结构,需要比实际的内容多分配一些冗余的空间。capacity 表示所分配数组的长度,len 表示字符串的实际长度。

    具体的分配规则如下如果对 :SDS 修改后,len 的长度小于 1M,那么程序将分配和 len 相同长度的未使用空间。举个例子,如果 len=10,重新分配后,buf 的实际长度会变为 10(已使用空间)+10(额外空间)+1(空字符)=21。如果对 SDS 修改后 len 长度大于 1M,那么程序将分配 1M 的未使用空间。

    这一点相对于C语言要优化了不少,在 C 中,当我们频繁的对一个字符串进行修改(append 或 trim)操作的时候,需要频繁的进行内存重新分配的操作,十分影响性能。

    2. 字典的优化

    字典是 Redis 中最为常用的复合型数据结构,它与 Java 中的 HashMap 类似。Redis 本身就是一个 K-V 服务器,除了 Redis 数据库本身外,字典也是哈希键的底层实现。字典的数据结构如下所示:

    typedef struct dict {
        dictType *type;
        void *privdata;
        dictht ht[2];
        int trehashidx;
    }
    
    typedef struct dictht {
        dectEntry **table;    // 哈希表数组
        unsigned long size;   // 第一维数组的长度
        unsigned long sizemask;
        unsigned long used;   // 哈希表中元素个数
    }
    

    重要的两个字段是 dictht 和 trehashidx,这两个字段与 rehash 有关,下面重点介绍 rehash。

    2.1 Rehash

    学过 Java 中的 HashMap 就会知道 rehash 操作。Redis 中的字典同样的会有 Rehash 过程。看上面代码,dict 中存储了一个 dictht 的数组,长度为2,表明这个数据结构中实际存储着两个哈希表 ht[0] 和 ht[1],为什么要存储两张表呢?当然是为了 Rehash,Rehash 的过程如下:

    • 为 ht[1] 分配空间。如果是扩容操作,ht[1]的大小为原数组的两倍;
    • 将 ht[0] 中的键值 Rehash 到 ht[1] 中。
    • 当 ht[0] 全部迁移到 ht[1] 中后,释放 ht[0],将 ht[1] 置为 ht[0],并为 ht[1] 创建一张表,为下一次 Rehash 做准备。

    2.2 渐进式 Rehash

    Redis 中的 Rehash 操作是将 ht[0] 中的键值全部迁移到 ht[1]。所以在大字典的扩容时是很耗时间的,作为单线程的 Redis 很难承受这样的耗时的过程,所以 Redis 使用渐进式 rehash 小步搬迁。这个过程大概如下:

    • 为 ht[1] 分配空间,让字典同时拥有 ht[0] 和 ht[1] 两个哈希表。

    • 字典中维护一个 rehashidx,并将它置为 0,表示 Rehash 开始。

    • 在 Rehash 期间,每次对字典操作(如hset、hdel)时,程序还顺便将 ht[0] 在 rehashidx 索引上的所有键值对 rehash 到 ht[1] 中,当 Rehash 完成后,将 rehashidx 属性+1。当全部 rehash 完成后,将 rehashidx 置为 -1,表示 rehash 完成。

    注意:

    • Redis 不止通过客户端操作对Rehash进行埋点,同时还会设置定时认为,进行渐进式 Rehash;
    • Redis 如果正在 bgsave,为了减少内存页的过多分离,Redis 尽量不去扩容,但是如果 hash 已经非常满了,元素的个数已经达到第一位数组长度的五倍,说明此时 hash 表已经过于拥挤了,这个时候就会强制扩容。

    Redis 中关于数据结构的优化还有很多,相关内容可以自行网络搜索下,这里就只介绍到这里了。

    参考文章

    • 《Redis核心原理与应用实践》
    展开全文
  • 纯内存操作 核心是非阻塞的IO多路复用机制 单线程反而避免了多线程频繁上下文切换的问题
    1. 纯内存操作
    2. 核心是非阻塞的IO多路复用机制
    3. 单线程反而避免了多线程频繁上下文切换的问题
    展开全文
  • Redis为什么是单线程还支持高并发

    千次阅读 2019-08-03 10:21:02
    Redis为什么设计成单线程模式 因为redis是基于内存的读写操作,所以CPU不是性能瓶颈,而单线程更好实现,所以就设计成单线程模式 单线程模式省却了CPU上下文切换带来的开销问题,也不用去考虑各种锁的问题,不存在...

    Redis为什么设计成单线程模式

    因为redis是基于内存的读写操作,所以CPU不是性能瓶颈,而单线程更好实现,所以就设计成单线程模式

    单线程模式省却了CPU上下文切换带来的开销问题,也不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。

    单线程为什么快

    1. 完全基于内存的操作。
    2. redis特有的数据结构,对存储数据做了优化,使访问更加简单高效
    3. 多路IO复用

    多路IO复用:这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗);

    redis虽然是单线程的,但是可以处理并发连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,使并发称为可能。

    单线程为什么快还支持高并发

    基于以上所有redis有以下几个优势:

    1. 完全基于内存操作,加上其特有的数据结构(优化的数据结构)使得其访问速度非常快。
    2. 单线程模式单省却了CPU上下文切换带来的开销问题,也不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。
    3. 多路IO复用,使其可以可以高效的处理多个连接请求,既支持了高并发,同时也减少了网络IO的消耗时间。
    4. Redis采用自己实现的事件分离器,效率比较高,内部采用非阻塞的执行方式,吞吐能力比较大

    单线程的劣势及解决方案

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

    展开全文
  • Redis如何实现高并发 并行与并发的定义: 并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。...
  • 为什么redis 的线程模型是单线程? Redis基于Reactor模式开发了自己的网络事件处理器——文件事件处理器 (file event handler),这个文件事件处理器是单线程的,所以 redis 才叫做单线程的模型。 文件事件处理器 ...
  • redis 内部使用文件事件处理器file event handler,这个文件事件处理器是单线程的,所以 redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器...
  • (1)为什么不采用多进程或多线程处理? 多线程处理可能涉及到锁 多线程处理会涉及到线程切换而消耗CPU (2)单线程处理的缺点? 无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善 2、Redis不...
  • redis 支持复杂的数据结构 redis 相比 memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作。如果需要缓存能够支持更复杂的结构和操作, redis 会是不错的选择。 redis 原生支持集群模式 在 redis3.x ...
  • 1.redis 支持复杂的数据结构 。 redis 相比 memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作。 2.redis 原生支持集群模式。在 redis3.x 版本中,便能支持 cluster 模式,而 memcached 没有原生的集群...
  • redis 支持复杂的数据结构 redis 相比 memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作。如果需要缓存能够支持更复杂的结构和操作, redis 会是不错的选择。 redis 原生支持集群模式 在 redis3.x ...
  • 面试官心理分析 这个是问 Redis 的时候,最基本的问题吧,Redis 最基本的一个内部原理和特点,就是 Redis 实际上是个单线程工作模型,你要是这个都不知道,那后面玩儿 Redis 的时候,出了问题岂不是什么都...Redis 支持
  • 今天我在一个技术群里提出一个问题:Redis为什么这么快,Redis的那些特性能够支持了它的高并发?之前的我,也只是知道Redis是内存数据库,所以读取速度快;IO使用的是多路复用(多路网络连接复用一个IO线程),使用一...
  • 1.redis和memcached有什么区别? 这个事儿吧,你可以比较出N多个区别来,但是我还是采取redis作者给出的几个比较吧 1)Redis支持服务器端的数据操作:Redis相比Memcached来说,拥有更多的数据结构和并支持更丰富...
  • Redis 为什么这么快

    2021-03-04 18:25:12
    Redis 都是你应该掌握的中间件之一。 Redis 是一个开源的底层使用 C 语言编写的 Key-Value 存储数据库,...我们都知道,在如今的互联网中,高并发的场景越来越多,比如双十一、618、抢火车票、抢红包等,一瞬间有成千上
  • Redis为什么这么快

    2018-01-04 10:04:00
    今天我在一个技术群里提出一个问题:Redis为什么这么快,Redis的那些特性能够支持了它的高并发? 之前的我,也只是知道Redis是内存数据库,所以读取速度快;IO使用的是多路复用,使用一个线程来轮询描述符,减少了...
  • Redis为什么这么快?

    万次阅读 2016-04-27 13:04:54
    今天我在一个技术群里提出一个问题:Redis为什么这么快,Redis的那些特性能够支持了它的高并发? 之前的我,也只是知道Redis是内存数据库,所以读取速度快;IO使用的是多路复用,使用一个线程来轮询描述符,减少了...
  • 使用redis缓存,主要是为了解决两个问题:高性能和高并发 (1)高性能 如果不使用缓存的话,对于一些需要后台程序经过复杂的计算、返回的数据相对稳定(不经常变化)、大量用户频繁访问的请求,对于这样类型请求的...
  • 因为Redis是单线程的,那么问题来了:单线程的Redis为什么反而比多线程的memberCache还能有这么好的性能呢?【Redis单线程的线程模型后面会整理发出来】主要是基于3点原因。 为什么Redis可以有更的性能呢? 1....
  • 前段时间学习点Redis,这次结合ssm实现一个高并发抢红包的项目。跟以前不一样的: 基于java配置SSM,而并非XML.为什么要这样呢?找了点网络上的答案: 在使用Spring开发时,我们经常会看到各种各样xml配置,过于繁多...
  • 前段时间学习点Redis,这次结合ssm实现一个高并发抢红包的项目。跟以前不一样的: 基于java配置SSM,而并非XML.为什么要这样呢?找了点网络上的答案: 在使用Spring开发时,我们经常会看到各种各样xml配置,过于繁多...
  • 为什么我们基本选择redis 需要支持复杂的数据结构 例如热搜榜、订单表等 需要持久化 AOF和RDB 优点:redis挂了再次重启,内存里能够快速恢复热数据 缺点:在redis挂了的过程中,数据库中数据修改,会导致数据库和...
  • 为什么使用 Redis ?

    千次阅读 2018-08-08 11:55:08
     Redis是一个性能(支持并发11万读8万写)的key-value存储系统。 支持丰富的存储value类型,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。 Redis支持主从同步。...
  • Redis

    2019-08-05 15:40:43
    Redis简介为什么要用Redis高性能高并发为什么要用Redis而不是Map/Guava做缓存 简介 简单的来说Redis就是一个非关系型数据库,不过跟传统数据库不同的是Redis的数据是存在内存中的,所以读写速度非常快,因此Redis 被...
  • 目录一、 Redis初识1. Redis特性目录1.1 速度快1.2 持久化(断电不丢数据)1.3 多种数据结构1.4 ...为什么Redis速度这么快? Redis将数据存放在内存中 c语言编写 单线程(多线程并发瓶颈) 1.2 持久化(断电不丢数据) Re

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 335
精华内容 134
关键字:

redis为什么支持高并发

redis 订阅