Tastypie APIパフォーマンスレスリング

TastypieパッケージをPony ORMにドラッグした方法とその由来。



この記事では、pythonとdjangoでのアプリケーションのパフォーマンスに対する私の苦労の物語を続けます。







前のシリーズの要約:

-ORMは遅くなり、非常に-3〜5倍以上

- そして、これはDjango ORMのダミーです

- うわー、このORMはほとんどスローダウンせず、可能なすべてをキャッシュします。

- これは、高性能Pony ORMをDjangoプロジェクトに固定し、主要な場所で使用する方法です。



はじめに





Pjan ORMを使用してDBMSにアクセスする速度について(Django ORMと比較して)非常に満足のいく結果が得られたので、実際にそれらを使用する方法について考え始めました。 まず、DjangoデータモデルをPonyデータモデルマッピングしました 。 これで、既成のデータモデルをプロジェクトで使用できます。



コードをゼロから作成する場合、Djangoの代わりにPonyモデルを使用するのは簡単ではありませんが、非常に簡単です。すべてのDjangoモデルの `p`属性がPonyモデルを指すようになりました。 ただし、すでにDjango ORMを使用している既製のパッケージをどうすればよいでしょうか?



残念なことに、Pony ORMのモデルとコレクションにアクセスする構文とセマンティクスはDjango ORMとは根本的に異なるため、書き換えまたは書き換えを行うのは1つの答えしかありません。 さらに、このような変装が行われると、中間層での損失のためにPony ORMを使用するすべての利点が失われることを強く疑います。 それでも、pythonはインタープリターであり、たとえば、関数呼び出しでの損失は、DBMSへのアクセスのバックグラウンドに対しても目立つほど大きいです。 Django ORMとSQLAlchemyのパフォーマンスをおそらく損なうのは、そのような損失です。



HTTP APIを介してサーバーをデータプロバイダーとして使用し、アプリケーションのインターフェイス全体(またはそのほとんど)をクライアント側に転送する予定です。 したがって、重要な要素はTastypieパッケージを使用して実装するAPIであるため、そのパフォーマンスを向上させると、アプリケーションインターフェースの生産性に直接影響し、サイトの全体的な負荷が減少します。



そしてTastypie引き受けました



Tastypie構造が私を助けた方法





Tastypieライブラリは、Djangoに依存していますが、Django ORMから独立したデータソース抽象化(リソース)のレイヤーを持っています。 次の子孫であるModelResourceのみがDjango ORM固有のデータアクセスを使用します。 したがって、最初に想定したように、Resourceから継承し、ModelResourceに似た機能を実装するだけで済みました。



実際には、クラスをToManyFieldと並列にする必要もありました。残念なことに、後者はDjango ORM専用の数行であることが判明したためです。 クラスSetFieldを呼び出したのは、1対多の関係を示すためにPony ORMで使用されるSetクラスだからです。



どうした





すべてがうまくいきました。 サンプルとして、django.contrib.authのデータモデルを使用し、約1000人のユーザーでそれを埋めました。 システム内のさまざまな種類のデータに対する159の権利をユーザーの1人に割り当て(多くのデータを蓄積しています-データ型)、この呼び出しをサンプルとして使用して、APIを通じて彼の権利とともにこのユーザーを要求しました。



Django ORMを使用した古いv2 APIのデータソース定義は次のとおりです(パフォーマンスを正しく測定するために、認証と承認が除外されていることに注意してください)。



class PermissionResource(ModelResource): class Meta: queryset = auth_models.Permission.objects.all() object_model = queryset.model filtering = dict([(n,ALL_WITH_RELATIONS) for n in object_model._meta.get_all_field_names()]) resource_name = 'auth/permission' class UserResource(ModelResource): user_permissions = ToManyField(PermissionResource,'user_permissions',related_name='user_set',null=True) class Meta: queryset = auth_models.User.objects.all() object_model = queryset.model filtering = dict([(n,ALL_WITH_RELATIONS) for n in object_model._meta.get_all_field_names()]) resource_name = 'auth/user'
      
      







さて、ここに新しいv3 APIの定義があり、Donyパッケージと組み合わせてPony ORMを使用するようになっています。



 class PermissionResource(DjonyResource): class Meta: object_model = auth_models.Permission filtering = dict([(n,ALL_WITH_RELATIONS) for n in object_model._meta.get_all_field_names()]) resource_name = 'auth/permission' class UserResource(DjonyResource): user_permissions = SetField(PermissionResource,'user_permissions',related_name='user_set',null=True) class Meta: object_model = auth_models.User filtering = dict([(n,ALL_WITH_RELATIONS) for n in object_model._meta.get_all_field_names()]) resource_name = 'auth/user'
      
      







メタデータ定義では、PonyモデルではなくDjangoモデルが使用されることに注意してください。 これは、PonyモデルにはDjango ORMに固有の多くの属性が含まれていないが、たとえばhelp_textなどのデータ構造自体を定義する必要がないためです。 このようなメタデータの投稿の問題は実際に重要ですが、その議論はこの記事の範囲を超えている可能性があります。



