范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

从MySQL源码看其网络IO模型

  从MySQL源码看其网络IO模型前言
  MySQL是当今最流行的开源数据库,阅读其源码是一件大有裨益的事情(虽然其代码感觉比较凌乱)。而笔者阅读一个Server源码的习惯就是先从其网络IO模型看起。于是,便有了本篇博客。
  MySQL启动Socket监听
  看源码,首先就需要找到其入口点,mysqld的入口点为mysqld_main,跳过了各种配置文件的加载
  之后,我们来到了network_init初始化网络环节,如下图所示:
  下面是其调用栈:mysqld_main (MySQL Server Entry Point)
  |-network_init (初始化网络)
  /* 建立tcp套接字 */
  |-create_socket (AF_INET)
  |-mysql_socket_bind (AF_INET)
  |-mysql_socket_listen (AF_INET)
  /* 建立UNIX套接字*/
  |-mysql_socket_socket (AF_UNIX)
  |-mysql_socket_bind (AF_UNIX)
  |-mysql_socket_listen (AF_UNIX)
  值得注意的是,在tcp socket的初始化过程中,考虑到了ipv4/v6的两种情况:// 首先创建ipv4连接
  ip_sock= create_socket(ai, AF_INET, &a);
  // 如果无法创建ipv4连接,则尝试创建ipv6连接
  if(mysql_socket_getfd(ip_sock) == INVALID_SOCKET)
  ip_sock= create_socket(ai, AF_INET6, &a);
  如果我们以很快的速度stop/start mysql,会出现上一个mysql的listen port没有被release导致无法当前mysql的socket无法bind的情况,在此种情况下mysql会循环等待,其每次等待时间为当前重试次数retry * retry/3 +1秒,一直到设置的—port-open-timeout(默认为0)为止,如下图所示:
  MySQL新建连接处理循环
  通过handle_connections_sockets处理MySQL的新建连接循环,根据操作系统的配置通过poll/select处理循环(非epoll,这样可移植性较高,且mysql瓶颈不在网络上)。
  MySQL通过线程池的模式处理连接(一个连接对应一个线程,连接关闭后将线程归还到池中),如下图所示:
  对应的调用栈如下所示:handle_connections_sockets
  |->poll/select
  |->new_sock=mysql_socket_accept(...sock...) /*从listen socket中获取新连接*/
  |->new THD 连接线程上下文 /* 如果获取不到足够内存,则shutdown new_sock*/
  |->mysql_socket_getfd(sock) 从socket中获取
  /** 设置为NONBLOCK和环境有关 **/
  |->fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK);
  |->mysql_socket_vio_new
  |->vio_init (VIO_TYPE_TCPIP)
  |->(vio->write = vio_write)
  /* 默认用的是vio_read */
  |->(vio->read=(flags & VIO_BUFFERED_READ) ?vio_read_buff :vio_read;)
  |->(vio->viokeepalive = vio_keepalive) /*tcp层面的keepalive*/
  |->.....
  |->mysql_net_init
  |->设置超时时间,最大packet等参数
  |->create_new_thread(thd) /* 实际是从线程池拿,不够再新建pthread线程 */
  |->最大连接数限制
  |->create_thread_to_handle_connection
  |->首先看下线程池是否有空闲线程
  |->mysql_cond_signal(&COND_thread_cache) /* 有则发送信号 */
  /** 这边的hanlde_one_connection是mysql连接的主要处理函数 */
  |->mysql_thread_create(...handle_one_connection...)
  MySQL的VIO
  如上图代码中,每新建一个连接,都随之新建一个vio(mysql_socket_vio_new->vio_init),在vio_init的过程中,初始化了一堆回掉函数,如下图所示:
  我们关注点在vio_read和vio_write上,如上面代码所示,在笔者所处机器的环境下将MySQL连接的socket设置成了非阻塞模式(O_NONBLOCK)模式。所以在vio的代码里面采用了nonblock代码的编写模式,如下面源码所示:
  vio_readsize_t vio_read(Vio *vio, uchar *buf, size_t size)
  {
  while ((ret= mysql_socket_recv(vio->mysql_socket, (SOCKBUF_T *)buf, size, flags)) == -1)
  {
  ......
  // 如果上面获取的数据为空,则通过select的方式去获取读取事件,并设置超时timeout时间
  if ((ret= vio_socket_io_wait(vio, VIO_IO_EVENT_READ)))
  break;
  }
  }
  即通过while循环去读取socket中的数据,如果读取为空,则通过vio_socket_io_wait去等待(借助于select的超时机制),其源码如下所示:vio_socket_io_wait
  |->vio_io_wait
  |-> (ret= select(fd + 1, &readfds, &writefds, &exceptfds,
  (timeout >= 0) ? &tm : ))
  笔者在jdk源码中看到java的connection time out也是通过这,select(…wait_time)的方式去实现连接超时的。
  由上述源码可以看出,这个mysql的read_timeout是针对每次socket recv(而不是整个packet的),所以可能出现超过read_timeout MySQL仍旧不会报错的情况,如下图所示:
  vio_write
  vio_write实现模式和vio_read一致,也是通过select来实现超时时间的判定,如下面源码所示:size_t vio_write(Vio *vio, const uchar* buf, size_t size)
  {
  while ((ret= mysql_socket_send(vio->mysql_socket, (SOCKBUF_T *)buf, size, flags)) == -1)
  {
  int error= socket_errno;
  /* The operation would block? */
  // 处理EAGAIN和EWOULDBLOCK返回,NON_BLOCK模式都必须处理
  if (error != SOCKET_EAGAIN && error != SOCKET_EWOULDBLOCK)
  break;
  /* Wait for the output buffer to become writable.*/
  if ((ret= vio_socket_io_wait(vio, VIO_IO_EVENT_WRITE)))
  break;
  }
  }
  MySQL的连接处理线程
  从上面的代码:mysql_thread_create(...handle_one_connection...)
  可以发现,MySQL每个线程的处理函数为handle_one_connection,其过程如下图所示:
  代码如下所示:for(;;){
  // 这边做了连接的handshake和auth的工作
  rc= thd_prepare_connection(thd);
  // 和通常的线程处理一样,一个无限循环获取连接请求
  while(thd_is_connection_alive(thd))
  {
  if(do_command(thd))
  break;
  }
  // 出循环之后,连接已经被clientdu端关闭或者出现异常
  // 这边做了连接的销毁动作
  end_connection(thd);
  end_thread:
  ...
  // 这边调用end_thread做清理动作,并将当前线程返还给线程池重用
  // end_thread对应为one_thread_per_connection_end
  if (MYSQL_CALLBACK_ELSE(thread_scheduler, end_thread, (thd, 1), 0))
  return;
  ...
  // 这边current_thd是个宏定义,其实是current_thd;
  // 主要是从线程上下文中获取新塞进去的thd
  // my_pthread_getspecific_ptr(THD*,THR_THD);
  thd= current_thd;
  ...
  }
  mysql的每个woker线程通过无限循环去处理请求。
  线程的归还过程
  MySQL通过调用one_thread_per_connection_end(即上面的end_thread)去归还连接。MYSQL_CALLBACK_ELSE(...end_thread)
  one_thread_per_connection_end
  |->thd->release_resources
  |->......
  |->block_until_new_connection
  线程在新连接尚未到来之前,等待在信号量上(下面代码是C/C++ mutex condition的标准使用模式):static bool block_until_new_connection
  {
  mysql_mutex_lock(&LOCK_thread_count);
  ......
  while (!abort_loop && !wake_pthread && !kill_blocked_pthreads_flag)
  mysql_cond_wait(&x1, &LOCK_thread_count);
  ......
  // 从等待列表中获取需要处理的THD
  thd= waiting_thd_list->front;
  waiting_thd_list->pop_front;
  ......
  // 将thd放入到当前线程上下文中
  // my_pthread_setspecific_ptr(THR_THD, this)
  thd->store_globals;
  ......
  mysql_mutex_unlock(&LOCK_thread_count);
  .....
  }
  整个过程如下图所示:
  由于MySQL的调用栈比较深,所以将thd放入线程上下文中能够有效的在调用栈中减少传递参数的数量。
  总结
  MySQL的网络IO模型采用了经典的线程池技术,虽然性能上不及reactor模型,但好在其瓶颈并不在网络IO上,采用这种方法无疑可以节省大量的精力去专注于处理sql等其它方面的优化。

