因为项目需要,最近学习了使用Yii2框架的使用。但毕竟刚上手,好多地方都不清楚。所以就有了这个博客。
1、需求
有这么一个需求:
后台需要访问用户的一个界面。为了界面不出问题,需要传递一个真实存在的Token。但对这个Token没有任何限制。
这里就偷了个懒,毕竟Token没有任何的限制。因此,直接访问了Token库,并从中读取一个数据。读取完成后就直接发给前端了。
UsersToken::find()->one()['token'];
毕竟不是什么大需求,经过测试后没有问题就这么上线了。
2、 问题
明明测试环境没问题的
但问题来了。上线后接口反而由于某种原因报错了。报错倒是简单,没有任何的报错信息,而是直接返回504。
这实在不正常。由于项目配置好了错误处理,一旦报错,必然能返回错误响应。只要有错误响应,自然能够排查出问题。
经过一番排查无果,选择向运维大哥要一下报错日志。结果得到了这个:
Allow memory size of 526385152 bytes exhausted (tried to allocate 4096 bytes) in xxx/xxxxx/xxx/xxxxxx...
大致内容看懂了,内存爆了: (
仔细查看代码,其他的执行条件没有任何问题。而Token的查询也很简单,不是很像有能力出问题的样子。所以陷入了某种僵局。
3、排查
查了种种资料没能看到一个解决方法~~(废话,这么弱智的问题竟然还要查资料 )~~。后来不得以翻了翻源码。最终在one()
方法中找到了这么一句话:
Executes query and returns a single row of result.
执行查询,并返回结果的第一条。
初见端倪。继续深入源码,翻到了执行的部分:
可以看到,在执行过程中,实际上是先执行了查询语句select * from user_token
,得到了数组result
。之后返回数组的第一条数据,也就是result[0]
。
4、原因
迎刃而解。由于在构建查询语句时,没有加上相应的限制。因此,将user_token表中的全部数据写入到了内存中。由于测试环境的数据比较少,因此没有出现问题。但正式环境中数据很多,超过了内存限制,这才出现了BUG。坑爹啊
5、解决
最后手动加上了限制,问题解决。
UsersToken::find()->limit(1)->one()['token'];