Redis它是一个单线程的,这一点需要去注意的。
首先我们呢会有一个客户端,这个客户端在我们之前其实使用的是一个redis client 这样的一个工具去连接的redis server。
如果说我们后续再整合到java 里面去的话,在java 里面其实也会提供相应的客户端的。
随后我们会有一个redis server,这个其实就是我们的一个redis,它整个服务在启动以后,它是会有一个进程的。
在我们的release 里面,在内部它其实会有两个东西。
首先一个它会有一个多路复用器,这个我们上节课已经是介绍过了,它是非阻塞的一个模型。
随后它其实还会有一个文件事件分配器,它专门是用于去分配一些事件的。
在这个下面,它会分为三个不同的处理器,分别来看一下。
首先呢有一个连接应答处理器,最后的是一个命令请求处理器,还有是一个命令回复处理器。
如何去理解呢?首先我们先来看一个连接应答处理器。
连接应答处理器的话,它的一个主要作用是要和我们的客户端去保持一个链接。
像我们的一个redis server一旦启动了以后,其实呢我们就会有read 的这样的一个事件和我们的连接应答器会捆绑到一起。
它的全称其实叫做AE_readable。你就可以把它理解为是一种标志啊,它会有这样的一个事件,这个事件是会和我们的连接应答处理器捆绑到一起的。
最后当我们的一个客户端和咱们的server 要去建立连接的时候,这个其实也就是我们在一开始在命令行工具里面敲下了一个redis client,一开始的话肯定是需要和我们的server 去建立连接嘛。建立连接的时候,他其实就会发送一个read 标志,其实就是一个read 的时间,这个时候的话,在我们的redis server 里面,它其实会有一个叫做server socket。
server socket 和我们的一个客户端socket 其实是对应的,他们是属于网络编程里面的一块内容,他们之间是一个socket 的通信。在我们接触到read 这样的一个事件了以后,随后我们呢就会交由咱们的多路复用器去进行处理吧。
交给他去处理以后的话,其实他是一个非阻塞的,拿到了以后一旦接收,他就会把它放到我们这样的一个箭头里面去。
这个箭头的话在这边其实我们可以称之为它是一个管道pipeline,或者我们也可以把它称之为是一个队列。它会往这里面丢,丢进去以后,这个世界呢其实就会到达我们的文件事件分配器。这个分配器当它识别到它是一个read 这样的事件以后,它就会和我们的这个连接应答处理器去做到一个匹配,也就是交由它去进行一个处理。
它是一个read 相互进行一个匹配。
这个时候的话其实就可以表明咱们的client 和server 这两端就是建立了一个连接。建立好连接了以后这个read 标识的话,这个事件它其实就会交由给我们的命令请求处理器。这个命令请求处理器的话,你就可以认为它是专门去处理请求的,也就是一个request。然后命令回复处理器,你可以把它理解为是一个response,也就是一个响应。
随后我们在客户端可能要去,比方说我们要去set 一个值,对吧?set 一个值的话,比方说set name *** 这样子的话,其实它是一个命令嘛。
这个命令的话它的一个世界类型其实也是一个read。随后呢经过server socket 再丢给多路复用器,拿到以后放到咱们的队列里面去再交由文件事件分配器。
这个文件事件分配器拿到以后,它会进行一个判断吧,它会判断匹配是read的事件。它这个时候是一个read的事件的时候,就会让我们的命令请求处理器去处理咱们的命令。他就会去识别了呀,他会去识别当前就是一个set name ***,所以他就要去做一个处理。他要把我们用户所设置的一个内容,把这个键值做一个存储,存储到咱们的内存里面去。这个其实就是一个命令请求的处理,就是一个request 。
当它处理完毕以后,随后的话它会分配一个white,也就是写的一个标识。这个写的标识的话,在这边的话,其实呢我们就可以把它作为响应。因为我们的一个请求其实在处理完毕之后,在我们输入完毕一个命令以后,可能会看到一个ok 对吧?这个ok 的话其实就相当于是我们的一个命令回复处理器回写给我们的一个内容。所以他会用到一个write写的一个标记。这样子我们的一个写的标记其实是会和我们命令回复处理器是捆在一起的。write 的话,其实它的全称是叫做AE_writable 这样的一个事件类型的。
好,随后在我们的客户端这个地方,其实我们就需要去做一个回写也。就是ok 或者说我们在查询list,我们要展示list 里面所有的内容的时候,它其实是回写的一个情况。我们要把内容显示在控制台的下方,它是一个write 这样的一个事件类型。随后交由我们的多路复用器再丢给咱们的一个队列,让这个队列分配给我们的一个文件事件分配器的。这个时候会匹配咱们的web 事件。web 事件是匹配到了。
随后的话,我们的命令回复处理器就会做一个回写。它会把我们的ok 啊或者说是我们的一个获得的一个list 数量,list 里面的内容等等。只要是一些需要展示的内容,他都会是作为一个response,就是把这个响应的内容回写给我们的一个客户端,在客户端上进行一个展示。在我们当前这整个模型里面的话,其实主要就是两个不同的事件,一个叫做readable 的,一个叫做writable 。
当然我们现在设置的仅仅只是一个客户端,如果说我们会有多个客户端的话,他们的道理也都是一模一样的。这个其实就是release 的一个线程模型。初次接触的话是可能会比较的难以去理解,但是没有关系的。这张图的话其实也是可以辅助大家去加深这个意向。
然后他整个处理的流程,也是可以跟着我所说的进行理解。为了便于大家的一个理解,我们在这里画一个图啊,来做一个举例。
假设我们现在呢有一个KTV,这个KTV就是redis。
然后呢我们有很多的顾客要去唱歌,要去唱歌的话,我们KTV里面肯定会有员工嘛,员工的话我们会分为两大类。
第一个大类是门口的接待员,第二个是大堂经理。
门口的接待员其实他就是一个多路复用器,大堂经理的话其实就是一个文件分配器。
然后呢,我们的顾客肯定是有一些相应的请求吧,或者说是相应的需求,这个时候肯定是要询问我们的门口的接待员,让门口的接待员去做简单的一些处理。
可能他要去看一下这个用户想要去参加什么样的活动,有没有优惠券等等。
然后门口的接单员,如果说确定这个顾客要去唱歌的话,就可以说请往后面走,后面有一个通道。这个通道的话其实就是一个队列,你们排着队往这个通道走。走到里面的话,就是我们整个KTV的一个营业厅了。到营业厅里面它会有一个大堂经理,大堂经理的话会去处理我们的一个顾客真实的请求。
随后在我们的一个KTV里面,其实我们的肯定会有一个包厢,每一个包厢的话是会去处理用户,去处理顾客不同的请求的了。在我们的这个包厢的内部呢,会有三个小姐姐或者小哥哥,他们呢是会为用户去处理不同的一些需求的。
比方说第一个的话,他就专门是为顾客去开门的。开门这个动作就相当于是我们的一个客户端和release 去建立了一个链接。门打开以后,你就可以进来了,对吧?进来以后的话,这个小姐姐就不负责他相应的一些工作了,他就会把他交给我们的下面的一个人,下面的一个小姐姐或者小哥哥,就是专门为用户去处理一些请求的。
比方说某一个顾客要点歌的,这个时候就会让点歌的人做一些相应的处理。这个处理的话就是打开电脑去点歌选歌。选完歌了以后,你得要响应给顾客吧。你有没有点好,对吧?你还要把一些话筒麦克风递给顾客,所以这个时候会有一个通知,有这样的一个小姐姐,这个小姐姐会把这个麦克风给到顾客。你现在可以去唱歌了,我们这个歌已经是为你点好了,你去唱吧。
这个时候其实就完成了一个顾客在KTV里面点歌唱歌这一整个动作。这个其实也就是对应在我们之前,我们在release 这个线程模型里面所提及的某一个客户端执行的一个操作吧。首先是建立连接,然后呢去处理请求,随后呢去响应他的一个请求。这个总共这里是有三步操作。
在我们这一块里面的话,整个大堂经理以及是他们点歌通知这一系列的操作的话,其实都是在我们的内部去做处理的。也就是基于我们的一个包厢。包厢的话,在我们的redis里面,咱们是不是可以把它作为是一个内存啊,因为redis一个存储读取等等的操作,其实都是基于内存的。所以在内存里面的话它是非常的快的。
在我们的包厢里面的话,包厢里面你不管是去唱歌还是点一些水果啊,喝一些啤酒啊等等。其实都是基于我们内部的一个包厢去做操作的话,它的一系列的动作等等的话,完成度其实也是非常的快的。
这个其实就可以为了我们的一个线程模型去做了朴素的理解。对于我们的redis 来讲的话,它其实是一个单线程模式。为什么使用单线程模型会非常的快呢?
其实主要是有两点。
第一点的话是我们的一个门口的接待员,其实也就是一个多路复用器。这个多路复用器的话,它是基于一个非阻塞的模型,所以呢它处理起来是非常的快的。它不会因为以前的一种阻塞模式,而一个一个的去等待去响应。现在使用了一个IO多路复用器这样的模型以后,其实它的一个处理效能是非常非常的快的。
另外一部分就是我们的大堂经理这一块,这一块其实它是基于内存去做操作的。纯内存的操作的话,其实它是会非常非常的快的。
当然使用了单线程以后,其实它的一个作用也说了,使用单线程的话,它是可以避免在多线程的时候。因为你多线程的话,你有可能会使用到它的一个上下文的一个切换。一旦切换的话,有可能会引起一些问题。另外呢也是可以避免一些相应的损耗的。所以当我们在使用干线模型的时候,它的一个并发性,它的效率是非常非常的高的。
以上就是图文解析Redis线程模型的详细内容,转载自php中文网
发表评论 取消回复