对象池、连接池的意义

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 对象池就是一个在程序启动的时候先创建好若干个可以重复使用的对象。 当程序其他地方需要使用该类型对象时,不再是向系统申请创建,而是向池发出请求。 池将会从池内发配出一个对象提供使用,当程序使用完毕后,需要将对象归还给对象池做管理。

这次我们来讲讲对象池、连接池的意义,在此之前我们先了解学习一些其他的基础知识,以便我们结合理解池的意义。


#nginx与php-fpm的进程模型


nginx采用多进程模型,启动之后的进程将包含一个master和多个worker进程。 master是worker的父进程,主要职责是用来管理worker进程的。


  • 向worker进程发送信号,如通知退出
  • 监控worker状态,当worker退出后(无论正常异常),可以重新启动新的worker。


可以实现从容重启:master进程在接收到信号后,会先重新加载配置,然后再启动新进程开始接收新请求,并向所有老进程发送信号告知不再接收新请求并在处理完所有未处理完的请求后自动退出。


worker进程负责处理请求,如果是静态文件则可以直接处理完,如果是php程序还需要调用php来处理,当php处理完成时获取php的返回,并返回给客户端。 采用的是异步非堵塞,当调用php的时候不会堵塞等待,会抽空处理下一个请求,当php处理完成时恢复之前的请求并返回给客户端。 php-fpm是php-cgi的管理器,在php >= 5.3.3就已经集成在php中了。 它的出现提供了更好的php管理方式


  • 可以平滑停止/启动php进程(重载配置生效)
  • 可以配置监控多个端口和使用不同的配置


php脚本的解释器是php-cgi php-fpm是一个管理器,管理对象是php-cgi php-fpm实现了fastcgi协议,当php-fpm启动时,会启动多个cgi解释器进程。 web服务器可以发送数据给php-fpm,php-fpm再把数据发给php-cgi处理。(跟nginx发送数据给php-fpm类似)


#常驻内存下程序的对象回收


常驻内存程序是指把自己装入内存后将控制返回给操作系统,直到运行结束、异常、用户手动退出才会中断运行的程序。 当程序运行时,对象和变量将会一直存在。除非在程序中释放销毁。


#高并发下频繁new对象的资源占用


当我们new一个对象的时候,需要先经过这几个步骤:类加载检查、分配内存空间、设置类的基本信息、调用初始化构造函数。


首先我们看看构造函数这一块,这是在代码中按我们的需求和意愿编写的。 在这一块中我们经常会做一些配置检测、数据初始化、数据库连接(网络io)等。


接下来是分配内存空间 OS的内存分配器一般是预先向OS申请一大段内存。然后每次分配时,再将里面的一小段标记为已分配,释放的时候再标记成未分配。 由于是有很多程序在运行,所以分配和释放会交替存在,得到的结果可能是 分配1段-未分配1段-分配2段-未分配2段 一个一个的未分配就是内存碎片,会占用额外的内存,碎片不一定可以马上被重复使用(当分配不出连续内存时,需要向OS申请更多的内存)


同时,创建和销毁对象时,OS都需要做一些处理工作,也会产生资源占用。


new太多对象,然后导致cpu负载上线让全站死机的概念


若程序未产生IO(网络请求、读写文件等),执行时间等于cpu的占用时间。 频繁地创建销毁对象将会占用更多cpu资源,高并发时容易导致cpu长期处于高负载运行状态。


什么是对象池


对象池就是一个在程序启动的时候先创建好若干个可以重复使用的对象。 当程序其他地方需要使用该类型对象时,不再是向系统申请创建,而是向池发出请求。 池将会从池内发配出一个对象提供使用,当程序使用完毕后,需要将对象归还给对象池做管理。


对象池服务可以减少从头创建每个对象的系统开销。


大并发下多个mysql连接导致mysql繁忙全站崩溃


<?php
function db(){
    return mysqli_connect("localhost","root","root"); 
}
for ($i=0; $i < 10000; $i++) { 
    $name  = "db{$i}";
    $$name = db();
}


这一个demo将会产生报错:Warning: mysqli_connect(): (08004/1040): Too many connections 我们习惯性地在PHP脚本中不会主动关闭mysql连接,而是等到脚本运行完毕之后再由gc自动回收。在这个期间将会继续占用连接资源,而连接资源的数量又是有限制的,所以会更快出现连接不够用的情况。 处理会影响程序的运行,同时还将可能导致全站崩溃


  • mysql是一个连接创建一个线程处理。
  • 创建销毁mysql线程需要的内存等性能消耗、线程缓存命中率下降
  • mysql底层几乎在同时需要处理几百个线程提交的查询请求,而cpu一次只能处理一条指令,并且数据库查询需要产生IO,在IO期间cpu将会切换上下文处理其他的请求,当cpu频繁切换上下文,性能抖动,发生性能下降甚至宕机的情况。


连接池 保护mysql不崩溃


连接池是将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对数据库进行访问。


<?php
class Pool{
    private $pool = [];
    private $min = 5;
    private $max = 100;
    private $now;
    public function __construct()
    {
        // 在池创建的时候就先创建好一些连接
        for ($i = 0 ; $i < $this->min; $i++){
            $this->pool[] = mysqli_connect("localhost","root","root");
            $this->now++;
        }
    }
    public function get()
    {
        // 这里要判断当前池还有没有空闲的
        // 若没有,则判断当前已经提供的服务数量大不大于最大数量   如果还没有达到最大数量  可以向系统再申请一个资源到池中
        // 如果已经达到最大数量,并且池内没有服务了,则进行短暂等等看看有没有
        // 需要销毁避免同一个连接多处使用,会冲突
        $connect = array_shift($this->pool);
        return $connect;//伪代码
    }
    public function recovery($connect)
    {
        $this->pool[] = $connect;
    }
}


