当客户端与ServerSocket产生链接时,会产生一个 AE_REABLE / AE_WRITABL 事件, 多个Socket可能并发产生不一样的事件,IO多路复用程序会监听这些Socket,按照顺序将这些Socket放到队列中排队。而后每次从队列中取出一个Socket来进行相应的操做。(这种io多路复用+事件驱动模式,在redis和netty中获得了很好的应用)html
*IO多路复用:能够参考个人这篇博客https://www.cnblogs.com/wlwl/p/10293057.htmlredis
下面举一个例子来讲明io多路复用,模拟一个tcp服务器处理30个客户socket。
假设你是一个老师,让30个学生解答一道题目,而后检查学生作的是否正确,你有下面几个选择:
1. 第一种选择:按顺序逐个检查,先检查A,而后是B,以后是C、D。。。这中间若是有一个学生
卡主,全班都会被耽误。这种模式就比如,你用循环挨个处理socket,根本不具备并发能力。
2. 第二种选择:你建立30个分身,每一个分身检查一个学生的答案是否正确。 这种相似于为每个
用户建立一个进程或者线程处理链接。
3. 第三种选择,你站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下
去依次检查C、D的答案,而后继续回到讲台上等。此时E、A又举手,而后去处理E和A。。。 这种就是IO复用模型。
*文件事件处理器:服务器
若是是客户端要链接redis,那么会为socket关联链接应答处理器
若是是客户端要写数据到redis,那么会为socket关联命令请求处理器
若是是客户端要从redis读数据,那么会为socket关联命令回复处理器多线程
*客户端与redis通讯的一次流程:并发
在redis启动初始化的时候,redis会将链接应答处理器跟AE_READABLE事件关联起来,接着若是一个客户端跟redis发起链接,此时会产生一个AE_READABLE事件,而后由链接应答处理器来处理跟客户端创建链接,建立客户端对应的socket,同时将这个socket的AE_READABLE事件跟命令请求处理器关联起来。socket
当客户端向redis发起请求的时候(无论是读请求仍是写请求,都同样),首先就会在socket产生一个AE_READABLE事件,而后由对应的命令请求处理器来处理。这个命令请求处理器就会从socket中读取请求相关数据,而后进行执行和处理。接着redis这边准备好了给客户端的响应数据以后,就会将socket的AE_WRITABLE事件跟命令回复处理器关联起来,当客户端这边准备好读取响应数据时,就会在socket上产生一个AE_WRITABLE事件,会由对应的命令回复处理器来处理,就是将准备好的响应数据写入socket,供客户端来读取。tcp
命令回复处理器写完以后,就会删除这个socket的AE_WRITABLE事件和命令回复处理器的关联关系。工具
*为啥redis单线程模型也能效率这么高?测试
1)简洁的命令表达式
2)纯内存操做
3)核心是基于非阻塞的IO多路复用机制
4)单线程反而避免了多线程的频繁上下文切换问题spa
redis自带redis-benchmark这个压力测试工具,我以一台2G2核的虚拟机为例作一下压力测试:
cd /redis/bin
*1. 模拟100个链接,一共发起100000个请求,它会打印出redis各个命令的执行效率
./redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000
2. 查看简单信息:
以100个字节装载来压测 (-q表示简单信息,只会打印出每一个命令的每秒处理请求个数)
./redis-benchmark -h 127.0.0.1 -p 6379 -q -d 100
3. 查看指定命令每秒处理请求量
查看set/lpush命令的tps
./redis-benchmark -t set,lpush -n 10000 -q