五月综合激情婷婷六月,日韩欧美国产一区不卡,他扒开我内裤强吻我下面视频 ,无套内射无矿码免费看黄,天天躁,日日躁,狠狠躁

新聞動(dòng)態(tài)

Redis線(xiàn)程模型的原理分析

發(fā)布日期:2022-02-02 17:06 | 文章來(lái)源:腳本之家

一、概述

眾所周知,Redis是一個(gè)高性能的數(shù)據(jù)存儲(chǔ)框架,在高并發(fā)的系統(tǒng)設(shè)計(jì)中,Redis也是一個(gè)比較關(guān)鍵的組件,是我們提升系統(tǒng)性能的一大利器。深入去理解Redis高性能的原理顯得越發(fā)重要,當(dāng)然Redis的高性能設(shè)計(jì)是一個(gè)系統(tǒng)性的工程,涉及到很多內(nèi)容,本文重點(diǎn)關(guān)注Redis的IO模型,以及基于IO模型的線(xiàn)程模型。

我們從IO的起源開(kāi)始,講述了阻塞IO、非阻塞IO、多路復(fù)用IO?;诙嗦窂?fù)用IO,我們也梳理了幾種不同的Reactor模型,并分析了幾種Reactor模型的優(yōu)缺點(diǎn)?;赗eactor模型我們開(kāi)始了Redis的IO模型和線(xiàn)程模型的分析,并總結(jié)出Redis線(xiàn)程模型的優(yōu)點(diǎn)、缺點(diǎn),以及后續(xù)的Redis多線(xiàn)程模型方案。本文的重點(diǎn)是對(duì)Redis線(xiàn)程模型設(shè)計(jì)思想的梳理,捋順了設(shè)計(jì)思想,就是一通百通的事了。

注:本文的代碼都是偽代碼,主要是為了示意,不可用于生產(chǎn)環(huán)境。

二、網(wǎng)絡(luò)IO模型發(fā)展史

我們常說(shuō)的網(wǎng)絡(luò)IO模型,主要包含阻塞IO、非阻塞IO、多路復(fù)用IO、信號(hào)驅(qū)動(dòng)IO、異步IO,本文重點(diǎn)關(guān)注跟Redis相關(guān)的內(nèi)容,所以我們重點(diǎn)分析阻塞IO、非阻塞IO、多路復(fù)用IO,幫助大家后續(xù)更好的理解Redis網(wǎng)絡(luò)模型。

我們先看下面這張圖;

2.1 阻塞IO

我們經(jīng)常說(shuō)的阻塞IO其實(shí)分為兩種,一種是單線(xiàn)程阻塞,一種是多線(xiàn)程阻塞。這里面其實(shí)有兩個(gè)概念,阻塞和線(xiàn)程。

  • 阻塞:指調(diào)用結(jié)果返回之前,當(dāng)前線(xiàn)程會(huì)被掛起,調(diào)用線(xiàn)程只有在得到結(jié)果之后才會(huì)返回;
  • 線(xiàn)程:系統(tǒng)調(diào)用的線(xiàn)程個(gè)數(shù)。

像建立連接、讀、寫(xiě)都涉及到系統(tǒng)調(diào)用,本身是一個(gè)阻塞的操作。

2.1.1 單線(xiàn)程阻塞

服務(wù)端單線(xiàn)程來(lái)處理,當(dāng)客戶(hù)端請(qǐng)求來(lái)臨時(shí),服務(wù)端用主線(xiàn)程來(lái)處理連接、讀取、寫(xiě)入等操作。

以下用代碼模擬了單線(xiàn)程的阻塞模式;

import java.net.Socket;
 
public class BioTest {
 