因为连接池需要长期保持在线,在传统的php脚本中不支持,在swoole中可以常驻内存运行,即可使用连接池


这样省略了创建连接和销毁连接的过程。这样性能上得到了提高。 然而除了性能上的提高外,还有一个意义也很重要:保护服务稳定运行,不发生全站崩溃。 在上面一点我们已经提到,更多的链接将会导致cpu频繁切换上下文,性能抖动,严重情况时将会全站崩溃。 假设本来我们的服务器配置是可以保证1000个连接同时稳定运行,突然某一时刻有3000个人并发,导致连接不够用,那么是保证原有1000人都正常运行好,还是让这3000人争抢资源最终导致机器响应不了全站崩溃好呢?


#连接池的意义此时才得以体现,我们设置连接池的最大数量为机器能承受并且稳定运行的最大数量。


当已经有这么多的数量在服务的时候,后面的请求申请连接资源时需要进行短暂的等待,若时间到了还是没有空余连接提供,则需要熔断服务,返回给客户端失败。 这样子可以保证机器长期稳定服务。若是越来越多的客户端申请不到资源,则需要提高机器配置。(因为我们的连接池最大数量已经是机器的瓶颈,只能通过硬件配置来提升能服务的数量)


nginx - php fpm在大并发下504


在最开始的时候已经介绍过nginx和php的运行进程模型,php-fpm就是一个池管理器,内部装了若干个php-cgi程序,当nginx申请解析php脚本时,php-fpm则分配一个php-cgi出去处理,处理完则收回管理。 在高并发下,nginx会产生504错误,这就是我们上面介绍到的,客户端进行了短暂的 等待 后,仍然申请不到资源,则只能告诉客户端失败。 (在京东、淘宝的大活动期间很有机会碰到504错误哦! 这种情况下我们一般只需要刷新页面即可。 因为再刷新时大几率已经有连接资源空闲了!)


  • Nginx 504 Gateway Time-out的含义是没有请求到可以执行的PHP-CGI。


总结


连接池、对象池的意义不仅仅是可以减少频繁创建销毁对象连接的性能开销 更大的意义是可以保证应有服务客户端的稳定运行。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
7月前
|
安全 数据库连接 数据库
连接池的并发和线程安全
连接池的并发和线程安全
|
druid Java 数据库连接
什么是连接池?为什么需要连接池呢?连接池的组成原理又是什么呢?
什么是连接池?为什么需要连接池呢?连接池的组成原理又是什么呢?
797 0
什么是连接池?为什么需要连接池呢?连接池的组成原理又是什么呢?
|
10天前
|
监控 数据库
优化连接池
合理设置连接池大小:连接池的大小应根据应用程序的并发量和数据库的承载能力来设置。过小的连接池会导致频繁的等待和阻塞,过大的连接池则会浪费资源。 连接池的监控和管理:实时监控连接池的使用情况,及时处理连接泄漏和失效连接,可以使用一些连接池管理工具来实现自动监控和管理。 连接池参数调整:根据实际情况调整连接池的参数,如连接超时时间、空闲连接的最小和最大数量等,以提高连接池的效率和稳定性。
16 0
|
7月前
|
安全 Java 数据库连接
C# | 对象池
当我们在做软件开发时经常会需要创建很多的相同且特殊的对象,比如线程、内存、数据库连接、文件句柄等,这类特殊对象有着占用IO资源、创建或销毁的开销大等特点,会导致系统的性能下降和资源浪费。而对象池的出现就是为了解决此类问题,使用对象池来管理这些对象让它们可以被重复使用,从而提高效率。
86 0
|
SQL 缓存 关系型数据库
连接池设置
连接池设置
109 0
|
监控 Java 数据库连接
c3p0连接池
c3p0连接池
144 0
|
存储 缓存 网络协议
数据访问连接池和线程池
报文请求头通过设置报文的传输方式和URL, 以及一些简单的客户端请求过来的数据,携带的数据量不能太大。通过报文请求头传输数据的方式类型为GET请求,GET请求的方式数据编码方式和数据服务器的编码方式一致,数据传输需要通过加密和解密的过程。JAVA 的WEB应用服务器的默认编码方式是IOS8859-1. 默认的国际化字符编码方式编码的对象是字符CHARACTER,对于中国汉字的编码和存储有UTF-8 和 GB2312 . 默认的国际化字符编码方式每个字符使用一个字节存储,汉字的存储需要两个字节。
67 0
|
设计模式 SQL druid
jdbcs之连接池和框架
jdbcs之连接池和框架
158 0
jdbcs之连接池和框架
连接池问题
连接池问题
173 0
|
缓存 安全 Java
数据库连接池为什么要用 ThreadLocal 呢?(不用会怎样?)
数据库连接池为什么要用 ThreadLocal 呢?(不用会怎样?) 本人是在学threadlocal的时候,网上大部分人都是说数据库连接池是典型的用了threadloca的例子,然后我就又查数据库连接池和
数据库连接池为什么要用 ThreadLocal 呢?(不用会怎样?)