首页 > 数据库 >单线程Redis:Redis为什么这么快

单线程Redis:Redis为什么这么快

时间:2024-08-29 20:23:06浏览次数:13  
标签:为什么 单线程 Redis ht 线程 内存 多线程

1 Redis是不是单线程

在这里插入图片描述

Redis 使用后台线程执行耗时的 I/O 操作,以免阻塞主线程

bio_close_file:后台 I/O 线程之一,异步关闭文件
bio_aof_fsync:后台 I/O 线程之一,异步地将 AOF(Append Only File)日志同步到磁盘
bio_lazy_free:异步释放内存,有些内存释放操作可能比较耗时,因此这些操作可以异步完成,以免阻塞主线程
jemalloc_bg_thd:这是由 jemalloc 内存分配器产生的后台线程。jemalloc 是 Redis 默认使用的内存分配器,因为它在多线程环境中表现出色,能够有效地管理内存碎片。这个后台线程通常用于维护和优化内存使用(例如回收空闲内存)。

如果有io_thd_1之类的,则是在处理网络IO

一般认为Redis是单线程,是因为Redis的命令处理是单线程的

1.1 为什么Redis是单线程

单线程的局限:

  • 不能有耗时操作,包括cpu运算和阻塞io

但Redis仍存在耗时操作

io密集型:

  • 磁盘io:有两种方式持久化,一种是bio_aof_fsync,开启一个线程持久化,另外一种是rdb,通过fok进程,在子进程持久化
  • 网络io:Redis需要处理多个服务,Redis采用Reactor网络模型,实现IO多路复用;若数据请求或返回数据量比较大,则会开启io多线程

cpu密集型:

  • Redis使用高效的数据结构,并允许数据结构切换,当数据量大的时候,需使用O(1)、O(lgn)复杂度的数据结构
  • 渐进式数据迁移

Redis为什么不采用多线程?
采用多线程需加锁,加锁复杂,加锁粒度不好控制,加锁会造成频繁的CPU上下文切换,抵消多线程的优势

1.2 单线程为什么快

  1. Redis使用了内存数据库

  2. Redis是一个key-value数据库,数据存储在hashtable中,复杂度是O(1),为了保证O(1)的复杂度,hash冲突不能太激烈。

若数据太多,而hashtable太小,则非常容易冲突。

而Redis是内存数据库,一开始就分配很大空间,浪费内存,因此Redis动态分配数组大小,允许进行扩容、缩容操作。

负载因子:used / size

  • 如果负载因子 > 1 ,则会发生扩容
  • 如果正在 fork (在 rdb、aof 复写以及 rdb-aof 混用情况下)时,会阻止扩容
  • 但是此时若负载因子 > 5 ,索引效率大大降低, 则马上扩容
  • 如果负载因子 < 0.1 ,则会发生缩容

扩容:位于0号的元素,会分别散落在0号和4号,其余同理
在这里插入图片描述

在这里插入图片描述

渐进式Rehash:

若hashtable的size非常大,进行翻倍迁移的时候,是一个非常耗时的操作,但Redis仍然需要服务用户,因此不能一次性迁移。

server.h:6.2.12版本
在这里插入图片描述

dict:存储的keys
expires:过期的keys
blocking_keys:阻塞的keys

在这里插入图片描述

可以看到有一个ht[2],即hashtable有两个,在没有扩容和缩容的时候,通常只使用ht[0],扩容时,会将ht[0]中的数据放入到ht[1]中,并将ht[1]的大小翻倍。

在这里插入图片描述

rehash步骤:
ht[0] 中的元素重新经过 hash 函数生成 64 位整数,再对 ht[1] 长度进行取余,从而映射到 ht[1]

渐进式rehash:

  • 将数据的rehash操作,分摊在增删改查操作中,每次操作一个索引中的全部元素,直到rehash结束,将ht[1]赋值给ht[0],并将ht[1]置为空
  • 在定时器中,在redis空闲时,最大执行一毫秒 rehash ;每次步长 100 个数组槽位
  1. 高效的reactor网络模型

1.3 scan

KEYS *命令非常耗时,若想获取所有keys,可以使用scan命令

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]

在这里插入图片描述

采用高位进位加法的遍历顺序,rehash 后的槽位在遍历顺序上是相邻的

在这里插入图片描述

接下来应该遍历16号索引

在这里插入图片描述

2 string

三种编码

  • int:字符串长度小于等于20且能转成整数
    • 对于大整数,int占的字节比字符串更少
  • raw:字符串长度大于44
  • embstr:字符串长度小于等于44

在这里插入图片描述

在Redis中,string被实现成sds,它包含一些头部,但仍返回实际存储数据的地址。

最后的char buf[]是柔性数组,使用sizeof会不包含char buf[]

面试题:为什么Redis中字符串选择44个字节作为分界线?

embstr顾名思义就是嵌入字符串,嵌入到redisObject中

在这里插入图片描述

在这里插入图片描述

