mysql async connector
所做的项目有个需求,有一个线程接收Udp请求然后向mysql的一个表插入一行记录.由于不希望该功能过多占用CPU,因此只用一个线程。 一开始用mysql-connector-c++作为客户端,由于只有单线程,插入速度不如人意。 主要是原因是网络延迟太大,线程大部分时间阻塞在等待数据库返回数据,于是考虑用异步的方式访问数据库。
目前mysql官方只有C#版本的connector有async操作的支持, mysql-connector-c/c++ 都没有提供异步操作的API.
但mariadb-connector-c提供了兼容mysql
的non-block API。
(该网页提到mysql-connector-c早就支持non-blocking,但没看出来怎么用,也找不到任何示例..)。
mariadb提供了一个使用异步API的demo,里面结合了libevent,最主要的部分是异步操作状态机的实现,看着比较费解, 我重新改写了,放在这里。
以下是一些测试结果(被插入记录的表使用InnoDB存储引擎;mysql数据库在同一台主机上;测试代码见 blocking,non-blocking):
记录数 | 阻塞式 | 非阻塞式 | 时间比 |
---|---|---|---|
1 | 0.031 | 0.029 | 1.1 |
100 | 3.011 | 0.624 | 4.8 |
10000 | 328.636 | 67.098 | 4.9 |
其中非阻塞式用了10个mysql连接。连接数增加时,耗时更少,几乎成反比(直到到达数据库处理能力的极限).
使用非阻塞式确实能够加快数据库操作,但存在问题:代码的复杂性增加了,特别是对于一些查询类操作,如果使用非阻塞操作的话,势必要维护每一个数据库请求的上下文数据. 很多情况下也可以通过使用阻塞式API但增加线程数(也即是数据库连接数)来解决这个问题,未必要使用非阻塞的API。
mariadb官网文档认为有以下场合比较适合使用非阻塞式API:
- 需要获取多个数据库的数据以进行下一步操作,用异步API可以使这些数据库请求并行化。
- 原有的代码使用了libevent等非阻塞式的框架
由于同一个连接无法同时处理多个查询,因此不管是阻塞还是非阻塞,连接数增加才有可能提高TPS。 当然,数据库的处理能力才是最根本的限制,在数据库处理能力内,可以通过选择合适的连接数来使数据库的能力达到最大值.但数据库处理能力跟不上的话,无论是阻塞式还是非阻塞,增加连接数也无法提高吞吐量。
回到我开始提到的需求来说,由于我只是插入记录,而且几乎不会有插入失败的情形,因此几乎不用维护上下文,可以使用这种异步的方式来操作数据库,既提高了处理速率,又不会产生太多的线程资源。
使用过程中发现mariadb-connect-c中,mysql连接关闭时没有清理使用异步mysql而额外申请的内存,顺便提了个pull request。