服务器中部署多个laravel应用时配置读取错乱的问题

小滴    PHP    999+次    2018-09-10 11:56:52


出现的问题

无意中发现,在多个基于Laravel(5.2)的Web应用中,当应用A进行一个长时间操作时(PHP会运行超过30s+),在这期间,在应用B中进行数据库操作时,B应用会连接到A应用中的数据库,而非B的数据库。

下面的这段错误就是因为不知道为何连接到了A数据库而出现的:

QueryException in Connection.php line 655: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'database_a.member_user' doesn't exist (SQL: select * from member_user limit 1)

    in Connection.php line 655
    at Connection->runQueryCallback('select * from member_user limit 1', array(), object(Closure)) in Connection.php line 611
    at Connection->run('select * from member_user limit 1', array(), object(Closure)) in Connection.php line 324
    at Connection->select('select * from member_user limit 1')
    at call_user_func_array(array(object(MySqlConnection), 'select'), array('select * from member_user limit 1')) in DatabaseManager.php line 296
    at DatabaseManager->__call('select', array('select * from member_user limit 1')) in Facade.php line 216
    at DatabaseManager->select('select * from member_user limit 1') in Facade.php line 216
    at Facade::__callStatic('select', array('select * from member_user limit 1')) in IndexController.php line 35
    at DB::select('select * from member_user limit 1') in IndexController.php line 35
    at IndexController->index(object(ConfigService), object(WechatQrcodeService))
    at call_user_func_array(array(object(IndexController), 'index'), array(object(ConfigService), object(WechatQrcodeService))) in Controller.php line 256
    at Controller->callAction('index', array(object(ConfigService), object(WechatQrcodeService))) in ControllerDispatcher.php line 164
    at ControllerDispatcher->call(object(IndexController), object(Route), 'index') in ControllerDispatcher.php line 112
    at ControllerDispatcher->Illuminate\Routing\{closure}(object(Request))
    at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139
    at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
    at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103
    at Pipeline->then(object(Closure)) in ControllerDispatcher.php line 114
    at ControllerDispatcher->callWithinStack(object(IndexController), object(Route), object(Request), 'index') in ControllerDispatcher.php line 69
    at ControllerDispatcher->dispatch(object(Route), object(Request), '\App\Controller\Wecolour\IndexController', 'index') in Route.php line 203

第一个猜想到的是不是在B应用连接数据库时,直接使用的是A应用中连接数据库的的资源ID,但是感觉这种情况应该不会出现。

另外一种情况,就是读取数据库配置的时候出错了,读取到了A应用的数据库配置信息,但是这个感觉理论有点不太可能,因为两个应用完全在两个不同的位置(后来证实确实是第二点)。

Laravel使用了 vlucas/phpdotenv 这个包来加载 .env 文件中的配置信息,具体的过程如下:

  1. 从 .env 文件中读取配置信息;
  2. 调用 putenv() 方法将配置信息设置到PHP环境中;
  3. 调用 Laravel 封装的 env() 方法来读取配置信息(env() 中其实调用了 getenv() 方法来配置信息读取);

.env 文件主要功能是为了在不同的部署环境实现不同配置,这样不同的环境可以共用同一套代码;
putenv() 和 getenv() 是PHP4,PHP5,PHP7支持的用来设置和获取环境变量(environment variable)的方法。

问题就出现在这里:

getenv() 和 putenv() 不是一个线程安全的函数,意味着如果两个线程同时调用这个函数,就会出现问题。

而且服务器的环境正好是:

Apache + worker 模式,这种模式下,php运行环境是以线程模式运行的,所以才出现了上述的问题。

解决办法

将.env中的配置写到/config/xxx.php中(记得执行php aritisan config:clear)
启用php进程运行模式;
将配置单独放在php配置文件中,这个可能造成硬编码,不过不推荐;
等待Laravel修复这个问题。

或者大家有没有遇到过这个问题,交流一下解决办法。


最新评论

是他是他就是他 回复:写的很棒![em_63][em_63][em_63]受教了

2019-07-19 11:45:33 回复


是他是他就是他 回复 是他是他就是他:很棒啊

2019-09-23 10:48:16 回复


最新评论

网站数据

网站文章数:305

注册用户数:18

TOP