Skip to content

Fix slow group loading on forking page

What does this MR do?

After introducing separate group loading on forking page, there was a really high page load times observed for large sets of data.

On local environment for ~1000 groups here are apache bench results:

ab -n 10 -C '_gitlab_session_7b75811b6f331df2ddd5b02eab038350b74456e89a857d26320864e9914e2b3b=c84888787b60da75e535871996c77555' 'http://127.0.0.1:3000/root/apitest/-/forks/new.json'


This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /root/apitest/-/forks/new.json
Document Length:        441241 bytes

Concurrency Level:      1
Time taken for tests:   158.401 seconds
Complete requests:      10
Failed requests:        0
Total transferred:      4421359 bytes
HTML transferred:       4412410 bytes
Requests per second:    0.06 [#/sec] (mean)
Time per request:       15840.073 [ms] (mean)
Time per request:       15840.073 [ms] (mean, across all concurrent requests)
Transfer rate:          27.26 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.1      1       1
Processing: 14391 15840 1513.7  15453   19164
Waiting:    14389 15837 1513.6  15450   19160
Total:      14392 15840 1513.8  15454   19165

Percentage of the requests served within a certain time (ms)
  50%  15454
  66%  15584
  75%  15598
  80%  17959
  90%  19165
  95%  19165
  98%  19165
  99%  19165
 100%  19165 (longest request)

What I did:

  1. I created easy-accesible hash with memberships that is used in serializer instead of querying database for each group.
  2. I added preloading of routes
  3. I added preloading for deletion_schedule

Apache bench results after changes:

ab -n 4 -C '_gitlab_session_7b75811b6f331df2ddd5b02eab038350b74456e89a857d26320864e9914e2b3b=c84888787b60da75e535871996c77555' 'http://127.0.0.1:3000/root/apitest/-/forks/new.json'
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /root/apitest/-/forks/new.json
Document Length:        441241 bytes

Concurrency Level:      1
Time taken for tests:   14.226 seconds
Complete requests:      4
Failed requests:        0
Total transferred:      1768540 bytes
HTML transferred:       1764964 bytes
Requests per second:    0.28 [#/sec] (mean)
Time per request:       3556.573 [ms] (mean)
Time per request:       3556.573 [ms] (mean, across all concurrent requests)
Transfer rate:          121.40 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.0      1       1
Processing:  3010 3556 904.9   3155    4910
Waiting:     3006 3553 904.9   3152    4906
Total:       3010 3557 904.9   3156    4910

Percentage of the requests served within a certain time (ms)
  50%   3156
  66%   3156
  75%   4910
  80%   4910
  90%   4910
  95%   4910
  98%   4910
  99%   4910
 100%   4910 (longest request)

I know for seconds is not super fast, but it's for huge set of data and it's on local machine.

Screenshots

Before changes, what I observed in logs: this part was repeated for every group:

 [1m[36mRoute Load (0.1ms)[0m  [1m[34mSELECT "routes".* FROM "routes" WHERE "routes"."source_id" = $1 AND "routes"."source_type" = $2 LIMIT $3[0m  [["source_id", 1011], ["source_type", "Namespace"], ["LIMIT", 1]]
  ↳ app/models/concerns/routable.rb:70:in `full_name'
  [1m[36mMember Load (0.2ms)[0m  [1m[34mSELECT "members".* FROM "members" WHERE "members"."user_id" = $1 AND "members"."source_type" = $2 AND "members"."source_id" = $3 LIMIT $4[0m  [["user_id", 2], ["source_type", "Namespace"], ["source_id", 1011], ["LIMIT", 1]]
  ↳ app/serializers/fork_namespace_entity.rb:43:in `membership'
  [1m[36mGroupDeletionSchedule Load (0.3ms)[0m  [1m[34mSELECT "group_deletion_schedules".* FROM "group_deletion_schedules" WHERE "group_deletion_schedules"."group_id" = $1 LIMIT $2[0m  [["group_id", 1011], ["LIMIT", 1]]
  ↳ ee/app/models/ee/group.rb:48:in `marked_for_deletion_on'

now:

 SELECT "group_deletion_schedules".* FROM "group_deletion_schedules" WHERE "group_deletion_schedules"."group_id" IN ...

and

 SELECT "routes".* FROM "routes" WHERE "routes"."source_type" = $1 AND "routes"."source_id" IN ...

and

  SELECT "members".* FROM "members" WHERE "members"."user_id" = ...

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

Security

If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:

  • Label as security and @ mention @gitlab-com/gl-security/appsec
  • The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • Security reports checked/validated by a reviewer from the AppSec team

Closes #235912 (closed)

Edited by Gosia Ksionek

Merge request reports