如何提高REST API的性能?

时间:2015-09-04 02:22:36

标签: python django rest server django-rest-framework

所以我决定今天使用Django REST Framework开发我的REST API。我发送的请求是一个GET请求,它基本上从数据库中检索最新的50个帖子并以JSON格式返回。

使用Apache Benchmark,统计数据为:

Server Software: nginx/1.4.6
Concurrency Level:      100
Time taken for tests:   18.394 seconds
Complete requests:      1000
Failed requests:        0
Non-2xx responses:      1000
Total transferred:      5628000 bytes
HTML transferred:       5447000 bytes
Requests per second:    54.36 [#/sec] (mean)
Time per request:       1839.442 [ms] (mean)
Time per request:       18.394 [ms] (mean, across all concurrent requests)
Transfer rate:          298.79 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       17 1137 1899.3     31   12366
Processing:    25  189 314.2     31    1418
Waiting:       24  184 309.4     29    1415
Total:         44 1326 1846.3    888   12407

Percentage of the requests served within a certain time (ms)
  50%    888
  66%   1178
  75%   1775
  80%   2286
  90%   3434
  95%   4576
  98%   7859
  99%   7922
  100%  12407 (longest request)

这显然非常缓慢......但我不确定如何改善这一点。

PS:我对开发服务器非常陌生,并希望从中吸取教训。在上面的GET请求中,我没有在服务器端进行任何类型的线程。它只是做的就是:

    user_id = str(request.QUERY_PARAMS.get("user_id", None))

    cur = connection.cursor()
    cur.execute("SELECT * FROM get_posts(%s)", [user_id]) # This is a Function in the SQL database

    return Response(convertToDict(cursor))

我想提高GET请求的速度,那么我可以做些什么才能让它更快?

2 个答案:

答案 0 :(得分:2)

好吧,看到一个原始的SQL查询(这是另一个节目)我有点惊讶,但你可以做各种各样的事情。

<强> TL; DR

前期

进行性能测试非常棒,定期对这些结果进行基准测试和记录是一种很好的做法,但基准测试可能很难做到:您必须考虑软件和硬件 - 测试结果将在很大程度上取决于这两件事的互动。尽力为这些东西复制你的生产环境并尝试不同的配置(你是{{​​3}},对吗?)以确定合适的。

旁注:我对AB并不是非常熟悉,但看起来你也会根据看似不是预期行为的输出返回HTML。

解决问题

要做的第一件事就是以深思熟虑的方式评估你所做的事情。

  1. 检查查询
  2. 使用诸如django-debug-toolbar之类的东西来查看是否存在一些查询瓶颈 - 许多链接在一起的查询,长时间运行的查询等。如果您需要更精细,您的数据库可能具有记录工具来记录长查询。

    假设您的数据非常规范化(在正常形式的意义上),这可能是引入非规范化的地方,因此您不必遍历尽可能多的关系。

    你也可以引入原始SQL(但你似乎已经这样做了。)

    1. 检查您的业务逻辑
    2. 您应该努力确保将业务逻辑放在请求和响应周期的正确部分。很多时候,为了让它正常工作,你把事情放在适当的地方,也许你最初的决定是找到它的限制。

      您似乎正在做一些非常简单的事情:获取表格中的最后50个条目。如果您正在计算是否包含帖子,您应该将其留给数据库 - 它应该在处理要检索的数据时处理所有逻辑。

      1. 检查支持代码
      2. 在您使用它时,请尝试进行更多性能测试,并查看代码的哪些区域落后。也许你可以做的事情可以改善你的代码(虽然是其他人可读和可理解的),并给你一个性能提升。列表推导,生成器,利用prefetch_和select_related,注意懒惰地评估查询 - 所有这些都值得实现,因为它们的功能已被充分记录和理解。也就是说,请务必仔细记录这些决定,以备将来的自己和其他人使用。

        由于它与Django REST框架有关,我对视图代码的实现并不熟悉,我可能会坚持使用它附带的JSON序列化程序。

        1. 解决方法
        2. 另一个有用的技巧是执行诸如实施12factor策略(但最有可能使用pagination)之类的事情,这样数据才会以小块形式传输到客户端。这将严重依赖于用例。

          这是一个很好的介绍:

          在问题上投掷软件

          您可以使用REST Framework将数据保存在服务器的RAM中,以便Django快速访问。

          通常,哪种缓存最有效将取决于数据本身。可能的情况是,使用搜索引擎来存储您经常查询的文档将是最有用的。但是,一个好的开始是cache。您可以阅读有关从各种来源实现缓存的所有信息,但是使用Django搜索的好地方是Redis

          在问题上投掷硬件

          速度也可以与硬件有关。您应该考虑软件的要求及其依赖性。做一些测试,搜索并尝试适合您的方法。在问题上投入更多硬件会导致边际收益严重下降。

答案 1 :(得分:1)

你可以发布你的get_posts(user_id)方法??。

提高绩效的步骤

  1. 对get_posts()方法进行改进。您需要确保对数据库的查询数量最少。尝试使用一个.filter获取结果,并使用select_related,prefetch相关以减少数据库调用。 https://docs.djangoproject.com/en/1.8/ref/models/querysets/#prefetch-related

  2. 如果需要,可以将.extra用于.filter,通过该属性可以向模型实例添加无法通过单个查询完成的其他属性https://docs.djangoproject.com/en/1.8/ref/models/querysets/#extra

  3. 对get_posts()进行这些更改,并查看您的GET请求如何响应。如果它仍然滞后,您可以选择缓存。

  4. 大部分时间消耗将用于数据库调用。如果优化get_posts(),您可能会对性能

    感到满意