    public static void main(String[] args) throws IOException {
        ServerSocket server=new ServerSocket(8081);
        while(true) {
            Socket socket=server.accept();
            System.out.println("accept port:"+socket.getPort());
            BufferedReader  in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String inData=null;
            try {
                while ((inData = in.readLine()) != null) {
                    System.out.println("client port:"+socket.getPort());
                    System.out.println("input data:"+inData);
                    if("close".equals(inData)) {socket.close();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }      
        }
    }
}

我們準(zhǔn)備用兩個(gè)客戶(hù)端同時(shí)發(fā)起連接請(qǐng)求、來(lái)模擬單線(xiàn)程阻塞模式的現(xiàn)象。同時(shí)發(fā)起連接,通過(guò)服務(wù)端日志,我們發(fā)現(xiàn)此時(shí)服務(wù)端只接受了其中一個(gè)連接,主線(xiàn)程被阻塞在上一個(gè)連接的read方法上。

我們嘗試關(guān)閉第一個(gè)連接,看第二個(gè)連接的情況,我們希望看到的現(xiàn)象是,主線(xiàn)程返回,新的客戶(hù)端連接被接受。

從日志中發(fā)現(xiàn),在第一個(gè)連接被關(guān)閉后,第二個(gè)連接的請(qǐng)求被處理了,也就是說(shuō)第二個(gè)連接請(qǐng)求在排隊(duì),直到主線(xiàn)程被喚醒,才能接收下一個(gè)請(qǐng)求,符合我們的預(yù)期。

此時(shí)不僅要問(wèn),為什么呢?

主要原因在于accept、read、write三個(gè)函數(shù)都是阻塞的,主線(xiàn)程在系統(tǒng)調(diào)用的時(shí)候,線(xiàn)程是被阻塞的,其他客戶(hù)端的連接無(wú)法被響應(yīng)。

通過(guò)以上流程,我們很容易發(fā)現(xiàn)這個(gè)過(guò)程的缺陷,服務(wù)器每次只能處理一個(gè)連接請(qǐng)求,CPU沒(méi)有得到充分利用,性能比較低。如何充分利用CPU的多核特性呢?自然而然的想到了——多線(xiàn)程邏輯。

2.1.2 多線(xiàn)程阻塞

對(duì)工程師而言,代碼解釋一切,直接上代碼。

BIO多線(xiàn)程

package net.io.bio;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
 
public class BioTest {
 
    public static void main(String[] args) throws IOException {
        final ServerSocket server=new ServerSocket(8081);
        while(true) {
            new Thread(new Runnable() {
                public void run() {
                    Socket socket=null;
                    try {socket = server.accept();System.out.println("accept port:"+socket.getPort());BufferedReader  in=new BufferedReader(new InputStreamReader(socket.getInputStream()));String inData=null;while ((inData = in.readLine()) != null) {
System.out.println("client port:"+socket.getPort());
System.out.println("input data:"+inData);
if("close".equals(inData)) {
    socket.close();
}}
                    } catch (IOException e) {e.printStackTrace();
                    } finally { 
                    }
                }
            }).start();
        }
    }
 
}

同樣,我們并行發(fā)起兩個(gè)請(qǐng)求;

兩個(gè)請(qǐng)求,都被接受,服務(wù)端新增兩個(gè)線(xiàn)程來(lái)處理客戶(hù)端的連接和后續(xù)請(qǐng)求。

我們用多線(xiàn)程解決了,服務(wù)器同時(shí)只能處理一個(gè)請(qǐng)求的問(wèn)題,但同時(shí)又帶來(lái)了一個(gè)問(wèn)題,如果客戶(hù)端連接比較多時(shí),服務(wù)端會(huì)創(chuàng)建大量的線(xiàn)程來(lái)處理請(qǐng)求,但線(xiàn)程本身是比較耗資源的,創(chuàng)建、上下文切換都比較耗資源,又如何去解決呢?

2.2 非阻塞

如果我們把所有的Socket(文件句柄,后續(xù)用Socket來(lái)代替fd的概念,盡量減少概念,減輕閱讀負(fù)擔(dān))都放到隊(duì)列里,只用一個(gè)線(xiàn)程來(lái)輪訓(xùn)所有的Socket的狀態(tài),如果準(zhǔn)備好了就把它拿出來(lái),是不是就減少了服務(wù)端的線(xiàn)程數(shù)呢?

一起看下代碼,單純非阻塞模式,我們基本上不用,為了演示邏輯,我們模擬了相關(guān)代碼如下;

package net.io.bio;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
 
import org.apache.commons.collections4.CollectionUtils;
 
 
public class NioTest {
 
    public static void main(String[] args) throws IOException {
        final ServerSocket server=new ServerSocket(8082);
        server.setSoTimeout(1000);
        List<Socket> sockets=new ArrayList<Socket>();
        while (true) {
            Socket socket = null;
            try {
                socket = server.accept();
                socket.setSoTimeout(500);
                sockets.add(socket);
                System.out.println("accept client port:"+socket.getPort());
            } catch (SocketTimeoutException e) {
                System.out.println("accept timeout");
            }
            //模擬非阻塞:輪詢(xún)已連接的socket,每個(gè)socket等待10MS,有數(shù)據(jù)就處理,無(wú)數(shù)據(jù)就返回,繼續(xù)輪詢(xún)
            if(CollectionUtils.isNotEmpty(sockets)) {
                for(Socket socketTemp:sockets ) {
                    try {BufferedReader  in=new BufferedReader(new InputStreamReader(socketTemp.getInputStream()));String inData=null;while ((inData = in.readLine()) != null) {
System.out.println("input data client port:"+socketTemp.getPort());
System.out.println("input data client port:"+socketTemp.getPort() +"data:"+inData);
if("close".equals(inData)) {
    socketTemp.close();
}}
                    } catch (SocketTimeoutException e) {System.out.println("input client loop"+socketTemp.getPort());
                    }
                }
            }
        }
 
    }
}

系統(tǒng)初始化,等待連接;

發(fā)起兩個(gè)客戶(hù)端連接,線(xiàn)程開(kāi)始輪詢(xún)兩個(gè)連接中是否有數(shù)據(jù)。

兩個(gè)連接分別輸入數(shù)據(jù)后,輪詢(xún)線(xiàn)程發(fā)現(xiàn)有數(shù)據(jù)準(zhǔn)備好了,開(kāi)始相關(guān)的邏輯處理(單線(xiàn)程、多線(xiàn)程都可)。

再用一張流程圖輔助解釋下(系統(tǒng)實(shí)際采用文件句柄,此時(shí)用Socket來(lái)代替,方便大家理解)。

服務(wù)端專(zhuān)門(mén)有一個(gè)線(xiàn)程來(lái)負(fù)責(zé)輪詢(xún)所有的Socket,來(lái)確認(rèn)操作系統(tǒng)是否完成了相關(guān)事件,如果有則返回處理,如果無(wú)繼續(xù)輪詢(xún),大家一起來(lái)思考下?此時(shí)又帶來(lái)了什么問(wèn)題呢。

CPU的空轉(zhuǎn)、系統(tǒng)調(diào)用(每次輪詢(xún)到涉及到一次系統(tǒng)調(diào)用,通過(guò)內(nèi)核命令來(lái)確認(rèn)數(shù)據(jù)是否準(zhǔn)備好),造成資源的浪費(fèi),那有沒(méi)有一種機(jī)制,來(lái)解決這個(gè)問(wèn)題呢?

2.3 IO多路復(fù)用

server端有沒(méi)專(zhuān)門(mén)的線(xiàn)程來(lái)做輪詢(xún)操作(應(yīng)用程序端非內(nèi)核),而是由事件來(lái)觸發(fā),當(dāng)有相關(guān)讀、寫(xiě)、連接事件到來(lái)時(shí),主動(dòng)喚起服務(wù)端線(xiàn)程來(lái)進(jìn)行相關(guān)邏輯處理。模擬了相關(guān)代碼如下;

IO多路復(fù)用

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
 
public class NioServer {
 
    private static  Charset charset = Charset.forName("UTF-8");
    public static void main(String[] args) {
        try {
            Selector selector = Selector.open();
            ServerSocketChannel chanel = ServerSocketChannel.open();
            chanel.bind(new InetSocketAddress(8083));
            chanel.configureBlocking(false);
            chanel.register(selector, SelectionKey.OP_ACCEPT);
 
            while (true){
                int select = selector.select();
                if(select == 0){
                    System.out.println("select loop");
                    continue;
                }
                System.out.println("os data ok");
                 
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()){
                    SelectionKey selectionKey = iterator.next();
                     
                    if(selectionKey.isAcceptable()){ServerSocketChannel server = (ServerSocketChannel)selectionKey.channel();SocketChannel client = server.accept();client.configureBlocking(false);client.register(selector, SelectionKey.OP_READ);//繼續(xù)可以接收連接事件selectionKey.interestOps(SelectionKey.OP_ACCEPT);
                    }else if(selectionKey.isReadable()){//得到SocketChannelSocketChannel client = (SocketChannel)selectionKey.channel();//定義緩沖區(qū)ByteBuffer buffer = ByteBuffer.allocate(1024);StringBuilder content = new StringBuilder();while (client.read(buffer) > 0){
buffer.flip();
content.append(charset.decode(buffer));}System.out.println("client port:"+client.getRemoteAddress().toString()+",input data: "+content.toString());//清空緩沖區(qū)buffer.clear();
                    }
                    iterator.remove();
                }
            }
 
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

同時(shí)創(chuàng)建兩個(gè)連接;

兩個(gè)連接無(wú)阻塞的被創(chuàng)建;

無(wú)阻塞的接收讀寫(xiě);

再用一張流程圖輔助解釋下(系統(tǒng)實(shí)際采用文件句柄,此時(shí)用Socket來(lái)代替,方便大家理解)。

當(dāng)然操作系統(tǒng)的多路復(fù)用有好幾種實(shí)現(xiàn)方式,我們經(jīng)常使用的select(),epoll模式這里不做過(guò)多的解釋?zhuān)信d趣的可以查看相關(guān)文檔,IO的發(fā)展后面還有異步、事件等模式,我們?cè)谶@里不過(guò)多的贅述,我們更多的是為了解釋Redis線(xiàn)程模式的發(fā)展。

三、NIO線(xiàn)程模型解釋

我們一起來(lái)聊了阻塞、非阻塞、IO多路復(fù)用模式,那Redis采用的是哪種呢?

Redis采用的是IO多路復(fù)用模式,所以我們重點(diǎn)來(lái)了解下多路復(fù)用這種模式,如何在更好的落地到我們系統(tǒng)中,不可避免的我們要聊下Reactor模式。

首先我們做下相關(guān)的名詞解釋?zhuān)?/p>

