>  기사  >  데이터 베이스  >  Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석

Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석

青灯夜游
青灯夜游앞으로
2022-01-26 10:38:023249검색

이 기사에서는 Redis6의 스레드 모델을 이해하고 단일 스레드 모델과 다중 스레드 모델을 소개합니다. 모든 사람에게 도움이 되기를 바랍니다.

Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석

1. Redis의 진화 역사

단순히 Redis가 단일 스레드 또는 다중 스레드라고 말하면 이 답변은 확실히 다른 버전에서 사용되는 스레딩 모델이 다릅니다. [관련 권장사항: Redis 동영상 튜토리얼]

Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석

  • 버전 3.x, 입소문이 심한 Redis는 싱글스레드입니다.

  • 버전 4.x는 엄밀히 말하면 싱글 쓰레드가 아닌, 클라이언트 요청 처리를 담당하는 쓰레드가 싱글 쓰레드인데, 일부 멀티 쓰레드(비동기 삭제) . <code>多线程的东西(异步删除)

  • 最新版本的6.0.x后, 告别了大家印象中的单线程,用一种全新的多线程来解决问题。

2. Redis单线程模型

2.1 单线程真实含义

主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석
但Redis的其他功能, 比如持久化、异步删除、集群数据同步等等,其实是由额外的线程整个Redis来说,是多线程的

2.2 单线程性能快原因

Redis 3.x 单线程时代但是性能很快的主要原因

  • 基于内存操作:所有数据都存在内存中,因此所有的运算都是内存级别的
  • 数据结构简单:Redis的数据结构是专门设计的,而这些简单的数据结构的查找和操作的时间大部分复杂度都是o(1)
  • 多路复用和费阻塞IO:使用IO多路复用功能监听多个socket连接客户端,这样就可以使用一个线程连接处理多个请求,减少线程切换带来的开销,同时避免IO阻塞操作
  • 避免上下文切换:因为是单线程模型,就可以避免不必要的上先文切换和多线程竞争,这样可以省去多线程切换带来的时间和性能上的消耗,而且单线程不会导致死锁问题的发生

2.3 采用单线程原因

Redis 是基于内存操作的, 因此他的瓶颈可能是机器的内存或者网络带宽而并非 CPU ,既然 CPU 不是瓶颈,那么自然就采用单线程的解决方案了,况且使用多线程比较麻烦。 但是在 Redis 4.0 中开始支持多线程了,例如后台删除等功能
简单来说,Redis  4.0 之前一直采用单线程的主要原因有以下三个: 

  • 使用单线程模型是 Redis 的开发和维护更简单,因为单线程模型方便开发和调试;多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。Redis通过AE事件模型以及IO多路复用等技术,处理性能非常高,因此没有必要使用多线程。单线程机制使得 Redis 内部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等 “线程不安全” 的命令都可以无锁进行。 

  • 即使使用单线程模型也并发的处理多客户端的请求,主要使用的是多路复用和非阻塞 IO; 

  • 对于 Redis 系统来说, 主要的性能瓶颈是内存或者网络带宽而并非 CPU최신 버전 6.0 이후.

2. Redis 단일 스레드 모델

2.1 단일 스레드

