诱因

Django 做为 Python知名的Web架构,坚信很多人都会用,自身工作中中也有新项目新项目再用 ,而在近期几日的应用中发觉,布署Django程序流程的网络服务器出現了内存难题,状况便是运作一段时间以后 ,内存占用十分高,最后会把网络服务器的内存耗光,针对Python新项目出現内存难题 ,自身以前解决过一次,因此 并沒有第一次处理时的惊慌,自身以前把解决方案也梳理了blog:https://www.cnblogs.com/zhaof/p/10031945.html

可是事儿好像并沒有我觉得的这么简单 ,自身试着用以前的的方式tracemalloc库开展难题的排查,可是那么问题来了具体的新项目中有快一百多个接口,如何排查?难道说一个一个接口开展检测排查 ,可是時间又较为应急 ,很有可能又来不及了。比照之前自身处理是由于之前的新项目非常简单,相对而言精准定位较为非常容易,那麼此次怎么处理呢?

处理方式

一般Python新项目实际上是非常少出現内存难题的 ,一般全是自身编码写的不太好造成的,而针对此次出現的难题,自身的排查思路(针对web 接口种类的新项目):

  1. 先排查启用较为经常的接口
  2. 随后排查数据统计接口(查寻非常复杂)
  3. 假如所述都还没查出 ,再排查剩下的接口

在此次的难题排查中,自身大概也是依照这一思路开展的,在对启用经常的接口开展排查时 ,并沒有发觉内存的出现异常,而出現内存的难题则是在数据统计的有关接口上 。

实际上这类接口针对初中级开发设计可能是非常容易出难题的地区,最先这类接口查寻的数据信息相对性别的接口会非常复杂 ,假如编号基本又不是特别好,很有可能便会在这种接口上出現bug.

而在此次的排查中,最后明确是在一个归纳数据信息的接口上 ,精准定位到难题处于了Django ORM 错误操作造成的。自身根据一个简单代码案例来表明:

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来仿真模拟,出現题的编码就出在有关这一表的接口上:

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

以便让内存难题非常容易重现 ,我根据脚本制作向Student中插入了20000条数据信息,自然这儿数据信息越多,难题越显著

根据一个检测脚本制作高并发恳求这一接口 ,观查内存状况,你能发觉,内存会出現一瞬间增涨的状况 ,而且假如你的数据信息越多,恳求越多,你的内存很有可能会在一段时间持续上升 ,而且慢慢增涨。难题出在哪儿了?

其实不是很难,难题出在了编码中的if 分辨那边,大家根据filter 查寻回到的是QuerySet 种类的数据信息 ,而大家过虑以后的数据信息很有可能会存有十分多的情况下 ,这个时候大家根据if 断定,自身的了解这个地方会将全部QuerySet载入到内存中,进而出現内存占用过高的难题 ,而假如而且这个时候这一接口的响应时间也是十分会很慢,而这一QuerySet 中的数据信息越多,内存占用越显著 。

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() 就可以解决困难。

这是一个不大的知识要点 ,可是假如应用不对,很有可能便会导致十分比较严重的内存难题。

小结

  • 除开单元测试卷,还必须做大信息量检测 ,此次的难题假如在检测的情况下做了一定信息量的检测,很有可能很早已能及时处理难题
  • 针对基本的库的应用要更为了解
  • 排查难题的思路要确立,要不然很有可能会找不到方向

拓宽阅读文章

  • https://docs.djangoproject.com/en/3.0/ref/models/querysets/
  • https://www.cnblogs.com/zhaof/p/10031945.html
文章来源于网络 ,如有侵权请联系站长QQ61910465删除
本文版权归去快排wWw.seogUrublog.com 所有,如有转发请注明来出,竞价开户托管,seo优化请联系qq❉61910465