webman mysql数据库连接自动释放资源问题

anlla

项目描述
1。定时任务每秒提交订单至redis队列处理订单是否过期
2。自定义进程异步websocket客户端获得数据并写入数据库
3。其它就是一些常规crud操作的接口。
4。项目用think-orm操作mysql 8.0。

异常描述:
运行一段时间后,内存使用率会升高不少,稳定要65%左右。然后接口提交的数据像写入内存没实际写入数据库里一样,比如:下单流程执行成功,刷新订单列表,新产生的订单通过接口拉取是正常,刷新页面再拉取的订单列表就会没有刚新下的订单。再刷新又会有新订单。 如此往复,重启mysql数据库服务后,之前新下的订单就会消失,再下订单一切正常。查看自增ID,会缺失。

下图是查询异常的截图

之前全部php-fpm开发,逻辑上还是按php-fpm开发,项目重新基于webman开发 开发前已避免手册上无限注入静态变量的造成内存泄露问题。查阅资料 php start.php status查看是正常.
目前无法理解cli模式下,数据连接用完是否销毁,如果是连接池是如何重复利用的,是否有手动归还连接的操作?
上面的问题应该如何解决?以后开发中的注意事项

还希望大神能帮助解决一下。

504 2 6
2个回答

walkor

linux系统与windows不同,linux会尽可能利用内存提高性能,65%如果是指整个系统的内存使用率,实际上是一个很低的值。一般linux系统内存占用都在90%左右都是正常的。即时占用90%,也不意味着是webman程序自身占用。

新订单时而显示时而消失看起来和事务有关,有可能是有事务没提交。请检查所有事物相关的代码(注意用try catch(\Throwable $e),不要用try catch(\Exception $e ) 。

截图中的报错是因为数据库没启动或者重启导致的,如果数据库重启过,报这个错很正常。

webman中一般不需要关注内存泄漏问题,因为webman会自动跟踪各个进程使用情况,如果真的有内存泄漏达到一定值会安全重启对应进程,对业务无影响。如果你关心内存泄漏,根据手册,只需要注意静态数组不要无限膨胀即可,和静态变量没有直接关系。

webman里数据库连接用完不会销毁,也不需要程序手动归还连接,不需要做任何其它操作。只需要注意事物记得在业务里提交或者回滚。

  • anlla 17天前

    我想的也是事务那块的问题,重启后回滚才造成自增ID删除的。
    目前业务提交是按tp的事务提交方式提交
    Db::startTrans();
    try {
    ...
    Db::commit();
    return msg('提交成功')
    } catch (\Exception $e) {
    Db::rollback();
    return msg($e->getMessage())
    }
    不知道这样写是否会有问题?如果没问题为何会运行一段时间事务就无法提交?

  • Le 16天前

    catch 那里要用Throwable 不是exception吧

  • 王八念经 16天前

    学习

  • walkor 1天前

    你多虑了,webman里请求是排队处理的,不会出现一个进程同时处理多个请求的情况,不会出现你说的事物不完整数据混乱的情况。当然你业务有bug在一个请求里没有提交或者回滚事物除外。

    另外连接池也不会因为你使用事物去频繁的断开连接,连接池的一个主要目的就是避免频繁创建销毁数据库连接。

    一个进程只有一个mysql链接,8个worker进程,同时只能8个人同时访问数据库。

  • walkor 1天前

    事物用 try {} catch (\Throwable $e) {Db::rollback();}就没问题哈,这个是基本的事物操作。如果你对自己代码没有信心,可以弄个中间件,在请求处理完毕的时候判断下是否有未提交的事物,自己决定是否提交或者回滚。

  • evilk 1天前

    之前回答过这个问题,现在再多讲两句
    之前我们也遇到跟楼主一模一样的问题
    当时觉得非常震惊和担心
    上一个请求的事务没有提交或者回滚,的确是会影响下一个请求
    这就需要保证每一个请求的事务,都必须提交或者回滚,不能挂起(这个需要使用者自己来保证)
    最后检查了代码,所有事务,都 catch (Throwable $throwable) 而非 catch (Exception $exception)

  • walkor 1天前

    感谢你对workerman的支持,不过对于完善workerman的生态,我没有不耐心哈 😂

  • nitron 1天前

    业务层面的问题,不应由框架去保证,毕竟DB层的Adapter太多,有人用EloquentORM,有人用ThinkORM, 有人用Medoo,有人用Doctrine,还有人用简单PDO
    而且也说了, catch Throwable即可

  • 咸鱼.php 20小时前

    第一次见到说walkor没有“耐心”的,有空多看看问答,walkor在线解决了多少问题,还有哪个框架的作者会这样回答问题?

  • 张大娃 20小时前

    我也觉得walkor是最有耐心的作者了,其他作者至今还没看到如此亲力亲为回答问题并提供解决分析的了

evilk

我们之前遇见过类似的问题
页面上显示有数据,再次刷新或者重启后,数据消失
检查了代码,排查了各种可能性
可能是某个请求的事务被挂起了
既没有提交,也没有回滚
同一个进程,处理下一个请求的时候,如果发生回滚,会把之前的事务一起回滚了
检查了所有事务的地方

  • 最终全部使用 catch (Throwable $throwable) 而非 catch (Exception $exception)
  • 注册register_shutdown_function函数,在请求结束后,检查事务状态
    后面再也没有出现过类似情况

常驻内存模式下,同一个进程,只会维护一个MySQL链接,所有请求都复用这个MySQL链接
所以一定要确保每个请求处理完成后,该请求的事务,要么提交,要么回滚
如果挂起了,就会和下个请求互相影响

  • anlla 17天前

    好的,提供了一些思路,我尝试一下,谢谢!

  • tanhongbin 16天前

    php中是怎么判断事务是否存在和提交没提交的??查了半天没找到

  • anlla 16天前

    PHP7中使用Throwable来捕获的话比使用register_shutdown_function这个函数来得更方便,也更推荐Throwable,Error类也是可以捕获到致命错误,不过Error只能捕获致命错误,不能捕获异常Exception,而Throwable是可以捕获到错误和异常的,所以更推荐

  • evilk 16天前

    @anlia 正确

  • 咸鱼.php 15天前

    学习了

🔝