redisObject共占用4 + 4 + 8字节

长度为44的话,选择了sdshdr8的结构(表示长度0-128),sdshr8头部占用了3个字节

cpu cache line最小访问单位为64个字节

同时sds为了兼容strlen等函数,在柔性数组最后加上’\0’分隔符

因此64 - (4 + 4 + 8) - 3 - 1 = 44

3 Redis跳表

跳表(多层级有序链表)结构用来实现有序集合,redis 需要实现 zrange 以及 zrevrange功能,需要节点间最好能直接相连并且增删改操作后结构依然有序

节点数量大于 128 或者有一个字符串长度大于 64,则使用跳表(skiplist)

在这里插入图片描述

4 Redis IO多线程原理

对于一个Redis请求,需要经过read、decode、compute、encode、send这5个流程。

而有时候read、decode、encode、send过程很慢,把它们放在主线程操作,很浪费时间,因此Redis使用了IO多线程。

在这里插入图片描述

将多个IO分发到多个线程(包括主线程)中,但所有的compute仍在主线程中,因此,这与Redis是单线程的并不冲突。

参考链接:https://xxetb.xetslk.com/s/1QH6AQ

标签:为什么,单线程,Redis,ht,线程,内存,多线程
From: https://blog.csdn.net/weixin_45717971/article/details/141679027

相关文章

  • Redis组件介绍(二)
    写在前面今天我们继续学习Redis。Redis常用数据类型在Redis中,每个存储的键值对中,键是String类型,值可以是不同的数据类型。Redis的索引是含头含尾的。String内存模型常用指令设置值SETkeyvalue:设置一个key/value。MSETkey1value1[key2value2...]:一......
  • lock 为什么要传入一个object对象
    lock为什么要传入一个object对象publicclassSingleton{publicstaticSingletoninstance;publicstaticreadonlyobjectsingletonLock=newobject();privateSingleton(){}publicstaticSingletonGetInstance(){if(instance=......
  • 【转发】为什么说程序员是一个极度劳累的工作?
    我们的累明天项目上线,通宵改BUG,好累。需求变来变去,这个项目什么时候是个头,好累现有的技术将要过时,面临淘汰,一堆的新技术要学,好累每天上下班总计四个小时,好累每天六点就要起床去上班,好累又要坐挤死人的地铁,好累。。。为什么会累本来的一个好觉,变成了通宵加班,打乱了作息规律,扰乱了生......
  • 【挖矿病毒】为什么容易传播
    对于大多数挖矿病毒,有以下几个主要因素:漏洞利用:许多挖矿病毒利用操作系统或应用程序的已知漏洞来入侵系统。如果用户没有及时安装安全更新和补丁,这些漏洞就会暴露出来,为挖矿病毒提供了入侵的机会。社会工程和钓鱼攻击:挖矿病毒可能会通过钓鱼邮件、恶意链接或下载的文件等......
  • Redis 数据类型详解
    Redis是一个开源的内存数据结构存储系统,广泛应用于缓存、消息队列、实时数据分析等场景。Redis提供了多种数据类型,本文将详细介绍Redis的五种主要数据类型及其应用场景,并从概述、基本操作、应用场景和数据结构等方面进行深入探讨。1.字符串(String)概述字符串是Redis......
  • Redis 数据类型详解
    Redis是一个开源的内存数据结构存储系统,广泛应用于缓存、消息队列、实时数据分析等场景。Redis提供了多种数据类型,本文将详细介绍Redis的五种主要数据类型及其应用场景,并从概述、基本操作、应用场景和数据结构等方面进行深入探讨。1.字符串(String)概述字符串是Redis......
  • Redis十大数据类型
    Redis十大数据类型数据类型一般指的是value的数据类型,key的类型一般都是字符串一、总体概述redis字符串(String)string是redis最基本的类型,一个key对应一个value,string类型是二进制安全的,意思是redis的string可以包含任何数据,比如jpg图片或者序列化的对象一个redis中字......
  • Redis 安装
    Redis安装 安装前的准备确保Linux是64位,用getconfLONG_BIT查看Linux必须具备gcc编译环境使用gcc-v查看版本如果没有使用yum-yinstallgcc-c++命令安装安装步骤:下载redis7的压缩包,放到本地opt目录下命令:wgethttps://download.redis.io/re......
  • Redisson分布式延迟队列
    Redisson是一个基于redis实现的Java驻内存数据网格,它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。Redisson除了提供我们常用的分布式锁外,还提供了一个分布式延迟队列RDelayedQueue,他是一种基于zset结构实现的延迟队列,其实现类是RedissonDelayedQu......
  • redis过期监听
    redis是一个高性能的KV数据库,除了用作缓存以外,其实还提供了过期监听的功能在redis.conf中,配置notify-keyspace-eventsEx即可开启此功能。然后在代码中继承KeyspaceEventMessageListener,实现onMessage就可以监听过期的数据量publicabstractclassKeyspaceEventMe......