HWSQL线程池实现原理
HWSQL线程池实现原理
常见场景
数据库在平时的应用开发中是不可或缺的一部分。但是,随着应用越来越复杂,一个数据库承载的应用数量逐渐增加,数据库性能随着负载的增加而降低。为了解决这个问题,大家可能使用了中间件来管理数据库连接,或者干脆将数据库拆分。但是,使用中间件使用了新的组件,引入了不稳定的风险;数据库拆分又没有充分使用硬件的性能。所以,一款能够使用大量连接,并在大量连接下仍能够保证良好的执行效率的数据库就显得格外重要。
那么,为什么数据库性能会随着连接数的增加而降低呢?目前MySQL社区版针对每一个连接都创建一个线程来处理该连接的请求。当并发请求过大时,操作系统会在资源上和线程调度上耗费大量的资源。线程的频繁切换还会带来大量的内存页面失效和CPUcache的不命中,内存换页和重新cache会导致MySQL运行效率大幅度降低。这样,使用线程池的方式处理任务针对大量请求连接变得十分必要。
线程池特性分析
线程池的设计原理为:
1) 创建线程池,线程池中有线程组,每个线程组中有若干个线程。
2) 网络连接多路复用,循环监听所有套接字,一次获取可读的套接字。
3) 针对每一个可读的套接字,从线程池中选择空闲的线程组,处理该请求。
4) 处理完成后线程组变为空闲状态,等待新的任务。
5) 线程组中有高优先级队列和低优先级队列,已经开始事务或者获得锁的任务更容易被执行,防止大量已经处理但未处理完的半成品。
6) 低优先级的任务不会发生过长时间的饥饿,会根据情况切换到高优先级队列中。
以下是连接的处理示意图,能够更加形象的说明该特性的原理。
MySQL社区版连接处理示意图
上图为社区版本的连接示意图,MySQL会对每个连接创建一个服务线程,该线程持续等待用户的请求,并负责处理该请求并返回结果。
HWSQL线程池对连接的处理示意图
上图为HWSQL线程池处理连接的方式,用户连接由线程池负责调度处理。线程个数由参数配置,不会因为连接数的增加而增加,这样能够提高cache和内存页面的命中率,减少线程切换以及线程本身对系统资源的消耗。
通过Sysbench压力测试可以发现,MySQL社区版的TPS随着连接数的增大先增加后减小,最后降低趋近为0,而使用了线程池的HWSQL的TPS随着连接数的增大而增加,最后保持最大值。
插件形式提供线程池功能
MySQL有一套完善的插件机制,定制化的功能可以使用插件的形式来实现。使用插件可以避免修改MySQL代码和主要流程,降低代码耦合。可以动态加载和卸载,使用灵活。可以对插件进行独立升级,减少代码修改带来的影响。
有关连接管理和调度部分,MySQL已经考虑到了自定义开发,在官方提供的两种调度管理外,还提供了一个抽象类让用户自定义连接的管理方法,以及为插件提供了初始化,去初始化方法。所以,线程池借助了这些便利,使用插件的形式实现是再好不过的了。
HWSQL使用了插件实现线程池,避免大量侵入MySQL原有逻辑。并方便用户进行配置,参数组的开启和关闭使用一个配置即可实现。
性能测试(基于MySQL5.6,性能仍在不断优化提升)
Sysbench workload 测试结果
- 点赞
- 收藏
- 关注作者
评论(0)