Reactor:類(lèi)似NIO編程中的Selector,負(fù)責(zé)I/O事件的派發(fā);

Acceptor:NIO中接收到事件后,處理連接的那個(gè)分支邏輯;

Handler:消息讀寫(xiě)處理等操作類(lèi)。

3.1 單Reactor單線(xiàn)程模型

處理流程

  • Reactor監(jiān)聽(tīng)連接事件、Socket事件,當(dāng)有連接事件過(guò)來(lái)時(shí)交給Acceptor處理,當(dāng)有Socket事件過(guò)來(lái)時(shí)交個(gè)對(duì)應(yīng)的Handler處理。

優(yōu)點(diǎn)

  • 模型比較簡(jiǎn)單,所有的處理過(guò)程都在一個(gè)連接里;
  • 實(shí)現(xiàn)上比較容易,模塊功能也比較解耦,Reactor負(fù)責(zé)多路復(fù)用和事件分發(fā)處理,Acceptor負(fù)責(zé)連接事件處理,Handler負(fù)責(zé)Scoket讀寫(xiě)事件處理。

缺點(diǎn)

  • 只有一個(gè)線(xiàn)程,連接處理和業(yè)務(wù)處理共用一個(gè)線(xiàn)程,無(wú)法充分利用CPU多核的優(yōu)勢(shì)。
  • 在流量不是特別大、業(yè)務(wù)處理比較快的時(shí)候系統(tǒng)可以有很好的表現(xiàn),當(dāng)流量比較大、讀寫(xiě)事件比較耗時(shí)情況下,容易導(dǎo)致系統(tǒng)出現(xiàn)性能瓶頸。

