Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve page load performance of large amount urls #5025

Merged

Conversation

vishalsabhaya
Copy link
Contributor

@vishalsabhaya vishalsabhaya commented Aug 17, 2024

@CommanderStorm @louislam

  1. fix loop to async
  2. query n+1 problem

Tick the checkbox if you understand [x]:

  • I have read and understand the pull request rules.

Description

Resolves #5129

testing results:
monitor url count: 415
current:
cpu: 1 memory 2 gb: 1 min 44 sec

after changes

database: aws rds marinadb db.t3.micro(memory: 1gb, cpu: 2vcpu)

with docker run on mac:
cpu: 0.5 memory 1 gb: 21 sec
cpu: 1 memory 2 gb: 11 sec
cpu: 1.5 memory 3 gb: 10 sec
cpu: 2 memory 4 gb: 10 sec

with ESC Farget(Linux/ARM64):
cpu: 0.5 memory 1 gb: 31 sec
cpu: 1 memory 2 gb: 6 sec
cpu: 2 memory 4 gb: 5 sec
Fixes #3494

Type of change

  • Performance improvement

Checklist

  • My code follows the style guidelines of this project
  • I ran ESLint and other linters for modified files
  • I have performed a self-review of my own code and tested it
  • I have commented my code, particularly in hard-to-understand areas (including JSDoc for methods)
  • My changes generates no new warnings
  • My code needed automated testing. I have added them (this is optional task)

Screenshots (if any)

1cpu-2gbram

1) fix loop to async
2) query n+1 problem
@vishalsabhaya
Copy link
Contributor Author

vishalsabhaya commented Aug 19, 2024

@CommanderStorm @louislam

I debug & fix performance issues for below
3) insert/update/delete/pause/resume monitor.

monitor url count: 415
database: aws rds marinadb db.t3.micro(memory: 1gb, cpu: 2vcpu)
current:
page load time + 500ms to 1 sec
it always fetches the latest data from the database & builds json. i felt that it was extra time.

after changes:
< 700ms

I just updated the target record with the front end instead of all records.

Copy link
Collaborator

@CommanderStorm CommanderStorm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late review, I am currently quite stressed work-wise..

While the ~16x(!) performance improvement in this PR is great, I don't quite like how you implemented some parts.
(most parts are fine)

preloadData is quite clunky
=> please move this into a single object per toJSON that we pass to the function instead of the current way of passing a lookup-object into the function.
The current way is quite likely error prown and without tests whatsoever way in this part extremely risky.

Only passing an object also has the advantage of allowing better type-checking via adding what is passed in to the doc-comment.

I have also left some comments below

);

