OneSQL :: 线程池(Thread Pool)虽好,线上启用须提防连接饿死现象!

数据库的线程池(Thread Pool)技术,可以提升高并发连接下的数据库性能,不过这是有条件的,即每个请求处理时间都差不多时,非常有效,反之则效果很差。其内部实现机制和现在流行的消息编程差不多,即处理消息的速度要一样快,最好全是短平快的。在深入分析线程池技术后,平民软件在OneSQL里实现了多队列的线程池,可以很好地避免大小请求混合的情况,现在我们来做一个测试,假设我们分别开启200个会话来执行如下两条SQL语句:

select * from t_binlog where id = :id;
update t_binlog set col3 = col3 - 1 where id = :id;

请注意是200个会话只执行第一条SQL,另外200个会话执行第二条语句,而不是400个会话执行两条SQL语句。相对来讲select处理会比交快,而update会比较慢,以模拟不同大小的请求混合的情况。使用“mydbtest”工具时,配置文件如下所示:

option
  user ......
  time 1m
  log  /dev/null
  groups 2
declare
  id int 1 10
begin
  group 1 select * from t_binlog where id = :id;
  group -1 update t_binlog set col3 = col3 - 1 where id = :id;
end

在8 Core的机器上,我们将线程池的大小设成16,使用“5.6.26-74.0 Percona Server (GPL)”版本;OneSQL使用的是最新的“5.6.31”版本。测试的表只有10条记录,可以完全存放在内存中,在OneSQL版本上测试结果如下:

[root@rhel data]# ./mydbtest_linux64.bin query=testonesql.sql degree=400
Summary: SQL01 exec=2409091, rows=2409091=100/e, avg=5012 us
Summary: SQL02 exec=387400, rows=387400=100/e, avg=31491 us
Summary: exec=45104/s, qtps=45104/s

可以看到Select语句和Update语句相互干扰的情况比较轻。再来看一下Percona线程池版本下的测试结果,可能会让人沮丧:

[root@rhel data]# ./mydbtest_linux64.bin query=testpercona.sql degree=400
Summary: SQL01 exec=126076, rows=126076=100/e, avg=98748 us
Summary: SQL02 exec=101545, rows=101545=100/e, avg=124843 us
Summary: exec=3347/s, qtps=3347/s

采用线程池后, 如果大操作(在这里是Update)的并发较高,线程池的工作线程会被大量占用,从而让小操作得不到机会来执行,产生严重的读写相互影响的情况,称之为线程池饿死现象。因此在生产环境上实际开启线程池的情况并不多,没办法做到所有的操作都同样大小,考虑到数据库事务的因素,可以情况会比Update更严重。在测试单纯的主键Select操作时(只测试第一条SELECT语句),线程池效果要比OneSQL要好。

[root@rhel data]# ./mydbtest_linux64.bin query=testpercona.sql degree=400
Summary: SQL01 exec=7946675, rows=7946675=100/e, avg=3029 us
Summary: exec=128172/s, qtps=128172/s
[root@rhel data]# ./mydbtest_linux64.bin query=testonesql.sql degree=400
Summary: SQL01 exec=7368335, rows=7368335=100/e, avg=3305 us
Summary: exec=118844/s, qtps=118844/s

如果你的应用SQL复杂度都差不多,则可以用线程池来应对高并发,但如果SQL复杂度相差较大,则建议使用OneSQL来应对高并发的情况。OneSQL已经帮助国内某大型连锁超市成功地度过了大型促销活动,无须应用做任何修改,即可以实施上线。