이 기사에서는 Redis6의 스레드 모델을 이해하고 단일 스레드 모델과 다중 스레드 모델을 소개합니다. 모든 사람에게 도움이 되기를 바랍니다.
단순히 Redis가 단일 스레드 또는 다중 스레드라고 말하면 이 답변은 확실히 다른 버전에서 사용되는 스레딩 모델이 다릅니다. [관련 권장사항: Redis 동영상 튜토리얼]
버전 3.x, 입소문이 심한 Redis는 싱글스레드입니다.
버전 4.x는 엄밀히 말하면 싱글 쓰레드가 아닌, 클라이언트 요청 처리를 담당하는 쓰레드가 싱글 쓰레드인데, 일부 멀티 쓰레드(비동기 삭제) . <code>多线程的东西(异步删除)
。
最新版本的6.0.x后, 告别了大家印象中的单线程,用一种全新的多线程
来解决问题。
2.1 单线程真实含义
主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。
但Redis的其他功能, 比如持久化、异步删除、集群数据同步等等,其实是由额外的线程
整个Redis来说,是多线程的
;
2.2 单线程性能快原因
Redis 3.x 单线程时代但是性能很快的主要原因
:
o(1)
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.1 단일 스레드
🎜의 진정한 의미는 주로 Redis의 네트워크 IO와 키-값 쌍 읽기 및 쓰기가 하나의 스레드로 완료된다는 의미이며, Redis는 고객의 획득(소켓 읽기), 구문 분석, 실행, 콘텐츠 반환(소켓 쓰기) 등을 포함한 클라이언트의 요청을 모두 순차 및 직렬 메인 스레드로 처리합니다. 이를 소위 "단일 스레드"라고 합니다. ". 이는 Redis가 외부 키-값 스토리지 서비스를 제공하는 주요 프로세스이기도 합니다.추가 스레드
에 의해 실행됩니다.
Redis 작업자 스레드는 단일 스레드라고 할 수 있습니다. 그러나 전체 Redis는 멀티 스레드
입니다. 🎜🎜🎜🎜2.2 단일 스레드 성능이 빠른 주된 이유🎜🎜🎜🎜Redis 3.x는 단일 스레드이지만 성능이 빠릅니다 :🎜o(1)
🎜🎜다중화 및 차단 IO: IO 다중화 기능을 사용하여 클라이언트에 대한 여러 소켓 연결을 모니터링합니다. 이 방법으로 하나의 스레드 연결을 사용하여 여러 요청을 처리하고 스레드 전환으로 인한 오버헤드를 줄이면서 IO 차단 작업을 피할 수 있습니다🎜🎜컨텍스트 전환 방지: 단일 스레드 모델이므로 불필요한 컨텍스트 전환 및 멀티스레딩을 피할 수 있습니다. 다중 스레드 전환으로 인한 시간 및 성능 소모를 절약할 수 있으며 단일 스레드로 인해 교착 상태 문제가 발생하지 않습니다🎜🎜🎜🎜🎜2.3 단일 스레드를 사용하는 이유🎜🎜🎜🎜Redis는 메모리 작업을 기반으로 하므로 병목 현상이 CPU보다는 머신의 메모리나 네트워크 대역폭. CPU는 병목 현상이 아니기 때문에 단일 스레드 솔루션을 사용하는 것이 당연하고 다중 스레드를 사용하는 것이 더 번거롭습니다. 하지만 Redis 4.0부터 백그라운드 삭제, 기타 기능 등 멀티스레딩
을 지원하기 시작했습니다. 既然单线程那么好,为啥又要引入多线程?
단일 스레드에도 큰 키 삭제 문제와 같은 자체적인 문제가 있습니다.
일반적인 상황에서는 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 调用,而这个拷贝的过程就是阻塞的,当数据量越大时拷贝所需要的时间就越多,而这些操作都是基于单线程完成的。
在 Redis 6.0 中新增了多线程的功能来提高 I/O 的读写性能,他的主要实现思路是将主线程的 IO 读写任务拆分给一组独立的线程去执行,这样就可以使多个 socket 的读写可以并行化了,采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),将最耗时的Socket的读取、请求解析、写入单独外包出去,剩下的命令执行仍然由主线程串行执行并和内存的数据交互。
结合上图可知,将网络数据读写、请求协议解析通过多个IO线程的来处理,对于真正的命令执行来说,仍然使用主线程操作(线程安全),是个不错的折中办法。因此,对于整个Redis来说是多线程的,但是对于工作线程(命令执行)仍旧是单线程
。
核心流程大概如下:
流程简述如下:
阻塞等待 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로 전달합니다. 이 복사 프로세스는 데이터 양이 많으면 복사에 더 많은 시간이 걸립니다. , 이러한 작업은 단일 스레드에서 완료됩니다. 🎜🎜Redis 6.0에는 I/O 읽기 및 쓰기 성능을 향상시키기 위해 새로운 멀티스레딩 기능이 추가되었습니다🎜. 주요 구현 아이디어는 IO 읽기 및 쓰기 작업을 분할하는 것입니다. 메인 스레드 여러 소켓의 읽기 및 쓰기가 병렬화될 수 있도록 실행할 독립 스레드 그룹을 제공합니다. 다중 채널 I/O 다중화 기술을 사용하면 단일 스레드가 여러 연결 요청을 효율적으로 처리할 수 있습니다(네트워크 최소화). IO 시간 소비), 가장 시간이 많이 소요되는 소켓 읽기, 요청 구문 분석 및 쓰기는 별도로 아웃소싱되고 나머지 명령 실행은 여전히 메인 스레드에 의해 직렬로 실행되며 메모리의 데이터와 상호 작용합니다. 전체 Redis에 대해서는 멀티 스레드이지만 작업자 스레드(명령 실행)에 대해서는 여전히 단일 스레드입니다
. 🎜는 IO 스레드를 차단하고 기다립니다. IO 스레드(멀티 스레드)
소켓 읽기가 완료되었습니다🎜🎜메인 스레드 실행 명령 - 싱글 스레드
(명령이 수신되지 않으면 다음에 IO가 계속될 때까지 기다립니다) 🎜🎜메인 스레드는 데이터를 다시 쓰기 위해 IO 스레드(멀티 스레드)를 기다리는 것을 차단
합니다. 소켓이 완료되었습니다(한 번 완료되지 않으면 다음에 다시 작성됩니다)🎜🎜바인딩 해제 그리고 대기 대기열을 삭제하세요🎜🎜🎜🎜특징은 다음과 같습니다:🎜🎜관심 있는 사람들의 스트레스 테스트를 거친 후 현재 성능이 1배 이상 향상될 수 있습니다.
질문 1: 대기자 명단이 꽉 차서 처리되지 않는 건가요?
답변: 차단 시 감지되는 것은 IO 스레드에 아직 작업이 있는지 여부입니다. 계속하기 전에 처리가 완료될 때까지 기다리십시오. 이러한 작업은 실행 중에 추가됩니다. 작업 수가 스레드 수보다 작으면 일부 스레드는 작업을 가져올 수 없으며 보류 중인 작업은 0이 됩니다. 작업이 할당된 스레드가 IO 이벤트를 처리한 후에는 작업을 받지 못한 스레드의 보류가 원래 0이므로 차단되지 않습니다. 아직도 이에 대해 약간의 의구심이 있습니다. 누구든지 설명해 주실 수 있나요(코멘트)?
3.4 멀티스레딩은 기본적으로 활성화되어 있나요?
Redis6.0에서는 멀티스레딩 메커니즘이 기본적으로 꺼져 있습니다
. 멀티스레딩 기능을 사용해야 하는 경우 redis.conf에서 두 가지 설정을 완료해야 합니다. 多线程机制默认是关闭的
,如果需要使用多线程功能,需要在redis.conf中完成两个设置。
如果为 8 核 CPU 建议线程数设置为 6
,线程数一定要小于机器核数,线程数并不是越大越好。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
으로 설정하는 것이 좋습니다. 스레드 수는 머신 코어 수보다 적어야 하며 스레드 수가 항상 더 좋은 것은 아닙니다.
I/O 읽기 및 쓰기를 멀티 스레딩으로 전환, 그리고 <code>명령 실행은 여전히 메인 스레드에 의해 직렬로 실행
되므로 다중 스레드에서 Redis를 작동할 때 스레드 안전 문제
는 없습니다. 🎜🎜🎜Redis 원래의 단일 스레드 디자인이든, 원래 디자인에 반대되는 현재의 멀티 스레드 디자인이든, 목적은 단 하나입니다: Redis를 더 빠르고 빠르게 만드는 것입니다. 🎜🎜🎜더 많은 프로그래밍 관련 지식을 보려면 🎜프로그래밍 소개🎜를 방문하세요! ! 🎜
위 내용은 Redis6의 단일 스레드 및 다중 스레드 모델에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!