Two weeks ago, after submitting a few PR’s to Flame on Appearance Level Online, I packaged it into a container for bookmarking and online app management.

However, while migrating my personal bookmarks, I found that Flame didn’t perform particularly well in terms of performance, so I made a modified version: Flare.

Writing in the front

Before I talk about flare, I want to talk about flame.

Flame is a look level online navigation page project where you can store your favorite bookmarks and online apps. It was created by a Polish guy and the project address is github.com/pawelmalak/…

After trying it out, I found the project to be ok, so I tweaked it and packaged a new image: github.com/soulteary/d…

In the project documentation, I recorded my changes:

  • Simplify program functions and dependencies (such as K8S), reduce the volume of software packages, reconstruct some detailed logic, and simplify the application startup process.
  • Rewrite the weather capture logic to get weather data using city names instead of latitude and longitude.
  • Some small bugs have been fixed to the program, support Chinese search.
  • The program has carried on the simple Chinese.

However, as I went deeper, I found that pages had significant performance issues.

Due to the SPA solution adopted by the Polish team, the project included more than 6700 SVG ICONS and several web fonts, and there were some minor issues with the interface, resulting in a very large page size and a large number of interface requests.

Even when you upload some SVG with a lot of elements as your bookmark icon, React triggered page rendering will cause the browser to freeze.

I had a few hundred bookmarks to work with, and I expected that number to grow in the future, so I used the program to batch create close to a thousand bookmarks. Then I noticed that rendering so many bookmarks made the page stall, and even searching the page for bookmarks with keywords made it obvious to drop frames.

So, I decided to rewrite a lighter program to address my needs. The new project address is here, if you’re curious, you can try it out: github.com/soulteary/d…

The process of making flare is also the process of tuning flame’s performance. But before we can solve the problem, we first have to be able to identify what the problem is.

Application performance problem analysis

In terms of performance optimization for this application, it is not complicated and not much different from traditional application optimization: reduce computation first, and solve the problem in a more computationally efficient way when it cannot be reduced.

However, in combination with usage scenarios, it is useful to start with functionality before analyzing technical issues.

Functions that don’t work for me

First of all, in terms of functions, I don’t need this application to integrate with Docker to provide “service discovery” functions. For example, when I start a container, the application automatically bookmarks the newly launched container or adds it as an application.

Secondly, after having my own SSO service, I no longer need to use simple login functions such as account and password, so this function can also be removed.

Finally, with regard to the storage of bookmark data, I feel that in the absence of a great user experience Web editor, the configuration declaration approach is probably not as easy to manage and maintain. (You can use any editor you like to update and maintain content, you can use Git or whatever you like to save your own data in white boxes.)

Based on the changes above, I could probably write less code in a few areas: container (Docker & K8S) integration, login authentication, applications and bookmarks, and “CRUD” for bookmark classification.

Problems in the front-end architecture

For the Flame project, the author used the create-React-app scaffolding to create the project. The project dependencies are: React v17 + TypeScript + Redux, in order to provide concise and consistent icon, the authors are introduced in the front-end Templarian/MaterialDesign – JS, a DOM structure be carefully handled very simple SVG icon library.

After being packaged with the build tool and GZip compressed on the server, close to 1MB of resources need to be transferred and the raw script is close to 3MB in size. The relatively large program size results in long page loading and execution times. For example, the first rendering time of a page fluctuates around 1s, more than 1s in most cases, and the completion time is usually more than 1.5 seconds. Maybe the author is not familiar with server-side program development. Although the interface will be reused when the application configuration is updated in the front end, as many as 8 interfaces will be called when the content page is displayed. In addition, in order to display and update the weather information on the page, The Polish boy also uses WebSocket for data interaction.

Other problems, which have been mentioned earlier in this article, will not be repeated.

Problems in the back-end architecture

The technology stack used in the project is Node.js, the Web framework is the latest version of Express with a very high market share, the ORM framework is Sequelize, and the data store is SQLite3. At first glance, the above choices don’t seem problematic, and if the application doesn’t need to publicly provide browsing access, there shouldn’t be any performance issues.

However, if we look closely at the service responses, we see that some requests take very long to respond to, such as page resources, such as JS program resources that are critical to the page, which take close to 400ms to fetch.

In addition, the front end makes multiple requests to get the data, and using SQLite in conjunction with the data store can easily lead to performance bottlenecks if public content access is provided.

Make improvements for applications

When we clearly understand the above problems, such as easy to take the plan is: based on the original program to restructure and adjust, simplify the front-end request, reasonably split the module, deal with resource loading and execution timing, adjust the data storage and processing mode, improve the response ability of the server and other combination of boxing. But would this be the simplest and most profitable solution?

Adjust the front-end implementation

If it is cost-effective to use MVVM frameworks in interactive page applications, it is not cost-effective to use such frameworks in scenarios where there is no multi-component code reuse and no server-side rendering requirements.

