因為項目需要,最近學習了使用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'];