0%

01-网络连接层

摘要:数据库三层架构

1
2
3
4
5
网络层

server层

存储层

存储层:mysql作为一个插件式的数据库,在存储层支持多种引擎,譬如默认的innodb,和之前版本默认的MyIsam。由不同的引擎提供相同的接口给server层调用,来完成数据的增删改查。

server层:是mysql比较复杂的地方,里面包含了大量的逻辑,譬如语义分析、查询优化、日志、缓存等等。

网络层:主要是提供socket连接。

网络层

在mysql的网络层,主要关注3点

  1. Poll、Select模型
  2. Max-connections
  3. connection复用

mysql在启动后,创建了socket server,绑定了3306端口,并对其进行监听。和java里的写法类似,用一个while循环来监听新来的connection,如果有了新连接,就创建一个新的连接线程去处理(不能超过max-connections)。

这种就是典型的BIO的模式,为每一个连接创建一个线程。并且,mysql在这里采用了IO多路复用,会有一个if语句来判断当前系统是否支持Poll模式,否则就走Select模型(各个系统默认都有实现)。

Poll模型和Select非常类似,只是少了1024个fd的限制,都是采用遍历数组轮询有没有新IO事件的方式,在连接数较少的情况下,性能优异,要好于epoll。

mysql基于BIO,本质上是不接受大量的socket连接的,所以设置了max-connections这个限制,超过设置的max,那么新来的连接会被拒绝。

那么,第一个问题,为什么是BIO,而不是可以承受更大连接数的NIO和AIO呢?是否用NIO就会更好呢?

mysql的BIO

bio和nio的区别

在BIO模式下,调用read,如果发现没数据,就会Block住。

在NIO模式下,调用read,如果发现没数据,就会立刻返回-1, 并且errno被设为EAGAIN。

基于NIO+IO多路复用的模式

server开发使用的web容器:tomcat、netty等,都是基于NIO+IO多路复用的模式,来大幅提升性能,承载高并发访问的。但是到了DB层,则使用hakiri、druid之类的线程池,开启10个线程去连接mysql,反复复用这个线程池。

NIO+IO多路复用,并不是指多个用户socket共享一个IO,从而使得服务端的socket数量大减。而是把多个socket连接,归并到一个进程进行管理,如用一个大数组来聚合起来,然后循环遍历这个数组,来一次性把多个连接的事件通知业务代码进行处理。
这样就大幅减少了server的压力,高效利用资源。

对mysql来说,一般都会有多个连接,毕竟并发肯定是要有的。不可能做个查询,也要大家一起排队等上一个人查询完。所以线程池和并发是一定的。

mysql和web Server区别

Web请求,往往是无状态的,一问一答的时候居多,请求也往往比较短促,对于顺序性也不是十分严格,哪怕是后请求的响应比先请求的提前到,也是有可能的。

DB请求,DB采用session作为一个连接会话,这一个session里,SQL的执行必须是串行、同步、有序的,而不能是异步乱序的。原因是,一个session内可能有多个操作,增删改查、事务隔离,必须保证顺序不能乱。
DB维护这样一个session,是要花费远大于web Server处理一个请求的资源才能完成的。

对于DB来说,连接是非常耗资源的事情,限制连接数是非常有必要的。

注意,当连接mysql出问题时,随便加大应用服务的连接池和增大mysql的max-connection。不能改善mysql的性能。当进行非常密集的数据库操作时,连接池的数量对性能产生的巨大影响。

为什么用BIO,而不是NIO。

原因是JDBC不支持,JDBC出现了20年,它是一个标准,在它被提出时,只有BIO模型,导致数据库驱动对JDBC的实现都是BIO的形式,mysql驱动connector早早地实现了JDBC标准,就是采用阻塞的方式。

当进行一个select查询,在查询没有完成之前,整个调用线程会被卡住,等到天荒地老也要等下去,绝不是一请求立马收到返回,然后等mysql回调你结果。

其实,也有人修改了mysql的协议,增加了NIO+多路复用的功能,最后失败,主要原因是mysql和web server功能意义都不一样,确切地说,90%的场景下,不需要一个NIO的数据库。

BIO+连接池,已经发展了很多年,大部分问题都已经解决,在目前的java环境中,是非常靠谱的方案。已经出现了很多优秀的连接池框架,你只需要配置好账号密码和连接池数量,就能很开心的使用mysql了。

从mysql的角度来说,客户端多是一些IO密集型的应用,应该在一个线程里频繁做大量IO操作,而不是说有大量的客户端来反复连接我。毕竟,mysql的用户是你写的几个程序应用,而web server的用户是海量的。

连接池

mysql能支撑的连接数是有限的,那么就需要应用程序来利用好连接池。对于连接池来说,就是做好这10个连接的管理就好。

对于mysql来说,管理好自己的所有连接也是很重要,哪些空闲的该休息就休息,让出资源,该复用就复用,避免创建太多线程。

IO密集的时候,要减少连接数。

譬如要读写几千万数据,非常密集的IO操作,那么你可以尝试一下开启少量的mysql连接(和cpu的核数相同)和开启大量的连接(成百上千),来做同样的事。你会发现,更少的连接数,会给你带来几百倍的性能提升。

譬如,你有4辆车(4核),要从仓库里拉一大堆货物到另一个地方。如果只有4条路,简单操作,一个车走一路,反复折返跑。现在有了100条路,还是4个车,车要频繁的在100条路上来回切换,每条路都必须要走到。

线程间的轮转会耗费大量的资源,尤其在密集操作时。但是当不密集时,情况就变了,大量的线程处于休息状态,那么你即便多开了几个连接,CPU还是能很快的照顾到你,并没有什么大的影响。

网络协议

作为RPC的连接,内部rpc数据协议

一分也是爱,两分情更浓【还没有人赞赏,支持一下呗】