// Organize preloaded data for efficient access
return {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the .reduce calls with object-changes here are really hard to parse for me and thus likely other devs.
If there were a bug in here, I would not be able to tell.

Please move this into regular for-loops.
While moving this, please also check if Map is not more appropriate.
I found this blog post with some claims that this might increase performance (if that code happends to be a factor we are spending a part of the remaining 700ms..)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CommanderStorm
understand let me double check with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CommanderStorm
I simplified logic. can you review one more time.

let list = await this.getMonitorJSONList(socket.userID);
this.io.to(socket.userID).emit("monitorList", list);
return list;
async sendMonitorList(socket, op = OPERATIONS.LIST, monitorID = null) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems pretty strange
the whole part why you added op here and above seems to be to create a fast-path for OPERATIONS.DELETE, right?

Instead of doing this, please just remove the calls for OPERATIONS.DELETE if we really don't use the list there..
Cleans up the code a lot..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CommanderStorm
its used as common method. based on this parameter we will identified operation & update same to frontend list. you can refer socket.js changes

while page load it will use OPERATIONS.LIST as default.
while insert or update. we will add only 1 URL object to list.
while delete no need to send list because we have to delete from fronted list. from backend already deleted.

server/uptime-kuma-server.js Outdated Show resolved Hide resolved
server/model/monitor.js Outdated Show resolved Hide resolved
server/server.js Outdated Show resolved Hide resolved
src/mixins/socket.js Outdated Show resolved Hide resolved
src/mixins/socket.js Outdated Show resolved Hide resolved
@CommanderStorm CommanderStorm added area:api concearning the api or automation pr:please address review comments this PR needs a bit more work to be mergable labels Aug 21, 2024
@vishalsabhaya
Copy link
Contributor Author

@CommanderStorm

Thank you for your effert to review my pr. i am really appreciate your hard work for community.
I can't understand below comment can you elaborate?

While the ~16x(!) performance improvement in this PR is great, I don't quite like how you implemented some parts.
(most parts are fine)

preloadData is quite clunky
=> please move this into a single object per toJSON that we pass to the function instead of the current way of passing a lookup-object into the function.
The current way is quite likely error prown and without tests whatsoever way in this part extremely risky.

Only passing an object also has the advantage of allowing better type-checking via adding what is passed in to the doc-comment.

@vishalsabhaya
Copy link
Contributor Author

@CommanderStorm @louislam

I found 1 more thing. it will improve more seconds.

marked realtime dot is maximum 43. why we are fetching 100 records for each monitor? is there any reason?
currently I am testing with 834 monitor
limit 100 takes: 13 sec
limit 43 takes: 7 sec

image

image

@CommanderStorm
Copy link
Collaborator

is there any reason?

I can imagine two:

  • What happens if you zoom out?
  • What happens on high-dpi devices?

image

If we change that part, lets please do this in a second PR ^^

@vishalsabhaya
Copy link
Contributor Author

is there any reason?

I can imagine two:

  • What happens if you zoom out?
  • What happens on high-dpi devices?

image

If we change that part, lets please do this in a second PR ^^

yes, you are correct. i didn't think about it. we will do in next pr. but we should restrict max span. because for detail information already provided graph.

@vishalsabhaya
Copy link
Contributor Author

@CommanderStorm
i seen something strange. did you notice ever?

i did testing with 800 records.

when I remove below line. all monitoring is working fine but current case most of monitor is stopped. monitoring data is not updating so monitor is not starting.
await sleep(getRandomInt(300, 1000));
image

startMonitors does not have await that's why?
image

@CommanderStorm
Copy link
Collaborator

Sorry, above comment does not quite parse for me.

As far as I understand that line, this just means that the monitors are started one after another with random intervals in between.

The way this is executed, starting monitors should happen after the server started listening, but must not have completely/partially completed before starting the versionCheck.
That this is not done in a Promise.all makes a thundering heard problem less likely. The speed of starting them is constant though.

As far as I understand async js (feel free to correct), that sounds partially reasonable.
Changing the monitor startup to be smarter can be done, but let's separate this Into its own PR. ^^

@vishalsabhaya vishalsabhaya mentioned this pull request Sep 18, 2024
7 tasks
revert to original insted of map
@vishalsabhaya
Copy link
Contributor Author

@CommanderStorm
now all changes are done. can you review & guide me further? we should merge after review?

@vishalsabhaya
Copy link
Contributor Author

@CommanderStorm
is there any new changes?
sorry to ping you again. i know you are very busy

@CommanderStorm
Copy link
Collaborator

CommanderStorm commented Sep 30, 2024

Sorry, got back from vacation on monday and am still picking up the pieces work wise and had not time for such a large PR.
I can answer issues or merge small PRs on the train but for this one, I need an hour of free time to look if everything works as intended.

@vishalsabhaya
Copy link
Contributor Author

@CommanderStorm
ahhh, understood. take your time.

@CommanderStorm CommanderStorm mentioned this pull request Oct 4, 2024
2 tasks
@CommanderStorm CommanderStorm added pr:needs review this PR needs a review by maintainers or other community members and removed pr:please address review comments this PR needs a bit more work to be mergable labels Oct 4, 2024
Copy link
Collaborator

@CommanderStorm CommanderStorm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have left a few nits to apply, but mostly LGTM 🎉

Note

This PR is part of the v2.0 merge window => see #4500 for the bugs that need to be addressed before we can ship this release ^^

All changes in this PR are small and uncontroversial ⇒ merging with junior maintainer approval

server/model/monitor.js Outdated Show resolved Hide resolved
server/model/monitor.js Outdated Show resolved Hide resolved
server/model/monitor.js Outdated Show resolved Hide resolved
server/model/monitor.js Outdated Show resolved Hide resolved
server/model/monitor.js Outdated Show resolved Hide resolved
src/mixins/socket.js Outdated Show resolved Hide resolved
server/uptime-kuma-server.js Outdated Show resolved Hide resolved
server/uptime-kuma-server.js Outdated Show resolved Hide resolved
@CommanderStorm CommanderStorm added this to the 2.0.0 milestone Oct 6, 2024
@CommanderStorm CommanderStorm merged commit d0067a0 into louislam:master Oct 6, 2024
18 checks passed
for (let monitorID in monitorList) {
await sendHeartbeatList(socket, monitorID);
monitorPromises.push(sendHeartbeatList(socket, monitorID));
monitorPromises.push(Monitor.sendStats(io, monitorID, user.id));
Copy link
Owner

@louislam louislam Oct 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vishalsabhaya Just checking this pr. Is this code correct? Because the function returns nothing.

@louislam louislam added the question Further information is requested label Oct 12, 2024
@louislam louislam mentioned this pull request Oct 29, 2024
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:api concearning the api or automation pr:needs review this PR needs a review by maintainers or other community members question Further information is requested
Projects
None yet
Development

Successfully merging this pull request may close these issues.

URLs not showing in uptime dashboard On Page reload monitors do not load
4 participants