怎么去解決上述問(wèn)題呢?既然業(yè)務(wù)處理邏輯可能會(huì)影響系統(tǒng)瓶頸,那我們是不是可以把業(yè)務(wù)處理邏輯單拎出來(lái),交給線(xiàn)程池來(lái)處理,一方面減小對(duì)主線(xiàn)程的影響,另一方面利用CPU多核的優(yōu)勢(shì)。這一點(diǎn)希望大家要理解透徹,方便我們后續(xù)理解Redis由單線(xiàn)程模型到多線(xiàn)程模型的設(shè)計(jì)的思路。

3.2 單Reactor多線(xiàn)程模型

這種模型相對(duì)單Reactor單線(xiàn)程模型,只是將業(yè)務(wù)邏輯的處理邏輯交給了一個(gè)線(xiàn)程池來(lái)處理。

處理流程

  • Reactor監(jiān)聽(tīng)連接事件、Socket事件,當(dāng)有連接事件過(guò)來(lái)時(shí)交給Acceptor處理,當(dāng)有Socket事件過(guò)來(lái)時(shí)交個(gè)對(duì)應(yīng)的Handler處理。
  • Handler完成讀事件后,包裝成一個(gè)任務(wù)對(duì)象,交給線(xiàn)程池來(lái)處理,把業(yè)務(wù)處理邏輯交給其他線(xiàn)程來(lái)處理。