If you don’t use frameworks like React, Vue, Angular, etc., why do you want to go back to jQuery in 2022? It can, but in a near-pure presentation scenario, we can do business functions and simple interactions without JS, such as automatically fetching focus, menu button activation changes, and even weather ICONS with animated effects.

So, when it comes to tweaking implementations, there’s really an option: no scripts at all.

After completing the program, we can see that the complete time to get the entire page data from the server, structure parsing, style calculation, element layout, and page drawing is in 33ms (including idle wait time), where the time consumption of the key process adds up to less than 10ms, and the time to complete the page rendering is reduced to 1.65ms.

With the ability to render pages quickly, we were able to do “no refresh” browsing of page transitions (because rendering was fast enough) without using the browser to cache resources and speed up rendering.

Adjust the back-end implementation

While I’m a big fan of Node.js, and have shared a lot of node.js programming and optimization practices in the past, it’s necessary to switch the technology stack in order to achieve high performance resource response at a low cost: Golang, for example.

With Golang’s simplified application, the application’s response to each request remained within milliseconds (limited by network traffic), down by two or three orders of magnitude. The page’s critical DOM ContentLoad time is reduced to an eighth of that.

Combined with the rendering time mentioned in the front-end optimization above, the total amount from resource download to rendering is less than 10ms. If it is not for some limitations of the browser, the frame rate of drawing should be far more than 60 frames, further satisfying our implementation of “even if refreshed, it is smoother than some implementation that has not been refreshed”.

In the above implementation, I split the page icon request and the page document, which may not be optimal in a scenario with a small number of bookmarks and icon types, but once the bookmarks are in the hundreds or thousands, you will find that icon splitting can greatly improve performance.

Of course, to accommodate a smaller number of scenarios, I also implemented the merged output, with only two requests, including the Site Favicon fetch. Rendering performance is even better than document and resource split output when there are not many bookmarks.

Icon Resource optimization

Flame uses a solution that reads the back-end interface configuration and dynamically creates SVG ICONS from a front-end script and inserts them into a document, whereas Flare’s default approach is to split SVG and the document to address page performance issues with a large number of bookmarks.

Although the page performance problem is solved, the server SIDE IO problem will be accompanied, so here also need to deal with the resource on the server side release and read the problem, as far as possible to reduce the disk IO of the resource to zero.

It sounds silly, but it’s actually pretty easy to do with code generation. Of course, because Go has automatic GC, so when different resources are used, there will be a large amount of memory allocation, affecting efficiency. Here you can consider using persistent solution to solve the problem, it is interesting to deal with, due to the space and subject. There is a section I covered in the last two articles about the use and optimization of Golang embedded resources.

For example, without any optimization for THE HTTP service implementation and under the premise of limiting the running resources to two cores, only optimizing the resource IO can achieve stable 3ms output resources and provide more than 27,000 response services per second.

Optimization of container images

In addition to normal optimization, mirror optimization is also critical for container era applications. Container optimization, which I mentioned many times in the previous article, will not be expanded. If you are interested, you can browse through the previous content.

# docker images | grep fla                 Soulteary/Flare 0.1.1 22b18AD73C66 12MB Soulteary/Flaume 2.b39FFFC0CA81 152MB Pawelmalak/Flame 2.2.0 FA47C93C0AF6 179MB Pawelmalak/Flame 2.0.0 729b0FCEa7F0 190MBCopy the code

As you can see, the optimized program is about 15 to 16 times the size of the original program when decompressed locally.

Additional optimizations

If we were to test the Flame front end implementation with Lighthouse, we could see a few minor implementation issues with the front end. Although three of the four rings were green, only one was green.

In the process of re-implementation, in addition to simplifying the structure, debugging implementation, but also smoothly hit the four circles of full marks (Chrome version V97 +).

The last

Having said that, I’m sure you’ve seen how I do it. If you’re interested in Flare and also need a simple navigation app, visit the project github.com/soulteary/d… Come and see for yourself.

–EOF


We have a little group of hundreds of people who like to do things.

In the case of no advertisement, we will talk about software and hardware, HomeLab and programming problems together, and also share some information of technical salon irregularly in the group.

Like to toss small partners welcome to scan code to add friends. (To add friends, please note your real name, source and purpose, otherwise it will not be approved)

All this stuff about getting into groups


If you think the content is still practical, welcome to share it with your friends. Thank you.

If you want to see the next content faster, please feel free to “like” or “share”, these free encouragement will affect the speed of subsequent content updates.


This article is published under a SIGNATURE 4.0 International (CC BY 4.0) license. Signature 4.0 International (CC BY 4.0)

Author: Su Yang

Creation time: January 19, 2022 statistical word count: 5054 words reading time: 11 minutes to read this article links: soulteary.com/2022/01/19/…