mysql接收查询的请求连接时,会有对应的线程来接收并处理请求,随着需求的日益增长,单一的一对一模式已经不能满足请求的膨胀,因此,新版本的mysql提供了几种处理模式来应对需求。
单线程模式(No-Threads)
单线程模式也就是只有一个主线程来完成所有的请求处理,通常只用于调试。
一对一模式(one-connection-per-thread)
也就是传统的处理模式,该模式下一个线程对应处理一个请求,缺点也明显,首先请求过多的情况下会造成处理线程快速膨胀,产生不稳定的状态,第二,线程过多会占用大量的资源,增加系统负担,影响运行速度,第三,线程的等待、线程上下文切换、资源锁机制等会严重拖慢系统。
线程池模式(Pool-Threads)
线程池模式能够更好的应对多连接和高并发的需求,是目前的默认模式。这里先说下其原理,其实这个模式的核心思想有点类似于java的常用容器的hashmap中的hash桶,将请求分配到每个组(Group)中进行处理,每个组包含一定数量的处理线程(worker)和一个侦听线程(listener),因为线程数量是有限的,只能让外部请求共享这写线程,为了保证访问顺序和提供优先处理策略,这些请求会被放入组中的正常队列或优先队列。优先队列中的请求会被优先处理,避免发生等待资源解锁时间过长。
Group组的数量、Group中的worker都是可以自定义的,另外,除了Group,还有个守护线程timer,它会监控group的状态有无“偷懒”或“罢工”。
线程池和连接池的关系
通常所说的数据库线程池,指的就是mysql创建的处理请求的线程组,而连接池一般指的是应用程序对DB进行请求操作的线程集合,为什么应用程序需要用到线程池呢?如hibernate等orm框架需要使用第三方连接池管理连接,这是由于应用程序多度的请求DB时可以缓冲DB线程池的压力,在前段对请求频率进行控制,从而缓冲高并发带来的压力,也就是说,线程池和连接池是相互配合使用来发挥共同作用的。
线程池和连接池的优化
有关这方面是一个复杂的话题,在概念上来说,主要是两方面的问题:
线程池的调度死锁
熟悉sql过程和多查询我们会知道,如果A查询时间较长,而B查询需要的到A查询锁定的资源,而此时A又依赖B查询,这就造成的死锁,通常情况下我们应该在sql中进行处理,如果仅仅是因为A查询时间较长,但并没有出现真正意义上的死锁,应当开启优先队列,让worker优先处理这些查询。
线程池已满
请求数量大,或者连接池配合不好,或者是一些复杂大量查询,都容易造成线程池占满,也就是group中的队列增长速度超过了worker的处理速度,此时group就会发生“停滞”,外部请求就会长时间排队等候响应,如果时间过长就会影响大了,何时停滞是由线程数的阈值来设定的,如果出现这种情况,可以根据硬件和系统负荷调整阈值,如果仅仅是某个特定的查询或操作造成的,可以将这些处理的线程排除在统计和监控范围之外。