欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

記一次django內(nèi)存異常排查及解決方法

 更新時間:2020年08月07日 09:10:51   作者:syncd  
這篇文章主要給大家介紹了關(guān)于一次django內(nèi)存異常排查記解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用django具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

起因

Django 作為 Python著名的Web框架,相信很多人都在用,自己工作中也有項目項目在用,而在最近幾天的使用中發(fā)現(xiàn),部署Django程序的服務(wù)器出現(xiàn)了內(nèi)存問題,現(xiàn)象就是運行一段時間之后,內(nèi)存占用非常高,最終會把服務(wù)器的內(nèi)存耗盡,對于Python項目出現(xiàn)內(nèi)存問題,自己之前處理過一次,所以并沒有第一次解決時的慌張,自己之前把解決方法也整理了:http://www.dbjr.com.cn/article/151604.htm

但是事情似乎并沒有我想的那么簡單,自己嘗試用之前的的方法tracemalloc庫進(jìn)行問題的排查,但是問題來了實際的項目中有快一百多個接口,怎么排查?難道一個一個接口進(jìn)行測試排查,但是時間又比較緊急,可能又來不及了。對比上次自己解決是因為上次的項目比較簡單,相對來說定位問題比較容易,那么這次怎么處理呢?

處理過程

一般Python項目其實是很少出現(xiàn)內(nèi)存問題的,一般都是自己代碼寫的有問題導(dǎo)致的,而對于這次出現(xiàn)的問題,自己的排查思路(對于web 接口類型的項目):

  1. 先排查調(diào)用比較頻繁的接口
  2. 然后排查數(shù)據(jù)匯總接口(查詢比較復(fù)雜)
  3. 如果上述還沒有查出來,再排查剩余的接口

在這次的問題排查中,自己大致也是按照這個思路進(jìn)行的,在對調(diào)用頻繁的接口進(jìn)行排查時,并沒有發(fā)現(xiàn)內(nèi)存的異常,而出現(xiàn)內(nèi)存的問題則是在數(shù)據(jù)匯總的相關(guān)接口上。

其實這種接口對于初級開發(fā)可能是容易出問題的地方,首先這種接口查詢的數(shù)據(jù)相對其他接口會比較復(fù)雜,如果編碼基礎(chǔ)又不是特別好,可能就會在這些接口上出現(xiàn)bug.

而在這次的排查中,最終確定是在一個匯總數(shù)據(jù)的接口上,定位到問題處在了Django ORM 使用不當(dāng)導(dǎo)致的。自己通過一個簡單代碼實例來說明:

class Student(models.Model):
 name = models.CharField(max_length=20)
 name2 = models.CharField(max_length=20)
 name3 = models.CharField(max_length=20)
 name4 = models.CharField(max_length=20)
 name5 = models.CharField(max_length=20)
 name6 = models.CharField(max_length=20)
 name7 = models.CharField(max_length=20)
 name8 = models.CharField(max_length=20)
 name9 = models.CharField(max_length=20)
 name10 = models.CharField(max_length=20)
 name11 = models.CharField(max_length=20)
 name12 = models.CharField(max_length=20)
 name13 = models.CharField(max_length=20)
 name14 = models.CharField(max_length=20)
 name15 = models.CharField(max_length=20)
 age = models.IntegerField(default=0)

正常情況,我們的表字段會比較多,這里就通過多個name來模擬,出現(xiàn)題的代碼就出在關(guān)于這個表的接口上:

def index(request):
 studets = Student.objects.filter(age__gt=20)
 if studets:
  pass
 return HttpResponse("test memory")

為了讓內(nèi)存問題容易復(fù)現(xiàn),我通過腳本向Student中插入了20000條數(shù)據(jù),當(dāng)然這里數(shù)據(jù)越多,問題越明顯

通過一個測試腳本并發(fā)請求這個接口,觀察內(nèi)存情況,你會發(fā)現(xiàn),內(nèi)存會出現(xiàn)瞬間上漲的情況,并且如果你的數(shù)據(jù)越多,請求越多,你的內(nèi)存可能會在一段時間居高不下,并且逐漸上漲。問題出在哪里了?

其實很簡單,問題出在了代碼中的if 判斷那里,我們通過filter 查詢返回的是QuerySet 類型的數(shù)據(jù),而我們過濾之后的數(shù)據(jù)可能會存在非常多的時候,這個時候我們通過if 直接判斷,自己的理解這個地方會將整個QuerySet加載到內(nèi)存中,從而出現(xiàn)內(nèi)存占用過高的問題,而如果并且這個時候這個接口的響應(yīng)速度也是非常會變慢,而這個QuerySet 中的數(shù)據(jù)越多,內(nèi)存占用越明顯。

在Django的文檔中其實做了說明

exists()¶
Returns True if the QuerySet contains any results, and False if not. This tries to perform the query in the simplest and fastest way possible, but it does execute nearly the same query as a normal QuerySet query.