優(yōu)點(diǎn)

  • 讓主線(xiàn)程專(zhuān)注于通用事件的處理(連接、讀、寫(xiě)),從設(shè)計(jì)上進(jìn)一步解耦;
  • 利用CPU多核的優(yōu)勢(shì)。

缺點(diǎn)

  • 貌似這種模型已經(jīng)很完美了,我們?cè)偎伎枷?,如果客?hù)端很多、流量特別大的時(shí)候,通用事件的處理(讀、寫(xiě))也可能會(huì)成為主線(xiàn)程的瓶頸,因?yàn)槊看巫x、寫(xiě)操作都涉及系統(tǒng)調(diào)用。

有沒(méi)有什么好的辦法來(lái)解決上述問(wèn)題呢?通過(guò)以上的分析,大家有沒(méi)有發(fā)現(xiàn)一個(gè)現(xiàn)象,當(dāng)某一個(gè)點(diǎn)成為系統(tǒng)瓶頸點(diǎn)時(shí),想辦法把他拿出來(lái),交個(gè)其他線(xiàn)程來(lái)處理,那這種場(chǎng)景是否適用呢?

3.3 多Reactor多線(xiàn)程模型

這種模型相對(duì)單Reactor多線(xiàn)程模型,只是將Scoket的讀寫(xiě)處理從mainReactor中拎出來(lái),交給subReactor線(xiàn)程來(lái)處理。

處理流程

  • mainReactor主線(xiàn)程負(fù)責(zé)連接事件的監(jiān)聽(tīng)和處理,當(dāng)Acceptor處理完連接過(guò)程后,主線(xiàn)程將連接分配給subReactor;
  • subReactor負(fù)責(zé)mainReactor分配過(guò)來(lái)的Socket的監(jiān)聽(tīng)和處理,當(dāng)有Socket事件過(guò)來(lái)時(shí)交個(gè)對(duì)應(yīng)的Handler處理;

Handler完成讀事件后,包裝成一個(gè)任務(wù)對(duì)象,交給線(xiàn)程池來(lái)處理,把業(yè)務(wù)處理邏輯交給其他線(xiàn)程來(lái)處理。

優(yōu)點(diǎn)

  • 讓主線(xiàn)程專(zhuān)注于連接事件的處理,子線(xiàn)程專(zhuān)注于讀寫(xiě)事件吹,從設(shè)計(jì)上進(jìn)一步解耦;
  • 利用CPU多核的優(yōu)勢(shì)。

缺點(diǎn)

  • 實(shí)現(xiàn)上會(huì)比較復(fù)雜,在極度追求單機(jī)性能的場(chǎng)景中可以考慮使用。

四、Redis的線(xiàn)程模型

4.1 概述

以上我們聊了,IO網(wǎng)路模型的發(fā)展歷史,也聊了IO多路復(fù)用的reactor模式。那Redis采用的是哪種reactor模式呢?在回答這個(gè)問(wèn)題前,我們先梳理幾個(gè)概念性的問(wèn)題。

