PHP提高连接数据库的效率
目录
最近小编方包在学习到java使用连接池操作mysql数据库提高效率的课程中,突发奇想!php能不能实现这个黑科技呢?答案是肯定的!使用连接池相当于一个容器,可以大大提高php连接数据库的运行效率!说起来,不单单只有连接池,还有多种方法也能提高db数据库的效率。以下是小编总结能提高php连接数据库的效率的几种方法:
1.用mysql_connect()函数建立一个单例类
比如:
class DB { private static $db=NULL; private function __construct() { ; } public static function conn() { if(self::$db==NULL) { self::$db=mysql_connect('localhost','root','****'); } return self::$db; }
2.直接使用pconnect长连接
3.建立一个数据库操作类,构建实例的时候连接数据库,销毁的时候关闭连接(mysql_close)
4.优先采用长连接PHP代码
if(mysql_pconnect()) { $conn=mysql_pconnect(); }else{ $conn=mysql_connect(); }
以上四个方式采用哪个性能高?或者针对不同的并发情况,什么场景使用什么连接较好?
在php层面,无论你怎么写代码,都是半斤八两,没啥区别。我来强调下长连接和普通链接的区别:
永久链接并不是说,服务器打开了一个连接,然后所有的人都共享这个链接。永久连接一样是每个客户端来就打开一个连接,有200人访问就有200个连接。其 实mysql_pconnect()本身并没有做太多的处理, 它唯一做的只是在php运行结束后不主动close掉mysql的连接。
在php经cgi方式运行时pconnect和connect是基本没有区别的, 因为cgi方式是每一个php访问起一个进程, 访问结束后进程也就结束了, 资源也全释放了. 当php以apache模块方式运行时, 由于apache有使用进程池, 一个httpd进程结束后会被放回进程池, 这也就使得用pconnect打开的的那个mysql连接资源不被释放, 于是有下一个连接请求时就可以被复用.这就使得在apache并发访问量不大的时候, 由于使用了pconnect, php节省了反复连接db的时间, 使得访问速度加快. 这应该是比较好理解的. 但是在apache并发访问量大的时候, 如果使用pconnect, 会由于之前的一些httpd进程占用的mysql连接没有close, 则可能会因为mysql已经达到最大连接着, 使得之后的一些请求永远得不到满足.若mysql最大连接数设为500, 而apache的最大同时访问数设为2000,假设所有访问都会要求访问db, 而且操作时间会比较长,当前500个请求的httpd都没有结束的时候,之后的httd进程都是无法连接到mysql的(因已经达到mysql最大连接 数). 只有当前500个httpd进程结束或被复用才可以连接得到了mysql。
当db操作复杂, 耗时较长时, 因httpd会fork很多并发进程处理, 而先产生的httpd进程不释放db连接, 使得后产生的httpd进程无法连上db. 因为这样没有复用其它httpd进程的mysql连接. 于是会就产生很多连接超时。 在并发访问量不高时,使用pconnect可以简单提高访问速度, 但在并发量增大后, 是否再使用pconnect就要看程序员的选择了。
php对mysql的连接并没有真正用到连接池, pconnect也只是相当于借了apache的进程池来用, 所以在并发访问量大的时候pconnect并不能很好的提高访问db效率。
在实际的应用中,用mysql_pconnect的话,每次刷新和请求新的页面都比较快,而用mysql_connect的话,每次刷新都要重新请求,当数据库连接比较慢的时候,就能看出差异了。当你的数据库连接比较慢,DB操作不是很复杂,并且你对自己的程序足够自信,不会产生死锁的时候,且你对服务器有控制权的话,满足以上四个条件中的任意两个,那么就可以用 pconnect。
pconnect不用在脚本里关闭,可以在mysql中设置lifetime,也可以写shell定期扫描,kill掉休眠过长的连接。 一句话总结:要用好pconnect,不仅仅是php脚本的事 还关系到数据库和服务器的设置。
PHP使用数据库长连接,让性能提升30%
一直认为在高并发情况下相对于java,php没有数据库长连接是很吃亏的。直到我翻php.net看到了数据库长连接和连接与连接管理。
废话不多说先上教程:
本文使用tp5+php7.1,需要更改think\library\think\Connection.php给
protected $params = [ PDO::ATTR_CASE => PDO::CASE_NATURAL, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, PDO::ATTR_STRINGIFY_FETCHES => false, PDO::ATTR_EMULATE_PREPARES => false, ];
添加一个属性
PDO::ATTR_PERSISTENT => true
即可。值得注意的是,fpm进程管理模式必须是static(同时要配置合适的连接数,建议自己花点时间慢慢试试)。压力测试结果表明整体性能提升30%。
5.php – 数据库连接池实现
php-cp(php-connect-pool)是用php扩展写的一个数据库连接池。
一、它不同于市面上其他的开源数据库中间件产品
1、它不需要单独部署中间件集群,是跑在应用服务器上的代理进程,减少了一层外部依赖,这样使得架构更加简单、清爽、可靠。
2、性能更高,减少了一次网络传输,它通过高效的ipc方式和php进程通信,并且避免了协议解析的消耗。
3、同时支持redis和mysql,不需要部署2套单独的中间件系统。
二、简单原理图
三、技术特性
1、支持最大最小连接数配置。
2、支持压力小自动回收连接(力度和频率可配置)。
3、支持平滑重启。
4、支持连接用光的排队机制。
5、同时支持mysql和redis。
6、使用简单,框架简单整合后(修改new 方法),现有业务一行代码都不用改即可用上连接池。
7、提供了get_disable_list函数,来获得不可用的宕机ip列表,这样负载均衡也可以做在客户端(配置文件全部的ip和宕机ip做差集,然后再随机即可)。 btw:你也可以用lvs,但是lvs转发在系统架构上引入了依赖,dr模式不能跨网段又限制了扩容,而且后端db出问题只能知道lvs的vip。
8、连接池进程会启动ping进程来监听宕机列表,如果可用会反映到get_disable_list函数的返回值上。
9、做了大量优化,虽然请求经过连接池进程转发,但是基本无qps损耗。
四、如何使用
1、把pool.ini文件放到 /etc/ 并按需修改里面的配置。
2、启动代理进程 ./pool_server start 支持 “start” “stop” “restart” “reload”命令
3、修改php脚本 $db = new PDO(xxxxx); 修改成 $db = new pdo_connect_pool(xxxx);//dont use persistent $redis = new Redis();
修改成 $redis = new redis_connect_pool();//dont use pconnect
提示: 尽早调用$db/$redis->release() 来释放这个进程占用的连接到池子里面。
6.php实现Redis缓存技术
以下是redis缓存技术及应用场景介绍:
Remote Dictionary Server(Redis) 是一个开源的由Salvatore Sanfilippo使用ANSI C语言开发的key-value数据存储服务器。其值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型,所以它通常也被称为数据结构服务器。
Redis特点
redis足够简单和稳定
支持丰富的数据结构
内存存储读写性能优秀
提供持久化的支持
支持事务操作
提供主从复制功能
Redis与memcache性能压力测试比较
Redis的典型应用场景:
一:缓存热点数据
热点数据(经常会被查询,但是不经常被修改或者删除的数据),首选是使用redis缓存,redis的性能非常优秀。
二:计数器
诸如统计点击数、访问数、点赞数、评论数、浏览数等应用,由于单线程,可以避免并发问题,保证数据的正确性,并且100%毫秒级性能,同时开启Redis持久化,以便于持久化数据。
三:单线程机制
验证前端的重复请求,可以自由扩展类似情况),可以通过redis进行过滤,比如,每次请求将Request IP、参数、接口等hash作为key存储redis(幂等性请求),设置多长时间有效期,然后下次请求过来的时候先在redis中检索有没有这个key,进而验证是不是一定时间内过来的重复提交;再比如,限制用户登录的次数,比如一天错误登录次数10次等。
秒杀系统,基于redis是单线程特征,防止出现数据库超卖;
全局增量ID生成等;
四:排行榜
谁得分高谁排名在前,比如点击率最高、活跃度最高、销售数量最高、投票最高的前10名排行等等;
五:分布式锁
使用redis可以实现分布式锁,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
互斥性,在任意时刻,只有一个客户端能持有锁。
不会发生死锁,即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
具有容错性,只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
解铃还须系铃人,加锁和解锁必须是同一个客户端,客户端不能解他人加的锁。
六:Session存储
使用Redis的进行会话缓存(session cache)是非常常见的一种场景。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化,目前大量的方案均采用了redis作为session的存储方案。
php如何使用redis?
本文实例讲述了PHP使用redis实现统计缓存mysql压力的方法。分享给大家供大家参考,具体如下:
<?php header("Content-Type:text/html;charset=utf-8"); include 'lib/mysql.class.php'; $mysql_obj = mysql::getConn(); //redis $redis = new Redis(); $redis->pconnect('127.0.0.1', 6379); if(isset($_SERVER['HTTP_REFERER'])){ $url_md5 = md5($_SERVER['HTTP_REFERER']); } $adve_key = 'adve'; $adve_key_exists = 'adve_exists'; if(!$redis->exists($adve_key_exists)){ $list = $mysql_obj->fetch_array("select * from user_online_adve"); if($list){ foreach ($list as $key => $value) { $url_hash = md5($value['adve_url']); $adve_hash_key = $adve_key.":".$url_hash; $id = $value['id']; $redis->set($adve_hash_key,$id); $redis->set($adve_key_exists,true); //$redis->hmset($adve_hash_key, array('id' =>$id)); //print_r($redis->get($adve_hash_key)); } } } $adve_new_key = $adve_key.':'.$url_md5; if($redis->exists($adve_new_key)){ $adve_plus = $adve_new_key.":plus" ; if(!$redis->exists($adve_plus)){ $redis->set($adve_plus,1); }else{ $redis->incr($adve_plus); $num = $redis->get($adve_plus); if($num >10){ $id = $redis->get($adve_new_key); // insert to sql; $mysql_obj->query("update user_online_adve set adve_num=adve_num+$num where id=$id"); $redis->set($adve_plus,1); } } } header('HTTP/1.0 301 Moved Permanently'); header('Location: https://itunes.apple.com/cn/app/san-guo-zhi15-ba-wangno-da-lu/id694974270?mt=8'); /* if(){ $adve_plus = $adve_key.":plus" ; if($redis->exists($adve_plus)){ $redis->incr($adve_plus); }else{ $redis->set($adve_plus,1); } echo $redis->get($adve_plus); } foreach ($list as $key => $value) { $url_hash = md5($value['adve_url']); $id = $value['id']; $adve_num = $value['adve_num']; $adve_plus = $adve_key.":plus" ; if($redis->exists($adve_plus)){ $redis->incr($adve_plus); }else{ $redis->set($adve_plus,1); } echo $redis->get($adve_plus); //if($redis->) //$redis->hmset($adve_key, array('id' =>$id, 'adve_num'=>$adve_num)); //print_r($redis->hmget("adve:$url_hash", array('adve_num'))); } print_r($list); */
送福利了!关注下方的公众号:“优派编程”,搜索关键词“下载”,即可获得软件app下载资源和python、java等编程学习资料~
更多课程和学习资料请登录“方包博客”———http://fang1688.cn
更多资源请关注公众号或点击下方“阅读原文”,回复关键词获取