exists() is useful for searches relating to both object membership in a QuerySet and to the existence of any objects in a QuerySet, particularly in the context of a large QuerySet.

The most efficient method of finding whether a model with a unique field (e.g. primary_key) is a member of a QuerySet is:

entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
 print("Entry contained in queryset")

Which will be faster than the following which requires evaluating and iterating through the entire queryset:

if entry in some_queryset:
 print("Entry contained in QuerySet")

And to find whether a queryset contains any items:

if some_queryset.exists():
 print("There is at least one object in some_queryset")

Which will be faster than:

if some_queryset:
 print("There is at least one object in some_queryset")

… but not by a large degree (hence needing a large queryset for efficiency gains).

Additionally, if a some_queryset has not yet been evaluated, but you know that it will be at some point, then using some_queryset.exists() will do more overall work (one query for the existence check plus an extra one to later retrieve the results) than using bool(some_queryset), which retrieves the results and then checks if any were returned.

所以對于我們的代碼我們只需要把if 判斷地方改成if not studets.exists() 就可以解決問題。

這是一個很小的知識點,但是如果使用不對,可能就會造成非常嚴(yán)重的內(nèi)存問題。

總結(jié)

除了單元測試,還需要做大數(shù)據(jù)量測試,這次的問題如果在測試的時候做過一定數(shù)據(jù)量的測試,可能很早就能及時發(fā)現(xiàn)

問題

對于基礎(chǔ)的庫的使用要更加熟悉

排查問題的思路要明確,不然可能會無從下手

延伸閱讀

到此這篇關(guān)于django內(nèi)存異常排查及解決方法的文章就介紹到這了,更多相關(guān)django內(nèi)存異常排查內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 用Python編寫一個簡單的Lisp解釋器的教程

    用Python編寫一個簡單的Lisp解釋器的教程

    這篇文章主要介紹了用Python編寫一個簡單的Lisp解釋器的教程,Lisp是一種源碼簡單的函數(shù)式編程語言,本文主要介紹對其中的一個子集Scheme的解釋器開發(fā),需要的朋友可以參考下
    2015-04-04
  • 解決springboot yml配置 logging.level 報錯問題

    解決springboot yml配置 logging.level 報錯問題

    今天小編就為大家分享一篇解決springboot yml配置 logging.level 報錯問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • python獲取微信企業(yè)號打卡數(shù)據(jù)并生成windows計劃任務(wù)

    python獲取微信企業(yè)號打卡數(shù)據(jù)并生成windows計劃任務(wù)

    由于公司的系統(tǒng)用的是Java版本,開通了企業(yè)號打卡之后又沒有預(yù)算讓供應(yīng)商做數(shù)據(jù)對接,所以只能自己搗鼓這個,以下是個人設(shè)置的一些內(nèi)容,僅供大家參考
    2019-04-04
  • matplotlib實現(xiàn)數(shù)據(jù)實時刷新的示例代碼

    matplotlib實現(xiàn)數(shù)據(jù)實時刷新的示例代碼

    這篇文章主要介紹了matplotlib實現(xiàn)數(shù)據(jù)實時刷新的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • python 排列組合之itertools

    python 排列組合之itertools

    python 排列組合之itertools,需要的朋友可以參考一下
    2013-03-03
  • Python學(xué)習(xí)之文件的創(chuàng)建與寫入詳解

    Python學(xué)習(xí)之文件的創(chuàng)建與寫入詳解

    本文主要介紹了Python中關(guān)于文件的處理,即如何創(chuàng)建、讀寫一個文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-03-03
  • python中pandas nlargest()的詳細(xì)用法小結(jié)

    python中pandas nlargest()的詳細(xì)用法小結(jié)

    df.nlargest()是一個DataFrame的方法,用于返回DataFrame中最大的n個值所在的行,通過調(diào)用nlargest()方法,我們返回了分?jǐn)?shù)最高的三個行,并按照降序排列,本文結(jié)合實例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-10-10
  • Python多線程編程(三):threading.Thread類的重要函數(shù)和方法

    Python多線程編程(三):threading.Thread類的重要函數(shù)和方法

    這篇文章主要介紹了Python多線程編程(三):threading.Thread類的重要函數(shù)和方法,本文講解了線程名稱、join方法、setDaemon方法等內(nèi)容,需要的朋友可以參考下
    2015-04-04
  • python中異常報錯處理方法匯總

    python中異常報錯處理方法匯總

    之前在學(xué)習(xí)python的時候有整理過python異常處理的文章,不夠簡單也不夠完整,所以決定再整理一篇,算做補充,大家學(xué)習(xí)一下,就可以自己思考解決方法了,希望對大家能夠有所幫助
    2016-11-11
  • python實現(xiàn)selenium截圖的兩種方法

    python實現(xiàn)selenium截圖的兩種方法

    本文主要介紹了python實現(xiàn)selenium截圖的兩種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04

最新評論