🎜의 진정한 의미는 주로 Redis의 네트워크 IO와 키-값 쌍 읽기 및 쓰기가 하나의 스레드로 완료된다는 의미이며, Redis는 고객의 획득(소켓 읽기), 구문 분석, 실행, 콘텐츠 반환(소켓 쓰기) 등을 포함한 클라이언트의 요청을 모두 순차 및 직렬 메인 스레드로 처리합니다. 이를 소위 "단일 스레드"라고 합니다. ". 이는 Redis가 외부 키-값 스토리지 서비스를 제공하는 주요 프로세스이기도 합니다. Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석
그러나 🎜지속성, 비동기 삭제, 클러스터 데이터 동기화 등🎜과 같은 Redis의 다른 기능은 실제로 추가 스레드에 의해 실행됩니다.​ Redis 작업자 스레드는 단일 스레드라고 할 수 있습니다. 그러나 전체 Redis는 멀티 스레드입니다. 🎜🎜🎜🎜2.2 단일 스레드 성능이 빠른 주된 이유🎜🎜🎜🎜Redis 3.x는 단일 스레드이지만 성능이 빠릅니다 :🎜
    🎜메모리 작업 기반: 모든 데이터가 메모리에 저장되므로 모든 작업이 메모리 수준입니다.🎜🎜간단한 데이터 구조: Redis의 데이터 구조는 특별히 설계되었으며 이러한 단순함 데이터 구조 검색 및 작업의 시간 복잡도는 대부분 o(1)🎜🎜다중화 및 차단 IO: IO 다중화 기능을 사용하여 클라이언트에 대한 여러 소켓 연결을 모니터링합니다. 이 방법으로 하나의 스레드 연결을 사용하여 여러 요청을 처리하고 스레드 전환으로 인한 오버헤드를 줄이면서 IO 차단 작업을 피할 수 있습니다🎜🎜컨텍스트 전환 방지: 단일 스레드 모델이므로 불필요한 컨텍스트 전환 및 멀티스레딩을 피할 수 있습니다. 다중 스레드 전환으로 인한 시간 및 성능 소모를 절약할 수 있으며 단일 스레드로 인해 교착 상태 문제가 발생하지 않습니다🎜🎜🎜🎜🎜2.3 단일 스레드를 사용하는 이유🎜🎜🎜🎜Redis는 메모리 작업을 기반으로 하므로 병목 현상이 CPU보다는 머신의 메모리나 네트워크 대역폭. CPU는 병목 현상이 아니기 때문에 단일 스레드 솔루션을 사용하는 것이 당연하고 다중 스레드를 사용하는 것이 더 번거롭습니다. 하지만 Redis 4.0부터 백그라운드 삭제, 기타 기능 등 멀티스레딩을 지원하기 시작했습니다.
    간단히 말하면 Redis가 4.0 이전에 항상 단일 스레딩을 사용한 세 가지 주요 이유는 다음과 같습니다. 🎜🎜🎜🎜단일 스레드 모델을 사용하면 Redis의 개발 및 유지 관리가 더 간단해집니다. 개발 및 디버깅에 편리합니다. 스레딩 모델은 일부 측면에서 잘 작동하지만 프로그램 실행 순서에 불확실성이 발생하고 동시 읽기 및 쓰기에 일련의 문제가 발생하며 시스템 복잡성이 증가하고 스레드 전환이 포함될 수 있습니다. 잠금 및 잠금 해제, 교착 상태로 인한 성능 손실. Redis는 AE 이벤트 모델, IO 다중화 및 기타 기술을 통해 매우 높은 처리 성능을 제공하므로 멀티 스레딩을 사용할 필요가 없습니다. 단일 스레드 메커니즘은 Redis 내부 구현의 복잡성을 크게 줄여주며, Rehash, Lpush 및 기타 "스레드 안전하지 않은" 명령은 잠금 없이 실행될 수 있습니다. 🎜🎜🎜🎜단일 스레드 모델을 사용하더라도 주로 멀티플렉싱 및 비차단 IO를 사용하여 여러 클라이언트 요청을 동시에 처리할 수 있습니다. 🎜🎜🎜🎜Redis 시스템의 경우 주요 성능 병목 현상은 CPU 대신 메모리 또는 네트워크 대역폭입니다. . 🎜🎜🎜🎜🎜3. Redis 멀티스레딩 모델🎜🎜🎜🎜🎜3.1 멀티스레딩 도입 이유🎜🎜🎜

    既然单线程那么好,为啥又要引入多线程?단일 스레드에도 큰 키 삭제 문제와 같은 자체적인 문제가 있습니다. 일반적인 상황에서는 del 명령어를 사용하여 데이터를 빠르게 삭제할 수 있습니다. 그러나 삭제된 키가 수천 개의 요소를 포함하는 해시 세트와 같이 매우 큰 개체인 경우 del 명령어로 인해 Redis 마스터가 실패하게 됩니다. 붙어 있습니다.

    따라서 Redis 4.0에는 멀티스레딩 모듈이 추가되었습니다. 물론 이 버전의 멀티스레딩은 주로 데이터 삭제 효율성이 낮은 문제를 해결하기 위한 것입니다. 지연 삭제를 통해 Redis 지연 문제(대규모 키 삭제 등)를 효과적으로 방지할 수 있습니다. 단계는 다음과 같습니다.

    • 키 연결 해제: 키 삭제 기능의 지연 자유 구현 DEL과 마찬가지로 유일한 차이점은 예입니다. UNLINK가 세트 유형 키를 삭제할 때 세트 키의 요소 수가 64보다 크면 메인 스레드는 삭제될 키만 데이터베이스 사전에서 제거하고 실제 키는 제거합니다. 메모리 해제 작업은 별도의 bio에서 수행됩니다. 요소 수가 적거나(64개 미만) 문자열 유형인 경우에도 기본 스레드에서 직접 삭제됩니다.

      unlink key : 与DEL一样删除key功能的lazy free实现,唯一不同是,UNLINK在删除集合类型键时,如果集合键的元素个数大于64个,主线程中只是把待删除键从数据库字典中摘除,会把真正的内存释放操作,给单独的bio来操作。如果元素个数较少(少于64个)或者是String类型,也会在主线程中直接删除。

    • flushall/flushdb async : 对于清空数据库命令flushall/flushdb,添加了async异步清理选项,使得redis在清空数据库时都是异步操作。实现逻辑是为数据库新建一个新的空的字典,把原有旧的数据库字典给后台线程来逐一删除其中的数据,释放内存。

    • 把删除工作交给了后台子进程异步删除数据

    因为Redis是单个主线程处理,redis之父antirez一直强调"Lazy Redis is better Redis". 而lazy free的本质就是把某些cost(主要时间复制度,占用主线程cpu时间片)较高删除操作, 从redis主线程剥离让bio子线程来处理,极大地减少主线阻塞时间。从而减少删除导致性能和稳定性问题。

    Redis 4.0 就引入了多个线程来实现数据的异步惰性删除等功能,但是其处理读写请求的仍然只有一个线程,所以仍然算是狭义上的单线程。

    从上一小结分析:Redis的主要性能瓶颈是内存或网络带宽而并非CPU。内存问题比较好解决,因此Redis的瓶颈原因为网络IO。接下来,引入多线程模型。

    3.2 多线程工作原理

    I/O 的读和写本身是堵塞的,比如当 socket 中有数据时,Redis 会通过调用先将数据从内核态空间拷贝到用户态空间,再交给 Redis 调用,而这个拷贝的过程就是阻塞的,当数据量越大时拷贝所需要的时间就越多,而这些操作都是基于单线程完成的。Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석

    在 Redis 6.0 中新增了多线程的功能来提高 I/O 的读写性能,他的主要实现思路是将主线程的 IO 读写任务拆分给一组独立的线程去执行,这样就可以使多个 socket 的读写可以并行化了,采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),将最耗时的Socket的读取、请求解析、写入单独外包出去,剩下的命令执行仍然由主线程串行执行并和内存的数据交互。Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석
    结合上图可知,将网络数据读写、请求协议解析通过多个IO线程的来处理,对于真正的命令执行来说,仍然使用主线程操作(线程安全),是个不错的折中办法。因此,对于整个Redis来说是多线程的,但是对于工作线程(命令执行)仍旧是单线程

    3.3 工作流程

    核心流程大概如下:Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석
    流程简述如下:

    • 主线程获取 socket 放入等待列表
    • 将 socket 分配给各个 IO 线程(并不会等列表满)
    • 主线程阻塞等待 IO 线程(多线程)读取 socket 完毕
    • 主线程执行命令 - 单线程(如果命令没有接收完毕,会等 IO 下次继续)
    • 主线程阻塞等待 IO 线程(多线程)
    • flushall/flushdb async: 데이터베이스를 지우는 플러시all/flushdb 명령에 비동기 비동기 정리 옵션이 추가되어 데이터베이스를 지울 때 redis가 비동기식으로 작동합니다. 구현 로직은 데이터베이스에 대한 새로운 빈 사전을 생성하고 원래의 기존 데이터베이스 사전을 백그라운드 스레드에 제공하여 데이터를 하나씩 삭제하고 메모리를 해제하는 것입니다.

    삭제 작업은 백그라운드 하위 프로세스에 넘겨져 데이터를 비동기식으로 삭제합니다

    🎜🎜Redis는 단일 메인 스레드로 처리되기 때문에 Redis의 아버지인 Antirez는 항상 "Lazy Redis가 낫다"고 강조해왔습니다. Redis". 그리고 lazy free의 본질은 redis 메인 스레드에서 특정 비용(메인 시간 복제, 메인 스레드 CPU 타임 슬라이스 점유) 높은 삭제 작업을 제거하고 바이오를 하위 스레드가 이를 처리하므로 메인 스레드 차단 시간이 크게 줄어듭니다. 이렇게 하면 삭제로 인해 발생하는 성능 및 안정성 문제가 줄어듭니다. 🎜🎜Redis 4.0에서는 데이터의 비동기 지연 삭제와 같은 기능을 구현하기 위해 여러 스레드를 도입했지만 여전히 읽기 및 쓰기 요청을 처리하는 스레드가 하나뿐이므로 좁은 의미에서는 여전히 단일 스레드로 간주됩니다. 🎜🎜 이전 요약 분석: Redis의 주요 성능 병목 현상은 CPU보다는 메모리나 네트워크 대역폭입니다. 메모리 문제는 상대적으로 해결하기 쉽기 때문에 Redis의 병목 현상은 네트워크 IO입니다. 다음으로 멀티스레딩 모델이 소개됩니다. 🎜🎜🎜3.2 멀티스레딩의 작동 원리🎜🎜🎜I/O 읽기 및 쓰기 자체가 차단됩니다. 예를 들어 소켓에 데이터가 있는 경우입니다. , Redis는 먼저 호출을 통해 데이터를 커널 공간에서 사용자 공간으로 복사한 다음 호출을 위해 Redis로 전달합니다. 이 복사 프로세스는 데이터 양이 많으면 복사에 더 많은 시간이 걸립니다. , 이러한 작업은 단일 스레드에서 완료됩니다. Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석🎜🎜Redis 6.0에는 I/O 읽기 및 쓰기 성능을 향상시키기 위해 새로운 멀티스레딩 기능이 추가되었습니다🎜. 주요 구현 아이디어는 IO 읽기 및 쓰기 작업을 분할하는 것입니다. 메인 스레드 여러 소켓의 읽기 및 쓰기가 병렬화될 수 있도록 실행할 독립 스레드 그룹을 제공합니다. 다중 채널 I/O 다중화 기술을 사용하면 단일 스레드가 여러 연결 요청을 효율적으로 처리할 수 있습니다(네트워크 최소화). IO 시간 소비), 가장 시간이 많이 소요되는 소켓 읽기, 요청 구문 분석 및 쓰기는 별도로 아웃소싱되고 나머지 명령 실행은 여전히 ​​메인 스레드에 의해 직렬로 실행되며 메모리의 데이터와 상호 작용합니다. Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석
    위 그림에서 볼 수 있듯이 네트워크 데이터 읽기 및 쓰기와 요청 프로토콜 구문 분석은 실제 명령 실행을 위해 여전히 기본 스레드 작업을 사용합니다. (스레드 안전성)🎜은 좋은 절충안입니다. 따라서 전체 Redis에 대해서는 멀티 스레드이지만 작업자 스레드(명령 실행)에 대해서는 여전히 단일 스레드입니다. 🎜

    3.3 워크플로

    🎜핵심 프로세스는 다음과 같습니다. Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석
    과정을 간략하게 설명하면 다음과 같습니다. 🎜🎜마스터 스레드는 소켓을 획득하여 대기 목록에 넣습니다.🎜🎜각 IO 스레드에 소켓을 할당합니다(목록이 가득 찰 때까지 기다리지 않습니다)🎜🎜메인 스레드 는 IO 스레드를 차단하고 기다립니다. IO 스레드(멀티 스레드) 소켓 읽기가 완료되었습니다🎜🎜메인 스레드 실행 명령 - 싱글 스레드 (명령이 수신되지 않으면 다음에 IO가 계속될 때까지 기다립니다) 🎜🎜메인 스레드는 데이터를 다시 쓰기 위해 IO 스레드(멀티 스레드)를 기다리는 것을 차단합니다. 소켓이 완료되었습니다(한 번 완료되지 않으면 다음에 다시 작성됩니다)🎜🎜바인딩 해제 그리고 대기 대기열을 삭제하세요🎜🎜🎜🎜특징은 다음과 같습니다:🎜🎜
    • IO 스레드는 동시에 소켓을 읽거나 쓰는 중이며, 동시에 읽거나 쓰지는 않습니다.
    • IO 스레드는 소켓 구문 분석 명령을 읽고 쓰는 역할만 담당하며 명령은 담당하지 않습니다. 처리(메인 스레드는 명령을 순차적으로 실행)
    • IO 스레드 수는 자체 구성 가능(현재 코드 제한의 상한은 512이고 기본값은 1입니다(이 기능을 끕니다))

    관심 있는 사람들의 스트레스 테스트를 거친 후 현재 성능이 1배 이상 향상될 수 있습니다.

    질문 1: 대기자 명단이 꽉 차서 처리되지 않는 건가요?
    답변: Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석차단 시 감지되는 것은 IO 스레드에 아직 작업이 있는지 여부입니다. 계속하기 전에 처리가 완료될 때까지 기다리십시오. 이러한 작업은 실행 중에 추가됩니다. 작업 수가 스레드 수보다 작으면 일부 스레드는 작업을 가져올 수 없으며 보류 중인 작업은 0이 됩니다. 작업이 할당된 스레드가 IO 이벤트를 처리한 후에는 작업을 받지 못한 스레드의 보류가 원래 0이므로 차단되지 않습니다. 아직도 이에 대해 약간의 의구심이 있습니다. 누구든지 설명해 주실 수 있나요(코멘트)?

    3.4 멀티스레딩은 기본적으로 활성화되어 있나요?

    Redis6.0에서는 멀티스레딩 메커니즘이 기본적으로 꺼져 있습니다. 멀티스레딩 기능을 사용해야 하는 경우 redis.conf에서 두 가지 설정을 완료해야 합니다. Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석多线程机制默认是关闭的 ,如果需要使用多线程功能,需要在redis.conf中完成两个设置。Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석

    • 设置io-thread-do-reads配置项为yes,表示启动多线程。
    • 设置线程个数。关于线程数的设置,官方的建议是如果为 4 核的 CPU,建议线程数设置为 2 或 3, 如果为 8 核 CPU 建议线程数设置为 6 ,线程数一定要小于机器核数,线程数并不是越大越好。

    4. 总结

    Redis自身出道就是优秀,基于内存操作、数据结构简单、多路复用和非阻塞 I/O、避免了不必要的线程上下文切换等特性,在单线程的环境下依然很快;

    但对于大数据的 key 删除还是卡顿厉害,因此在 Redis 4.0 引入了多线程unlink key/flushall async 等命令,主要用于 Redis 数据的异步删除;

    而在 Redis 6.0 中引入了 I/O 多线程的读写,这样就可以更加高效的处理更多的任务了, Redis 只是将 I/O 读写变成了多线程 ,而 命令的执行依旧是由主线程串行执行的 ,因此在多线程下操作 Redis 不会出现线程安全的问题

    io-thread-do-reads 구성 항목을 yes로 설정합니다. 이는 여러 스레드를 시작한다는 의미입니다. 스레드 수를 설정하세요. 스레드 수 설정과 관련하여 공식적인 권장 사항은 4코어 CPU인 경우 스레드 수를 2 또는 3으로 설정하는 것이 좋습니다. 8코어 CPU인 경우, 스레드 수는 6으로 설정하는 것이 좋습니다. 스레드 수는 머신 코어 수보다 적어야 하며 스레드 수가 항상 더 좋은 것은 아닙니다.

    4. 요약

    Redis 자체는 메모리 연산, 간단한 데이터 구조, 멀티플렉싱 및 비차단 I/O, 불필요한 스레드 컨텍스트 전환 방지 및 기타 기능을 기반으로 데뷔 이후 탁월했습니다. 단일 스레드 환경에서는 여전히 매우 빠릅니다. 🎜🎜하지만 빅 데이터의 키 삭제는 여전히 매우 느리기 때문에 주로 비동기에 사용되는 다중 스레드 unlink key/flushall async 및 기타 명령이 Redis 4.0에 도입되었습니다. 🎜🎜Redis 6.0에는 I/O 멀티 스레드 읽기 및 쓰기가 도입되어 더 많은 작업을 보다 효율적으로 처리할 수 있습니다. I/O 읽기 및 쓰기를 멀티 스레딩으로 전환, 그리고 <code>명령 실행은 여전히 ​​메인 스레드에 의해 직렬로 실행되므로 다중 스레드에서 Redis를 작동할 때 스레드 안전 문제는 없습니다. 🎜🎜🎜Redis 원래의 단일 스레드 디자인이든, 원래 디자인에 반대되는 현재의 멀티 스레드 디자인이든, 목적은 단 하나입니다: Redis를 더 빠르고 빠르게 만드는 것입니다. 🎜🎜🎜더 많은 프로그래밍 관련 지식을 보려면 🎜프로그래밍 소개🎜를 방문하세요! ! 🎜

위 내용은 Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제