久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

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

瀏覽:99日期:2024-09-24 08:18:01

起因

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

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

處理過程

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

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

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

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

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

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)

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

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ù)越多,問題越明顯

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

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

在Django的文檔中其實(shí)做了說明

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.

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

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

總結(jié)

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

問題

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

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

延伸閱讀

https://docs.djangoproject.com/en/3.0/ref/models/querysets/ https://www.jb51.net/article/151604.htm

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

標(biāo)簽: Django
相關(guān)文章:
主站蜘蛛池模板: 欧美一区 | 中文在线播放 | 美女天堂网 | 国产成人在线一区二区 | 精国产品一区二区三区 | 91av导航| 日日久 | 成人精品在线观看 | 色综合免费| 日韩免费网站 | 久久久精彩视频 | 四色永久| 日韩在线不卡 | 久久精品1区 | 久久精品国产77777蜜臀 | 日韩欧美二区 | 午夜精品久久久久久久久久久久 | 福利片在线观看 | 亚洲三级在线播放 | 日韩在线你懂的 | 精品亚洲一区二区三区四区五区 | 欧美日韩三区 | 色中色综合 | 91免费在线看 | 青青草国产| 亚洲一区二区视频在线播放 | 欧美一区二区三区 | 国产中文字幕一区 | 亚洲一区二区三区四区的 | av中文字幕在线播放 | 鲁一鲁影院| 99久久久久久 | 日本成人在线视频网站 | 人人爱夜夜爽日日视频 | 久久伊人中文字幕 | 国产一区二区三区在线 | 国产传媒视频 | 国产精品乱码一区二区三区 | 成人毛片在线观看 | 日韩精品久久久久久 | 亚洲第1页|