网站高性能架构设计——池化

开发过程中会用到很多的连接池,像是数据库连接池、HTTP 连接池、Redis 连接池等等。而连接池的管理是连接池设计的核心

1.连接池

(1)连接池管理的关键点

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

  • 如果当前连接数小于最小连接数,则创建新的连接处理数据库请求;
  • 如果连接池中有空闲连接则复用空闲连接;
  • 如果空闲池中没有连接并且当前连接数小于最大连接数,则创建新的连接处理请求;
  • 如果当前连接数已经大于等于最大连接数,则按照配置中设定的时间(C3P0 的连接池配 置是 checkoutTimeout)等待旧的连接可用;
  • 如果等待超过了这个设定时间则向用户抛出错误。
  • 在这里,需要注意池子中连接的维护问题,有的连接虽然还存在,但有的时候会有故障:
  • 数据库的域名对应的 IP 发生了变更,池子的连接还是使用旧的 IP,当旧的 IP 下的数据 库服务关闭后,再使用这个连接查询就会发生错误;
  • MySQL 有个参数是“wait_timeout”,控制着当数据库连接闲置多长时间后,数据库会 主动的关闭这条连接。这个机制对于数据库使用方是无感知的,所以当使用这个被关闭 的连接时就会发生错误。 有以下解决方案
    • 启动一个线程来定期检测连接池中的连接是否可用,比如使用连接发送“select 1”的命 令给数据库看是否会抛出异常,如果抛出异常则将这个连接从连接池中移除,并且尝试关闭。目前 C3P0 连接池可以采用这种方式来检测连接是否可用。
    • 在获取到连接之后,先校验连接是否可用,如果可用才会执行 SQL 语句。比如 DBCP 连 接池的 testOnBorrow 配置项,就是控制是否开启这个验证。这种方式在获取连接时会引 入多余的开销,在线上系统中还是尽量不要开启,在测试服务上可以使用。


 

(2)httpclient连接池设置

HttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams params = httpConnectionManager.getParams();
params.setConnectionTimeout(5000);
params.setSoTimeout(20000);       
params.setDefaultMaxConnectionsPerHost(32);//每个host路由的默认最大连接    
params.setMaxTotalConnections(256);//qps*建立连接时间*预留时间(一般是1.7)       


 

(3)为什么不用IO多路复用

DB 访问一般采用连接池这种现象是生态造成的。历史上的 BIO + 连接池的做法经过多年的发展,已经解决了主要的问题。在 Java 的大环境下,这个方案是非常靠谱的,成熟的。而基于 IO 多路复用的方式尽管在性能上可能有优势,但是其对整个程序的代码结构要求过多,过于复杂。当然,如果有特定的需要,希望使用 IO 多路复用管理 DB 连接,是完全可行的。

(4)数据库连接为什么费资源

MySQL 的通信协议是基于 TCP 传输协议的,所以需要经过三次握手和四次挥手

2.用线程池预先创建线程

(1)线程池简介

JDK 1.5 中引入的 ThreadPoolExecutor 就是一种线程池的实现,它有两个重要 的参数:coreThreadCount 和 maxThreadCount

  • 如果线程池中的线程数少于 coreThreadCount 时,处理新的任务时会创建新的线程;如果线程数大于 coreThreadCount 则把任务丢到一个队列里面,由当前空闲的线程执 行;
  • 当队列中的任务堆积满了的时候,则继续创建线程,直到达到 maxThreadCount;当线程数达到 maxTheadCount 时还有新的任务提交,那么我们就不得不将它们丢弃 了。

(2)线程池设置

最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

比如平均每个线程CPU运行时间为0.5s,而线程等待时间(非CPU运行时间,比如IO)为1.5s,CPU核心数为8,那么根据上面这个公式估算得到:((0.5+1.5)/0.5)*8=32。这个公式进一步转化为:

最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目

线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。

3.什么时候考虑使用池化

当遇到下面的场景,就可以考虑使用池化来增加系统性能:

  • 对象的创建或者销毁,需要耗费较多的系统资源;
  • 对象的创建或者销毁,耗时长,需要繁杂的操作和较长时间的等待;
  • 对象创建后,通过一些状态重置,可被反复使用。

将对象池化之后,只是开启了第一步优化。要想达到最优性能,就不得不调整池的一些关键参数,合理的池大小加上合理的超时时间,就可以让池发挥更大的价值。和缓存的命中率类似,对池的监控也是非常重要的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值