3岁女孩被父母喂到70斤开吃播自己是畜生,就不把孩子当人吗最近两天,有个叫佩琪的女孩火了。看到这个名字,我第一个联想到的就是小猪佩奇里的那只粉粉嫩嫩的小猪。而佩琪的父母,的确把她当小猪一样喂养。他们在社交平台上开了一个账号,得意洋洋地把佩小S女儿拿洗发水代言靠世袭?星二代混的还不如父母好就对了许曦文接任了清扬洗发水的代言人,品牌生怕人不知,官宣还特别强调了是小S女儿。以前只知道财产和爵位能继承,头回听说广告也能世袭的。作为一个从小学舞蹈的星二代,许曦文的身材气质都不错,抚顺6岁女孩被虐背后恋爱脑真的不只是蠢有读者让我写写抚顺虐童案,其实我不太想写。因为情绪支配之下,除了骂娘,我也不知道还能说什么。这两天平静了一点后,想说点不一样的。照片即便是打着码都让人头皮发麻,被用热水浇头铁钳拔牙鲍毓明的事情能用一句流氓遇到骗子就总结了吗?沸沸扬扬的鲍某某涉嫌性侵案总算水落石出了,经过了几个月的信息迭代,所谓的反转再反转,群众们其实已经基本快接近真相了。只不过,真相出炉的那一刻,还是有点不敢相信自己的眼睛。原文很长,拍到就是被陷害,李湘打算撑夫到几时?王岳伦昨晚发了个义正辞严的微博,说经历了这些天的自责反省和屈辱后,在大家的帮助下,终于弄明白了是谁在陷害他。字里行间都好像藏着惊天大阴谋至于这个有老婆有孩子心肠恶毒的神秘人士到底是教辅书分男女?这种事抖什么机灵啊前段时间,网上热炒教辅书被分了男女,初看还以为是段子。没想到,华东师范大学出版社真的搞出了一套名为男生女生学数学的数学教辅书,分蓝版和红版,一个男生版,一个女生版。就问你贴不贴心?贾欣,你妈妈喊你回家讲道理一个朋友给我分享了一段他爸发在他们家庭群里的小视频,神秘兮兮地说,让你感受一下我们家润物细无声的家教。看完这组魔性视频后,我满脑子里回荡的都是那句贾欣你记住。不能我一个人瞎,一起来论不要脸,就服曲婉婷要说娱乐圈里脖子最硬的人,我最服气的就是曲婉婷。别的艺人出名是靠作品说话,曲婉婷维持关注的杀手锏是持续六年隔空喊冤云爱妈,已经成了保留曲目了。三天前,曲婉婷发了一条微博,大言不惭的别再利用谭松韵的悲痛带节奏了今天想来聊聊谭松韵妈妈那场轰动全国的交通肇事逃逸案。这场事先张扬的庭审案,迷雾重重,肇事者背景深法官偏私等黑幕说甚嚣尘上。有人说,连明星都没法为自己维权,我们这些小老百姓该怎么办?朱一龙隐婚生子?我越发觉得鹿晗是条汉子了朱一龙被扒出隐婚生子,儿子还跟着自己认祖归宗姓了皮。一个三十多岁的男明星,结个婚生个孩子有什么问题?至于归姓也没什么可嘲的,人家的孩子,爱姓啥你管得着吗?我姥爷姓班,我妈跟了我姥姥61岁老阿姨和靳东谈恋爱的瓜,我笑不出来61岁的江西老阿姨黄月(化名)一头扎进了跟演员靳东的爱情里,不吃不喝瘦了十多斤,跟老公分床睡,一心一意要跟自己的情郎终成眷属。稍微有点常识的人都知道,这个靳东跟演员靳东没有一点关系
研究生开学后,是否需要为导师准备见面礼,不送会怎样能够考上研究生是非常值得庆祝的事情,社会的普遍学历在提升,本科学历已经不那么吃香了,硕士的学历还是有一定的优势的。很多成功考研的学生比较纠结,是否应该在开学时期,给导师准备见面礼呢小学生作文委屈走红,全篇不见委屈二字,老师却笑出鹅声小学生的世界是多姿多彩的,他们总是脑洞大开,有时候气的家长火冒三丈,有时候又让家长喜欢不已,在老师的眼中,这群熊孩子就像是个小大人一样,无论是在生活中还是学习中,总是有很多鬼点子,211高校食堂火了,用餐环境很特别,学生吐槽太接地气说到上大学,是多少莘莘学子的梦想,高考成绩出来后,准新生们都在忙碌着去奔向自己的新生活,对于父母们来说,在一边跟着欢喜的同时,也很担心孩子的食宿问题,尤其是去外省上大学,一些饮食习江苏一所大学宣布改名,将常熟改为苏州,新校名很大气我国的高等教育资源丰富,能够在高考中金榜题名,是很多人的理想,虽然大学数量众多,各具特色和优势,但也是有等级的划分的。985,211这些可以说是名校的标签,而某某职业学院也成了专科体育老师公认的省力跑步法,学生长跑不怕累,提前了解有好处素质教育的发展,体育学科的地位越来越高,中考要考体育,跑步也成了很多人头疼的问题,在学生时代,学生们最喜欢哪类课程,其中体育应该是最受欢迎的,体育课学生们主要是以玩为主,去放松身心武汉多所大学出现天价学费,学生难以接受,家长直言供不起了经历了漫长的暑假,学生们也期盼着开学快一点到来,尤其是大学生们,更想回归大学校园,大一的新生更加憧憬大学的美好生活。孩子读大学对于每个家庭来说,还是有一定的压力的,学生不能够经济独哪凉快哪待着去,小心你的孩子中暑!全国多地气温一路飙升,平均气温高达37度以上,连非洲留学生都直呼被晒黑了,说要回家避暑热浪滚滚中,大家一定要注意防暑降温,尤其是家中有孩子的家庭,以防因为中暑而引发热射病(也叫中暑儿童冬季感冒鼻涕鼻塞的家庭护理与治疗预防冬季气温降幅大,寒冷及干燥最易引发呼吸道疾病,已经有不少宝宝罹患上呼吸道感染,若不加以重视诊治,极易出现反复上呼吸道感染。成为宝爸妈后,每次听到感染两个字,都心慌慌。听到别家孩子感事业单位迎来喜讯,新制度将全国统一实行,工资有望提升大学生就业难,很多学生毕业后纷纷的加入了考公的队伍中,也有的学生考事业单位,铁饭碗的工作更加稳定,社会地位也比较高,很受学生们的青睐。社会在不断的向前发展,政策也在不断的更新,即使军队文职招聘遇冷,月薪9000元却无人问津,真实原因叫人扎心学生时代努力的学习,在大学中努力的提升自己,都是希望自己能够在毕业后获得一份高薪的工作,这也是很多学生的理想和目标。随着高校的数量增多,本科生的含金量也降低了,似乎变得不再值钱,大奥运游泳冠军张雨霏火了,背后故事却发人深思,难怪她这样厉害今年的奥运备受社会各界人士的关注,很多运动员也出现在大众的视野中,他们为国家争得荣誉的时候,我们的内心也满是骄傲,奥运的精神让我们更加热爱祖国,希望祖国更加繁荣昌盛。参赛的运动员们