サーバーは、2.2 GHzの2つのコアと3 GBのRAMを備えた、控えめな職場のコンピューターに展開されました。 テストクライアントは同じコンピューターから起動されました。 最後の手段として、abパッケージ(Apache Benchmark)が開始されました。



 seva@SEVA (2):~/djony$ ab -n 100 -c 4 "http://localhost:8080/api/v2/auth/user/3/?format=json" This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient).....done Server Software: nginx/1.1.19 Server Hostname: localhost Server Port: 8080 Document Path: /api/v2/auth/user/3/?format=json Document Length: 5467 bytes Concurrency Level: 4 Time taken for tests: 17.331 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 582900 bytes HTML transferred: 546700 bytes Requests per second: 5.77 [#/sec] (mean) Time per request: 693.256 [ms] (mean) Time per request: 173.314 [ms] (mean, across all concurrent requests) Transfer rate: 32.84 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 1.5 0 9 Processing: 313 685 486.1 575 3357 Waiting: 312 684 485.8 574 3355 Total: 313 685 486.7 575 3357 Percentage of the requests served within a certain time (ms) 50% 575 66% 618 75% 647 80% 670 90% 819 95% 1320 98% 2797 99% 3357 100% 3357 (longest request) seva@SEVA (2):~/djony$ ab -n 100 -c 4 "http://localhost:8080/api/v3/auth/user/3/?format=json" This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient).....done Server Software: nginx/1.1.19 Server Hostname: localhost Server Port: 8080 Document Path: /api/v3/auth/user/3/?format=json Document Length: 5467 bytes Concurrency Level: 4 Time taken for tests: 8.339 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 582900 bytes HTML transferred: 546700 bytes Requests per second: 11.99 [#/sec] (mean) Time per request: 333.557 [ms] (mean) Time per request: 83.389 [ms] (mean, across all concurrent requests) Transfer rate: 68.26 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.0 0 0 Processing: 137 317 375.9 243 2753 Waiting: 137 316 375.7 243 2751 Total: 137 317 375.9 243 2753 Percentage of the requests served within a certain time (ms) 50% 243 66% 264 75% 282 80% 299 90% 351 95% 433 98% 2670 99% 2753 100% 2753 (longest request)
      
      







ご覧のとおり、ここでPony ORMを使用すると、APIのパフォーマンスが2倍になりました。



2番目の例では、テーブルからすべてのオブジェクトを照会します。 ここで、パフォーマンスの向上はさらに重要です。



 seva@SEVA (2):~/djony$ ab -n 20 -c 4 "http://localhost:8080/api/v2/auth/user/?format=json&limit=0" This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient).....done Server Software: nginx/1.1.19 Server Hostname: localhost Server Port: 8080 Document Path: /api/v2/auth/user/?format=json&limit=0 Document Length: 306326 bytes Concurrency Level: 4 Time taken for tests: 40.891 seconds Complete requests: 20 Failed requests: 0 Write errors: 0 Total transferred: 6133760 bytes HTML transferred: 6126520 bytes Requests per second: 0.49 [#/sec] (mean) Time per request: 8178.157 [ms] (mean) Time per request: 2044.539 [ms] (mean, across all concurrent requests) Transfer rate: 146.49 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 0 Processing: 6235 7976 1035.4 7980 10671 Waiting: 6225 7959 1033.0 7958 10654 Total: 6235 7976 1035.4 7980 10671 Percentage of the requests served within a certain time (ms) 50% 7980 66% 8177 75% 8287 80% 8390 90% 10001 95% 10671 98% 10671 99% 10671 100% 10671 (longest request) seva@SEVA (2):~/djony$ ab -n 20 -c 4 "http://localhost:8080/api/v3/auth/user/?format=json&limit=0" This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient).....done Server Software: nginx/1.1.19 Server Hostname: localhost Server Port: 8080 Document Path: /api/v3/auth/user/?format=json&limit=0 Document Length: 306326 bytes Concurrency Level: 4 Time taken for tests: 11.841 seconds Complete requests: 20 Failed requests: 0 Write errors: 0 Total transferred: 6133760 bytes HTML transferred: 6126520 bytes Requests per second: 1.69 [#/sec] (mean) Time per request: 2368.136 [ms] (mean) Time per request: 592.034 [ms] (mean, across all concurrent requests) Transfer rate: 505.88 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 0 Processing: 1024 2269 806.2 2227 4492 Waiting: 1017 2252 803.6 2211 4472 Total: 1024 2269 806.2 2227 4492 Percentage of the requests served within a certain time (ms) 50% 2227 66% 2336 75% 2395 80% 2406 90% 4140 95% 4492 98% 4492 99% 4492 100% 4492 (longest request)
      
      







APIのパフォーマンスが4倍以上向上しました!



残っているもの





ただし、承認と認証は実装されていませんが、実装に特定の問題は見られません。



Pony ORMにはまだ類似の基準がないため、regex、week_day、検索などの基準に基づいたフィルターの実装に問題があります。



おわりに





Django既製のアプリケーションパッケージでDjango ORMの代替としてPony ORMを実装することは、生産性を高めるという点で非常に可能であり、非常に便利です。 パッケージ内のクラスを適切に抽象化すると、特にDjango ORMに依存しないレイヤーの存在が非常に役立ちます。



Djangoアプリケーションのパフォーマンスを向上させることに関心のあるすべての人に、オープンプロジェクトdjony(PonyとDjangoの交配)tastypie_djony(Pony ORMを使用したTastypieの高速化)に参加して、可能な限り迅速に持続可能な工業デザインを提供してもらいます。



Pony ORMプロジェクトはオープンソースプロジェクトです。



従来、Pony ORMの開発者はまだHabrahabrの読み取り専用ユーザーであることを思い出します。



AlexeyMalashkevich m.alexey@gmail.com



メタプログラマーalexander.kozlovsky@gmail.com



All Articles