高并发系统设计40讲之 池化技术

系统架构中,数据库的连接时间比SQL的执行时间要长,
为了提高效率,使用数据库连接池将连接预先建立好

用连接池预先建立数据库连接

数据库连接池有两个最重要的配置:最小连接数和最大连接数,它们控制着从连接池中获取连接的流程:

  1. 如果当前连接数小于最小连接数,则创建新的连接处理数据库请求;
  2. 如果连接池中有空闲连接则复用空闲连接;
  3. 如果空闲池中没有连接并且当前连接数小于最大连接数,则创建新的连接处理请求;
  4. 如果当前连接数已经大于等于最大连接数,则按照配置中设定的时间(C3P0 的连接池配置是 checkoutTimeout)等待旧的连接可用;
  5. 如果等待超过了这个设定时间则向用户抛出错误。

连接池故障:

  1. 数据库的域名对应的 IP 发生了变更,池子的连接还是使用旧的 IP,当旧的 IP 下的数据库服务关闭后,再使用这个连接查询就会发生错误;
  2. MySQL 有个参数是“wait_timeout”,控制着当数据库连接闲置多长时间后,数据库会主动地关闭这条连接。这个机制对于数据库使用方是无感知的,所以当我们使用这个被关闭的连接时就会发生错误。

如何保持连接池可用:

  1. 启动一个线程来定期检测连接池中的连接是否可用,比如使用连接发送“select 1”的命令给数据库看是否会抛出异常,如果抛出异常则将这个连接从连接池中移除,并且尝试关闭。目前 C3P0 连接池可以采用这种方式来检测连接是否可用,也是我比较推荐的方式。
  2. 在获取到连接之后,先校验连接是否可用,如果可用才会执行 SQL 语句。比如 DBCP 连接池的 testOnBorrow 配置项,就是控制是否开启这个验证。这种方式在获取连接时会引入多余的开销,在线上系统中还是尽量不要开启,在测试服务上可以使用。
用线程池预先创建线程

JDK 1.5 中引入的 ThreadPoolExecutor 就是一种线程池的实现,它有两个重要的参数:coreThreadCount 和 maxThreadCount,它的执行原理和数据库连接池类似
在这里插入图片描述
线程池中使用的队列的堆积量也是我们需要监控的重要指标,尤其对于实时性要求比较高的任务。
如果你使用线程池请一定记住不要使用无界队列。可能使用无界队列后,任务就永远不会被丢弃。但是大量的任务堆积会占用大量的空间,一旦内存空间被占满就会频繁的触发full GC,造成服务不可用。

池化技术的核心思想是空间换时间,对于创建过程比较耗时的,统一放在一个池子里管理,以达到提升性能和资源复用的目的。

存在的缺陷:
存储池子中的对象肯定需要消耗多余的内存,如果对象没有被频繁使用,就会造成内存上的浪费
池子中的对象需要在系统启动的时候就预先创建完成,这在一定程度上增加了系统启动时间

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章