周末被一个小同学搞的很不爽,他要跟我讨论redis是多线程还是单线程,这个问题解释的比较好,但是我遇到的是渣男,答案很明显:逃不过真象定理的redis6,引入了多线程;但在redis6之前,是单线程的,换句话说,这不是是或不是的问题,还涉及到二次元版本的参与。不过,这位同学想打我的脸。不知道小姐姐的皮肤是不是很嫩?我摸不着。“按照你的逻辑,redis5是单线程的?”“是的”“那下面截图是怎么回事?”同学扔给我一张图,鄙夷的看了我一眼。我解释一下?”这个问题,不知道怎么解释给他看,用top命令观察,redis5必须是多线程的,比如bgsave、aof等,必须开一个线程来操作,否则会炸毁。按照这个逻辑,Redis从来就没有一个进程。看着这幅画,我陷入了无尽的悲痛之中。“Redis是否是单进程,主要是针对Redis的读写操作。”不过这句话没有什么说服力吧。“写程序一定要严谨,你们人家太严谨了。多线程就是多线程,你应该问'redis的读写操作是不是多线程'”。我问你个大头鬼。我不想再和他交流了,因为我为自己的博学感到羞愧。但他的下一个问题让我陷入了真正的沉思。1、redis多线程有多快?redis多线程多少钱?有什么性能提升?官方的说法是:可以轻松加速两倍。将速度增加到两倍可能更容易。我的英文不是很好,对这个英文修改很是迷惑。既然容易,为什么还是有可能。两次,无论是增加2倍还是增加到2倍。据官方介绍,能提升多少取决于硬件的能力。官方建议只有当你的CPU核数达到4时,才有必要试试这个多线程的特性。不要用土豪的眼光盯着我。这种4core的配置,已经秒杀大部分公司了。所以Redis关闭了多线程功能。(好像有点俚语)只能求助于那些在一线的前同事了。他们在生产环境中使用过这种划时代的多线程Redis6x吗?结果让我很满意,不!我特别满意的回答之一。他说:“你其实是在问我谁卡在JDK1.6,跑的是Windows版的Redis,有没有用过Redis6,我还在用Redis3。”我比较满意的另一个答复,他说:走开!2.如何使用?新技术一定要吹捧,否则没人会去实践,作为追随者也只能吃。从理论上讲,多线程肯定会提高性能。一个爸爸挣钱和两个爸爸挣钱,效果自然不一样,苦的还是妈妈。Redis6开启了多线程,需要配置一个参数。当启用io-threads4时,只有出站流量使用多线程。如果您希望入站流量也使用多线程,您还可以配置以下参数。io-threads-do-readsyes就是这两个参数。可以看到现在的redis多线程还是有点寒酸。开启后,我们仍然使用top-Hp查看相关进程,可以看到多了3个io_thd进程。这部分逻辑在networking.c中实现。这个文件达到了3k多行,已经够庞大了。3、为什么Redis又要搞多线程了?使用redis-benchmark测试,单机单核吞吐量可达10w+。1秒是100亿纳秒,单次内存操作大约100纳秒,内存操作可以达到1000w/s的速度。Redis的瓶颈在哪里?使用perf进行跟踪,可以发现其耗时主要体现在sys_write系统调用,即向socket写入数据。既然找到了瓶颈,就把它优化掉。redis选择的方式是使用多线程。我使用基准测试它。在4核机器上,当CPU满负荷运行时,QPS达到16w,没有翻倍(对比单核9w/s)。benchmark6379clients32164519.20requestspersecond165411.09requestspersecond用了这么强的硬件,却获得了如此有限的性能提升,并不令人满意。不难解释为什么现在修炼的人这么少。因为是新的,所以还是不够吸引人。毕竟4core的机器,如果我部署3个redis集群实例,理论上会增加3倍。在redis的配置文件中,有很多内容标注了这个新特性。4.如何实现?如图所示,一个redis请求需要建立连接,然后获取操作命令,然后执行命令,最后将响应结果写入socket。在redis的多线程模式下,获取、解析命令、输出结果这两个过程可以配置为多线程执行,因为毕竟是我们定位的主要耗时点。但是命令的执行,也就是内存操作,还是单线程运行的。这种设计创造了一个特点。Redis依然不存在多线程锁竞争和线程安全问题,因为它的数据读取步骤还是单线程的,需要排队运行。一些比较耗时的操作,比如keys*、hgetall等,还是需要注意一下。Redis不是传统的反应器模型。说实话,很多东西如果硬套在概念上,只能进头漏尾。它不是master,worker是一个类似于memcached的clean模型,因为它抽取了命令执行操作。原因看上图就够了。End那么,下一个吸引bar的问题来了:在这种多线程的应用场景下,redis是I/O密集型还是计算密集型?或许,如果redis多线程中无处不在的轮询属于“计算”的话,就可以算是计算密集型应用了。
