MySQL:网络连接框架简析

作者简介:高鹏,笔名八怪。《深入理解MySQL主从原理》图书作者,同时运营个人公众号“MySQL学习”,持续分享遇到的有趣case以及代码解析!

一直对这部分不太了解,稍微看了一下,但由于知识储备有限,错误在所难免。

总的看起来MySQL在这部分依旧使用了常规的 reactor+线程池高并发网络模型,这里我们以poll为列,有如下特点:

  • 主reactor通过poll对listen fd的POLLIN event进行监控,并且设置了非阻塞。
  • 如果主reactor收到新的连接请求,在线程池中获取一个线程
  • 如果线程池中没有可用的线程,则新建线程
  • 新的线程对同样通过ppoll对连接fd的POLLIN event进行监控,并且负责实际业务逻辑的处理。

貌似看起来大佬的手法都是通用的,都是按照一定模式写出来的。当然实际上涉及的东西还是非常多,但是这里我们仅仅了解网络框架部分,对于线程池vio通信模块net协议模块不做讨论,因为我也不了解,这里主要看看网络框架。

简要流程分析

  • network_init 这部分主要对实例的端口进行bind->listen,并且设置好poll监控的event为 POLLIN,同时会将listen fd设置为非堵塞,这里还需要注意一点socket的属性设置了SO_REUSEADDR,这表明对于处于TIME_WAIT状态的连接,MySQLD客户端的端口能够快速重用,而不需要等待2MSL超时。
  • connection_event_loop 和所有的网络框架一样,这里需要开启主循环了。循环的目的当然就是不断监控poll的POLLIN和accpet 后返回连接fd,如果打开函数Mysqld_socket_listener::listen_for_connection_event就能看到一上来就是poll开始了。最后会将accpet的连接fd封装到Channel_info返回。并且随后本函数还负责了新线程的建立,这里可以考虑为我们的session即将诞生。随后调用的就是这里主要开始调用Per_thread_connection_handler::add_connection。首先会在线程池中获取一个已经建立好的线程来进行处理,这里和我们的参数thread_cache有关,这种缓存的线程通常在函数Per_thread_connection_handler::block_until_new_connection处堵塞,等待唤醒,一旦有足够的缓存的线程就会唤醒并且完成出队操作。当然了,如果线程吃没有缓存的线程,则新建线程用于新会话的处理。完成这一步后我们的主reactor线程也就是我们main线程就会(注意不是Innodb的master线程)堵塞在poll上等待新的连接请求的到来,来一个处理一个。等待如下,

main    ->mysqld_main         -> Connection_acceptor::connection_event_loop                 ->Mysqld_socket_listener::listen_for_connection_event                            ->poll ()