workerman如何写mysql连接池

Roger

workerman如何写mysql连接池

13952 4 16
4个回答

walkor

首先要了解为什么用连接池,连接池能为你解决什么问题

连接池主要的作用
1、减少与数据服务器建立TCP连接三次握手及连接关闭四次挥手的开销,从而降低客户端和mysql服务端的负载,缩短请求响应时间
2、减少数据库的并发连接数,即解决应用服务器过多导致的数据库 too many connections 问题

如果是为了解决问题1

则在workerman中数据库连接池不是最高效的方法。当前PHP PDO是阻塞式的,很难用原生PDO在当前进程做连接池。如果用单独的进程去做,那么就会涉及到进程间的通讯,使得原本和mysql直接通讯的过程变成 与连接池再到mysql的通讯,增加了应用端的负载。

解决问题1最高效的方法是为每个业务进程建立一个数据库单例(例如workerman提供的DB类),实现数据库长连接,这样每个进程的所有请求都使用自己的这一个数据库长连接,整个进程的生命周期只有一次TCP握手和断开连接挥手的开销,并且应用与mysql直接通讯,没有连接池那样中间一层进程间IPC通讯,性能是最高的,没有之一。

如果是为了问题2
首先看下自己到底有多少台应用服务器,每台服务器与mysql有多收并发连接。假如你只有10台应用服务器,每个服务器50个进程,每个进程1个数据库连接,那么到mysql服务端总共只有10*50=500个并发连接(并非活跃连接),500个并发连接对于mysql来说可以承受,为了解决问题2完全没有使用连接池的必要。

假如你有1000台应用服务器,那么连接池是有必要的,但是这个连接池不能是运行在本地应用服务器上的连接池,因为1000台应用服务器就有1000个连接池,即使每个连接池只开10个连接,那么数据库的连接数也会轻松打满。所以不要指望在当前服务器上开几个task进程实现的连接池就能解决这个问题。

1000台应用服务器的集群,每台服务器上搞几个进程实现连接池同样是不靠谱的方法。真正能够解决问题2的方法是建立一个独立的数据库连接池服务器或者说集群,全局管理所有的数据库链接。

综上所述,
如果单独是为了问题1实现php的mysql连接池,那么数据库单例是比所谓的连接池更简单更高效的做法。
如果是为了实现问题2,那么想必业务也有一定的规模了,如果真心是想用workerman做个单独的连接池集群,下面是大概简单的做法,建立一些task进程,每个进程创建一个数据库连接,task进程收到sql请求后发送给mysql服务器,mysql服务器返回后task进程再把结果发给sql发起者。

连接池代码类似如下 如果是多台服务器组成的连接池集群,前面最好加一个lvs

// task worker,使用Text协议
$task_worker = new Worker('Text://0.0.0.0:1234');
$task_worker->count = 64;
$task_worker->name = 'MysqlTask';
$task_worker->onMessage = function($connection, $sql)
{
    // 执行sql.... 得到结果,这里省略....
    $sql_result = your_mysql_query($sql);
    // 发送结果
    $connection->send(json_encode($sql_result));
};

在workerman中调用

use \Workerman\Connection\AsyncTcpConnection;

// 与远程连接池服务建立异步链接,ip为远程连接池服务的ip,如果是集群就是lvs的ip
$sql_connection = new AsyncTcpConnection('Text://ip:1234');
// 发送sql
$sql_connection->send("SELECT ... FROM .....");
// 异步获得sql结果
$sql_connection->onMessage = function($sql_connection, $sql_result)
{
    // 这里只是打印结果
    var_dump(json_decode($task_result));
};
// 执行异步链接
$sql_connection->connect();
lt

对于WM服务器框架,特别适合每个进程一个单例数据库连接!

  • 暂无评论
evilk

借用之前网上看到的一句话

连接池仅在超大型应用中才有价值
大部分人需要的不是数据库连接池来提高性能,而是sql的优化.
很多连这样的sql都不知道怎么正确建索引 select * from table where a=3 and b=4 orderby c DESC
我见过的程序员里60%都认为3列都建索引就好了
还有20%认为应该用c的索引让mysql排序用索引
还有10%会认为要建立三列的复合索引
其实这样的基本功,再怎么上连接池也是徒劳的
合理的缓存和索引才是解决问题的根本办法
别把架构搞复杂了才是好架构 连接池里如果有慢查询,mysql还是会卡住的
应该说,只有先做到整个应用完全没有慢查询,并且所有的查询速度都很快
比如都在0.0x秒以内。并且query查询已经降到最低(用了大量的缓存)
这个时候还扛不住,再去研究连接池吧
因为连接池主要解决的并不是sql性能问题,而是mysql服务器和系统层面的性能问题

  • liziyu 2022-03-07

    正解,学习了。

  • joytom 2022-03-07

    有道理,学习了

  • nitron 2022-03-07

    那么问题来了,上面这个sql该怎么设置索引呢[doge]

  • fa1se 2022-03-07

    是的,问题就来了,该怎么建索引,看看有多少人是剩下的10%

  • Tinywan 2022-03-07

    别把架构搞复杂了才是好架构

  • banro512 2022-03-08

    第一反应应该是建立 a,b,c 的联合索引
    实际测了下

    数据表记录行:7,725,756
    a,b,c 均为int(11)类型字段
    建立一个名为 ce 的索引,分别为 (a,b,c)联合索引,(a,b)联合索引,单列索引a,单列索引b,单列索引c

    每个查询重复多次,取最小值,实测联合索引 a,b,c 查询效率最高。最左、where、顺序、一次sql只使用一个索引

    explain 如下

    
    -- 联合索引 ce(a,b,c) 最小耗时0.028s 使用了索引
    explain SIMPLE  df_bet_platform_log_tsff    ref ce  ce  8   const,const   1        Using where
    
    -- 联合索引 ce(a,b)   最小耗时0.028s  使用了索引
    
    explain SIMPLE  df_bet_platform_log_tsff    ref ce  ce  8   const,const   1        Using where; Using filesort
    
    -- 单列索引 ce(a)     最小耗时0.031s  使用了索引
    
    explain SIMPLE  df_bet_platform_log_tsff    ref ce  ce  4   const         3775203   Using where; Using filesort
    
    -- 单列索引 ce(b)     最小耗时0.031s  使用了索引
    
    explain SIMPLE  df_bet_platform_log_tsff    ref ce  ce  4   const         1         Using where; Using filesort
    
    -- 单列索引ce(c)     最小耗时0.031s 未使用索引
    
    explain SIMPLE  df_bet_platform_log_tsff    ALL                           7467888   Using where; Using filesort
    
gddd

学习了

  • 暂无评论
年代过于久远,无法发表回答
🔝