Redis服務(wù)器中有兩類(lèi)事件,文件事件和時(shí)間事件。

  • 文件事件:在這里可以把文件理解為Socket相關(guān)的事件,比如連接、讀、寫(xiě)等;
  • 時(shí)間時(shí)間:可以理解為定時(shí)任務(wù)事件,比如一些定期的RDB持久化操作。

本文重點(diǎn)聊下Socket相關(guān)的事件。

4.2 模型圖

首先我們來(lái)看下Redis服務(wù)的線(xiàn)程模型圖;

IO多路復(fù)用負(fù)責(zé)各事件的監(jiān)聽(tīng)(連接、讀、寫(xiě)等),當(dāng)有事件發(fā)生時(shí),將對(duì)應(yīng)事件放入隊(duì)列中,由事件分發(fā)器根據(jù)事件類(lèi)型來(lái)進(jìn)行分發(fā);

如果是連接事件,則分發(fā)至連接應(yīng)答處理器;GET、SET等redis命令分發(fā)至命令請(qǐng)求處理器。

命令處理完后產(chǎn)生命令回復(fù)事件,再由事件隊(duì)列,到事件分發(fā)器,到命令回復(fù)處理器,回復(fù)客戶(hù)端響應(yīng)。

4.3 一次客戶(hù)端和服務(wù)端的交互流程

4.3.1 連接流程

連接過(guò)程

  • Redis服務(wù)端主線(xiàn)程監(jiān)聽(tīng)固定端口,并將連接事件綁定連接應(yīng)答處理器。
  • 客戶(hù)端發(fā)起連接后,連接事件被觸發(fā),IO多路復(fù)用程序?qū)⑦B接事件包裝好后丟人事件隊(duì)列,然后由事件分發(fā)處理器分發(fā)給連接應(yīng)答處理器。
  • 連接應(yīng)答處理器創(chuàng)建client對(duì)象以及Socket對(duì)象,我們這里關(guān)注Socket對(duì)象,并產(chǎn)生ae_readable事件,和命令處理器關(guān)聯(lián),標(biāo)識(shí)后續(xù)該Socket對(duì)可讀事件感興趣,也就是開(kāi)始接收客戶(hù)端的命令操作。
  • 當(dāng)前過(guò)程都是由一個(gè)主線(xiàn)程負(fù)責(zé)處理。

4.3.2 命令執(zhí)行流程

SET命令執(zhí)行過(guò)程

  • 客戶(hù)端發(fā)起SET命令,IO多路復(fù)用程序監(jiān)聽(tīng)到該事件后(讀事件),將數(shù)據(jù)包裝成事件丟到事件隊(duì)列中(事件在上個(gè)流程中綁定了命令請(qǐng)求處理器);
  • 事件分發(fā)處理器根據(jù)事件類(lèi)型,將事件分發(fā)給對(duì)應(yīng)的命令請(qǐng)求處理器;
  • 命令請(qǐng)求處理器,讀取Socket中的數(shù)據(jù),執(zhí)行命令,然后產(chǎn)生ae_writable事件,并綁定命令回復(fù)處理器;
  • IO多路復(fù)用程序監(jiān)聽(tīng)到寫(xiě)事件后,將數(shù)據(jù)包裝成事件丟到事件隊(duì)列中,事件分發(fā)處理器根據(jù)事件類(lèi)型分發(fā)至命令回復(fù)處理器;
  • 命令回復(fù)處理器,將數(shù)據(jù)寫(xiě)入Socket中返回給客戶(hù)端。

4.4 模型優(yōu)缺點(diǎn)

以上流程分析我們可以看出Redis采用的是單線(xiàn)程Reactor模型,我們也分析了這種模式的優(yōu)缺點(diǎn),那Redis為什么還要采用這種模式呢?

Redis本身的特性

命令執(zhí)行基于內(nèi)存操作,業(yè)務(wù)處理邏輯比較快,所以命令處理這一塊單線(xiàn)程來(lái)做也能維持一個(gè)很高的性能。

優(yōu)點(diǎn)

  • Reactor單線(xiàn)程模型的優(yōu)點(diǎn),參考上文。

