一、memcached如何支持高并发
Memcached使用多路复用 I/O模型(如epoll、select等)。传统阻塞 I/O中,系统可能会因为某个用户连接还没做好 I/O准备而一直等待,直到这个连接做好I/O准备。如果这时有其他用户连接到服务器,很可能会因为系统阻塞而得不到响应。
而多路复用I/O是一种消息通知模式,用户连接做好I/O准备后,系统会通知我们这个连接可以进行I/O操作,这样就不会阻塞在某个用户连接。因此,才能支持高并发。
此外,Memcached使用了多线程模式。在开启Memcached服务器时通过使用“-t”参数指定需要开启的线程数。一般设置为CPU核数,效率最高。因为线程数越多,系统需要的线程调度时间就越多。而把线程数设置成CPU核数,系统需要的线程调度时间最少。
下面举一个例子,模拟一个tcp服务器处理30个客户socket。假设你是一个超市老板,30个用户分别买不同的东西,但是有的商品有库存有的商品没有库存需要等待供应商送货,然后有下面几个选择:
-
第一种选择:按顺序逐个检查,A用户先来买卫生纸,B用户买手电筒,C用户买泡面。。。。,逐个处理的结果是A用户买完走了,但是B用户的商品卖完了等待供应商送货30分钟后货送到了B购买成功,继续处理C用户。。。,这样处理就相当于最后的需要等待前面的用户全部购买成功才能继续购买。这种模式就好比,你用循环挨个处理socket,根本不具有并发能力。
-
第二种选择:你创建30个分身,每个分身去负责处理每个用户的购买请求。 这种类似于为每一个用户创建一个进程或者线程处理连接,但是Redis是单线程的
-
第三种选择,当A请求购买时 有货告知可以买 然后A购买,B请求购买 需要等待供应商送货 等待直到供应商送货过来 告知B来货了 B发起购买 购买成功;在B等待供应商的期间C用户的购买请求开始处理 有货直接购买成功 无需等待B用户购买。 这种就是IO复用模型
客户端先去select循环询问服务端是否可以发起read 这个过程是阻塞的 但是速度很快,当服务端准备好了数据报告诉客户端readable,客户端即可发起read请求,此时因为服务端已经准备好了数据报,直接返回即可。整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的。这种方式避免了线程的阻塞,又称为非阻塞I/O模型
这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗)
具体流程可以参照下图: