锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

聊一个不常见的面试题:为什么数据库连接池不采用 IO 多路复用?

时间:2022-08-21 23:30:01 1208tj2连接器2431tj62连接器

前沿技术早就知道了,弯道超车有希望

积累超车资本,关注DD开始

作者:大宽宽,图文编辑:xj

来源:https://www.zhihu.com/question/23084473

今天我们来谈谈一个不常见的事情 Java 面试题:为什么数据库连接池不使用 IO 多路复用?

这是个很好的问题。IO多路复用被认为是一种很好的性能助力器。但我们通常使用它 DB 或者经常使用c3p0tomcat connection pool等技术来与 DB 即使整个程序已经成为连接Netty这到底是为什么?

首先,纠正常见的误解。IO多路复用听起来像多个数据可以共享一个IO(socket事实上,连接并非如此。「IO多路复用并不意味着多个服务共享一个连接,而只意味着多个连接的管理可以在同一过程中进行」。在网络服务中,IO多路复用的作用是「一次性通知业务代码处理多个连接事件」。至于这些事件的处理方法,业务代码是循环处理,扔进队列,还是交给线程池,由业务代码决定。

对于使用DB就程序而言,无论是多路复用还是连接池,都要维护一组网络连接,支持并发查询。

为什么要使用多个连接来完成并发查询?因为DB一般采用连接作为Session基本单位的管理。在连接中,SQL句子的执行必须串行同步。这是因为每一个Session,DB维护一组状态支持查询,如事务隔离等级,目前Session的变量等。只有单Session为了保持查询的正确性(想象一组sql不断增减变量,然后这组sql乱执行会发生什么?维持这些状态需要消耗内存和消耗CPU和磁盘IO。这样,限制对DB连接数是限制对的DB资源消耗。

因此,对DB关键是限制连接的数量。无论这个要求如何DB连接池还是NIO可以做到连接管理。

这样问题就回来了,为什么?DB不能放置连接IO多路复用一起执行吗?为什么每个人都使用连接池?

答案是,可以用IO但是「使用JDBC不行」。JDBC它的设计核心是近20年的标准BIO(因为199X年时还没有别的IO可用):调用者正在通过JDBC时执行比如query这样的API,在没有执行完成之前,整个调用线程被卡住。而类似于Mysql Connector/J这样的driver这套语义已经完全实现。

当然如果DB Client协议的连接处理和分析稍有变化:

  1. 将IO模式调整为Non-Blocking,这样就可以挂了IO内核多路复用(select、epoll、kqueue……)

  2. 在Non-Blocking实现的基础之上实现数据库协议的编码和解析

可实现使用IO多路复用访问DB。其实很多其他语言/框架都是这样做的。 Nodejs,see https://github.com/sidorares/node-mysql2;或者 Vert.X 的 db 客户端https://github.com/mauricio/postgresql-async,不要在意这个名字,它实际上时支持它mysql和postgres)。只不过对于IO官方数据库似乎没有支持多路复用——他们只支持JDBC、ODBC等等这些标准协议。

顺便说一近整理了一批,包括C 、java、Python、JavaScript以及各种语言,以及操作系统、数据结构、设计、网络等学习材料,您可以关注公共账户TJ回复武功秘籍领取。

那为什么基于呢? IO 多路复用的实现不能是默认的、官方的,而是偏门的?

对于数据库开发者来说。这种用法在整个用户中占有很小的份额,所以可能不值得努力。只需要写清楚协议(比如https://dev.mysql.com/doc/internals/en/client-server-protocol.html),可以实现。然后社区里有兴趣的人自然可以做。

另一个原因是系统的支持。简单地说,如果没有大的话 Reactive 的运行环境,IO 多路复用的使用会非常有限。

IO 多路复用之所以能成立,是因为需要「有一个整个程序IO多路复用驱动代码」——就是 select 调用-等待事件的到来,一个 blocking 的 API。整个程序必须以这个驱动代码为核心。这对整个代码的结构有很大的影响。这种影响不能用简单的界面抽象。

Java Web 容器之所以可以使用 NIO 是因为 NIO 容器内在容器内。Web 传统的多线程形式仍然暴露在容器的外部Java EE接口。

如果 DB 和 Web 同时使用容器 NIO,那么调用的DB连接库与必须与容器有一个约定描述「DB如何接入连接管理Web容器的NIO的驱动代码」。在 Java 在这种环境下,不同的人,不同的容器写不同的代码;或者,不要使用任何常见的容器,而是自己使用 NIO 包装一个。这不能在代码上形成协议。如此多的独立组件不能很好地共享 NIO 驱动代码。

上面这个用法假设整个程序应该共享一个 NIO 驱动代码。那么 Web 和 DB 能不能各用各的?也可以,但是为了保证这两个 NIO 驱动代码不会相互 block,最好分开两个线程。这样,它就会被打破 Web 用一个线程处理一个请求的一般做法会让程序边更复杂——你的业务代码和DB跨线程数据交换必须在查询之间进行。

相反,连接池的实现相对独立和简单。只要外部世界匹配得当 DB URL,可自行管理用户名密码和连接池的容量参数。

NodejsVert.X完全不同。它们的本质是Reactive的。他们的NIO驱动模式是其运行的基础——在此基础上开发的所有代码都必须遵守相同的代码NIO 使用相同的异步开发规范NIO驱动DBNIO合作不是问题。

最后,「需要大量的场景BIO的DB查询支持的」。批处理数据分析代码都是这样的场景。这样的程序写成NIO得不偿失——代码不容易理解,效率没有优势。Nodejs这样的运行时在此场景下,反而要利用async或者等价语法让代码看起来同步,这样很容易写。

总结一下。DB 这种现象通常是由生态引起的。历史上的 BIO 经过多年的发展,连接池的实践已经解决了主要问题。在 Java 这个方案在大环境下非常可靠成熟。而基于 IO 虽然多路复用方法在性能上可能有优势,但对整个程序的代码结构要求太高,太复杂。当然,如果有特定的需要,我希望使用它 IO 多路复用管理 DB 连接是完全可行的。

顺便说一句,我们创建了一个高质量的技术交流小组。当我们和优秀的人在一起时,我们会变得优秀。点击添加组,享受一起成长的快乐。

推荐阅读

  • 新冠肺炎疫苗制造商科兴成立房地产公司?网友:准备给房子打疫苗?

  • 干掉Postman?直接生成测试接口API强烈推荐文档!

  • Apache Dubbo 通知高危漏洞

前沿技术早就知道了,弯道超车有希望

积累超车资本,关注DD开始

点击阅读原文,送你免费Spring Boot教程!

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章