Redis(一)
计算机简单的构成分为 内存(线性地址抠空间),cpu,鼠标键盘打印机等IO设备。redis是一个典型的数据存储在内存条的。
内存存储的是运行的程序和指令的数据,运行程序又分为,
1.操作系统刚刚启动的内核程序kernel
2.用户相关的内存(tomcat,redis等)
先写一段简单的jedis代码。
public static void main(String[] args) { Jedis jedis = new Jedis(IP, PORT); jedis.auth("123456"); jedis.set("name","cjr"); jedis.close(); }
跟进jedis.set,发现jedis其实是对socket套接字封装(redisTemplate同理)
画图模拟一下,jedis的连接过程。
首先会连接操作系统的内核程序kernel,由我们的操作系统内核建立连接,在连接的过程中,可能会出现IO的多路复用。
这里我们考虑一个问题,假设现在jedis1,jedis2,jedis3都连接上了redis,但是只有jedis1和jedis2发送了数据,需要redis处理,肯定会通知redis处理。那么jedis3能不能通知到redis?
我们用代码模拟一下。之前说过,jedis底层其实就是socket套接字的封装,那我把redis想象成一个socketServer。
先写一个最基础的socketServer:
客户端:
客户端捕捉到键盘输入的流,发送给服务器,服务器打印。当我们连接到服务端,还没发送任何命令给server时,read会阻塞。
我们会想到,如果这时候是多个客户端连接redis怎么办?第一个客户端与服务端产生了连接,但是,被read阻塞,导致后面的客户端无法连接至服务端。于是,我们可以将read堵塞的这部分,用多线程来实现,这样就避免了read的堵塞。
但是,这样又会产生一个问题,就像开始画的图那样,假设有1000个客户端来连接服务端,但是只有10个客户端发送了数据,剩下的990个客户端仅仅只是连接服务端,并不发送数据。那么是不是有990个线程处于资源浪费的状态?那么有没有办法做到单线程来处理多个客户端连接的问题呢 ?
其实归根到底,单线程不能多个客户端同时连接,是因为accpect和read方法是阻塞的。现在假设我们修改了socket和sockerServer,让accpect和read方法不阻塞,那么,我们的伪代码应该是:
很遗憾,sun公司不会让你修改socket和socketServer。但是,他们提供了其他的方式来处理多个客户端并发问题,也就是Nio.
对比一下代码,其实NIO的思想就是设置accpect和read非阻塞。
问题解决了吗?并没有,目前的代码还是没有解决客户端只连接不发数据导致的资源浪费的问题。
下一节,从JVM层面和OS系统内核层面讨论代码该如何优化