Redis一个很是大的特色就是快,官方给出说明:web
1. 单线程,减小线程切换时间。
2. 纯内存操做
3. I/O多路复用机制redis
可能前二者比较好理解,可是I/O多路复用是什么,接下我讲介绍关于它的知识,但愿对你帮助缓存
多路 I/O 复用模型是利用select、poll、epoll能够同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中唤醒,因而程序就会轮询一遍全部的流(epoll是只轮询那些真正发出了事件的流),而且只依次顺序的处理就绪的流,这种作法就避免了大量的无用操做。这里“多路”指的是多个网络链接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可让单个线程高效的处理多个链接请求(尽可能减小网络IO的时间消耗),且Redis在内存中操做数据的速度很是快服务器
操做的瓶颈在于网络的I/O,I/O操做的步骤分为:网络
类比于jdk中NIO操做,NIO提供了selector器,是selectableChannel的多路服务器,用于监控SelectableChannel的io状态。通道注册到selector器上,并且能够选择注册那种事件类型,由selector对注册事件进行轮询。
以nio的SocketChannel为例,写示例代码;并发
public class TestNonBlockNIO { @Test public void testClient() throws IOException { //1.获取通道 SocketChannel sChannel=SocketChannel.open(new InetSocketAddress("127.0.0.1",9898)); //2.切换到非阻塞的状态 sChannel.configureBlocking(false); //3.分配指定大小的缓冲区 ByteBuffer buffer=ByteBuffer.allocate(1024); //4.发送数据给服务端 Scanner scan=new Scanner(System.in); while(scan.hasNext()){ String str=scan.next(); buffer.put((new Date().toString()+"\n"+str).getBytes()); buffer.flip(); sChannel.write(buffer); buffer.clear(); } // buffer.put(LocalDate.now().toString().getBytes()); //5.关闭通道 sChannel.close(); } @Test public void testServer() throws IOException { //1.获取server通道 ServerSocketChannel serverSocketChannel=ServerSocketChannel.open(); //2.切换成非阻塞的模式 serverSocketChannel.configureBlocking(false); //3.绑定链接 serverSocketChannel.bind(new InetSocketAddress(9898)); //4.获取选择器 Selector selector = Selector.open(); //5.通道注册到选择器上,而且选择监听的事件 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //6.轮询式获取选择器上已经“准备就绪”的事件 while (selector.select()>0){ //7.获取当前选择器中全部注册的“已经就绪的监听事件” Iterator<SelectionKey> iterable= selector.selectedKeys().iterator(); while (iterable.hasNext()){ //8.获取准备就绪的事件 SelectionKey sk=iterable.next(); //9.判断具体是什么事件就绪了 if(sk.isAcceptable()){ //接收就绪 //10.若接收就绪,获取客户端的链接 SocketChannel socketChannel=serverSocketChannel.accept(); //11.切换到非阻塞的模式 socketChannel.configureBlocking(false); //12.将该通道注册到选择器上 socketChannel.register(selector,SelectionKey.OP_READ); } if(sk.isReadable()){ //13.获取读状态就绪的通道 SocketChannel socketChannel= (SocketChannel) sk.channel(); ByteBuffer buffer=ByteBuffer.allocate(1024); int len=0; while((len=socketChannel.read(buffer))>0){ buffer.flip(); System.out.println(new String(buffer.array(),0,len)); buffer.clear(); } } } //14.取消选择键 iterable.remove(); } } }
其实reids之因此单线程还如此之快的缘由就是由于内部采用了I/O多路复用机制模型,可是这种机制不是什么状况下都是使用的,应为用与大量的连接,处理时间又不是很长的业务,链接数最好是大于1000,并发程度不高或者局域网环境下NIO并无显著的性能优点socket