缺點(diǎn)

  • Reactor單線(xiàn)程模型的缺點(diǎn)也同樣在Redis中來(lái)體現(xiàn),唯一不同的地方就在于業(yè)務(wù)邏輯處理(命令執(zhí)行)這塊不是系統(tǒng)瓶頸點(diǎn)。
  • 隨著流量的上漲,IO操作的的耗時(shí)會(huì)越來(lái)越明顯(read操作,內(nèi)核中讀數(shù)據(jù)到應(yīng)用程序。write操作,應(yīng)用程序中的數(shù)據(jù)到內(nèi)核),當(dāng)達(dá)到一定閥值時(shí)系統(tǒng)的瓶頸就體現(xiàn)出來(lái)了。

Redis又是如何去解的呢?

哈哈~將耗時(shí)的點(diǎn)從主線(xiàn)程拎出來(lái)唄?那Redis的新版本是這么做的嗎?我們一起來(lái)看下。

4.5 Redis多線(xiàn)程模式

Redis的多線(xiàn)程模型跟”多Reactor多線(xiàn)程模型“、“單Reactor多線(xiàn)程模型有點(diǎn)區(qū)別”,但同時(shí)用了兩種Reactor模型的思想,具體如下;

  • Redis的多線(xiàn)程模型是將IO操作多線(xiàn)程化,本身邏輯處理過(guò)程(命令執(zhí)行過(guò)程)依舊是單線(xiàn)程,借助了單Reactor思想,實(shí)現(xiàn)上又有所區(qū)分。
  • 將IO操作多線(xiàn)程化,又跟單Reactor衍生出多Reactor的思想一致,都是將IO操作從主線(xiàn)程中拎出來(lái)。

命令執(zhí)行大致流程

  • 客戶(hù)端發(fā)送請(qǐng)求命令,觸發(fā)讀就緒事件,服務(wù)端主線(xiàn)程將Socket(為了簡(jiǎn)化理解成本,統(tǒng)一用Socket來(lái)代表連接)放入一個(gè)隊(duì)列,主線(xiàn)程不負(fù)責(zé)讀;
  • IO 線(xiàn)程通過(guò)Socket讀取客戶(hù)端的請(qǐng)求命令,主線(xiàn)程忙輪詢(xún),等待所有 I/O 線(xiàn)程完成讀取任務(wù),IO線(xiàn)程只負(fù)責(zé)讀不負(fù)責(zé)執(zhí)行命令;
  • 主線(xiàn)程一次性執(zhí)行所有命令,執(zhí)行過(guò)程和單線(xiàn)程一樣,然后需要返回的連接放入另外一個(gè)隊(duì)列中,有IO線(xiàn)程來(lái)負(fù)責(zé)寫(xiě)出(主線(xiàn)程也會(huì)寫(xiě));
  • 主線(xiàn)程忙輪詢(xún),等待所有 I/O 線(xiàn)程完成寫(xiě)出任務(wù)。

五、總結(jié)

了解一個(gè)組件,更多的是要去了解他的設(shè)計(jì)思路,要去思考為什么要這么設(shè)計(jì),做這種技術(shù)選型的背景是啥,對(duì)后續(xù)做系統(tǒng)架構(gòu)設(shè)計(jì)有什么參考意義等等。一通百通,希望對(duì)大家有參考意義。

到此這篇關(guān)于Redis線(xiàn)程模型的原理分析的文章就介紹到這了,更多相關(guān)Redis線(xiàn)程模型內(nèi)容請(qǐng)搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!

香港快速服務(wù)器

版權(quán)聲明:本站文章來(lái)源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來(lái)源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非maisonbaluchon.cn所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來(lái)源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來(lái),僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。

相關(guān)文章

實(shí)時(shí)開(kāi)通

自選配置、實(shí)時(shí)開(kāi)通

免備案

全球線(xiàn)路精選!

全天候客戶(hù)服務(wù)

7x24全年不間斷在線(xiàn)

專(zhuān)屬顧問(wèn)服務(wù)

1對(duì)1客戶(hù)咨詢(xún)顧問(wèn)

在線(xiàn)
客服

在線(xiàn)客服:7*24小時(shí)在線(xiàn)

客服
熱線(xiàn)

400-630-3752
7*24小時(shí)客服服務(wù)熱線(xiàn)

關(guān)注
微信

關(guān)注官方微信
頂部