当前位置:网站首页>Teach you three ways to optimize the performance from 20s to 500ms
Teach you three ways to optimize the performance from 20s to 500ms
2022-07-25 04:59:00 【nginx】

Preface Interface performance problems , For students engaged in back-end development , It's a topic that can't be bypassed . Want to optimize the performance of an interface , We need to start from many aspects .
Actually , I also wrote an article about interface performance optimization before 《 Talk about interface performance optimization 11 A little trick 》, After being published, it was widely praised on the whole network , Interested guys can take a closer look .
This article will continue with the topic of interface performance optimization , From the perspective of actual combat , Talk about how I optimize a slow query interface .
Last week, I optimized the batch scoring query interface on the offline , Change the interface performance from the original 20s, Optimized to the current 500ms within .
On the whole , It's done with three moves .
What happened ?
1. crime scene Before we go to work every morning , Will receive an online slow query interface summary email , The email will show the interface address 、 Call the number 、 Most time consuming 、 Average time and traceId Etc .
I see a batch scoring query interface , The maximum time consumption has reached 20s, The average time is also 2s.
use skywalking View the calling information of this interface , It is found that in most cases , The response of this interface is relatively fast , Most of the time 500s You can return around , But there are also a few more than 20s Request .
This phenomenon is very strange .
Is it related to data ?
such as : To check the data of an organization , It's very fast . But if you want to check the platform , That is, the root node of the organization , In this case , The amount of data to be queried is very large , Interface response may be very slow .
But it turns out that this is not the reason .
Soon a colleague gave the answer .
They are on the statement list page , This interface is requested in batch , But the amount of data he transmitted was very large .
What's going on ?
The original requirement is that this interface calls the paged list page , The size of each page is :10、20、30、50、100, The user can choose .
let me put it another way , Call the batch evaluation query interface , You can query at most at one time 100 Bar record .
But the reality is : The statement list page also contains many orders . Basically every statement , There are multiple orders . When calling the batch evaluation query interface , It is necessary to merge the data of settlement documents and orders .
The result of this is : When calling the batch evaluation query interface , There are many parameters passed in at one time , Enter the reference list It contains hundreds 、 Even thousands of data are possible .
2. present situation If hundreds or thousands of them are transmitted at one time id, Batch query data is ok , You can go to the primary key index , Query efficiency is not too bad .
But the batch scoring query interface , Logic is not simple .
The pseudocode is as follows :
In fact, in the real scene , The code is much more complicated than this , Here is to show you , Simplified .
public Listquery(Listlist) {// resultListresult = Lists.newArrayList();// Get organization idListorgIds = list.stream().map(SearchEntity::getOrgId).collect(Collectors.toList());// adopt regin Call the remote interface to get the organization informationListorgList = feginClient.getOrgByIds(orgIds);for(SearchEntity entity : list) {// Through organization id Find organization codeString orgCode = findOrgCode(orgList, entity.getOrgId());// Query and evaluate by combining conditionsScoreSearchEntity scoreSearchEntity = new ScoreSearchEntity();scoreSearchEntity.setOrgCode(orgCode);scoreSearchEntity.setCategoryId(entity.getCategoryId());scoreSearchEntity.setBusinessId(entity.getBusinessId());scoreSearchEntity.setBusinessType(entity.getBusinessType());ListresultList = scoreMapper.queryScore(scoreSearchEntity);if(CollectionUtils.isNotEmpty(resultList)) {ScoreEntity scoreEntity = resultList.get(0);result.add(scoreEntity);}}return result;}
There are two key points :
- Another interface is called remotely in the interface
- Need to be in for Query the data in the loop, and the number of 1 spot , namely : Another interface is called remotely in the interface , This code is required .
Because if there is a redundant organization in the evaluation table code Field , In case the organization in the organization table code Modified , Have to go through some mechanism , Inform us of the organization that synchronously modifies the evaluation form code, Otherwise, there will be data inconsistency .
Obviously , If you want to adjust like this , The business process needs to be changed , The code change is a little big .
therefore , Let's keep calling remotely in the interface first .
So it looks like , The places that can be optimized can only be :for Query data in the loop .
3. First optimization Because of the need in for In circulation , Each record should be based on different conditions , Find the desired data .
When the business system calls this interface , No transmission id, The bad thing is where In terms of id in (...), Batch query data in this way .
Actually , There is a way to avoid circular query , One sql Can solve the demand : Use or Keyword splicing , for example :(org_code='001' and category_id=123 and business_id=111 and business_type=1) or (org_code='002' and category_id=123 and business_id=112 and business_type=2) or (org_code='003' and category_id=124 and business_id=117 and business_type=1)...
This way will lead to sql The statement will be very long , The performance will be very poor .
In fact, there is another way to write :
But this sql, If the amount of data queried at one time is too much , The performance is not very good either .
where (a,b) in ((1,2),(1,3)...)
It's impossible to change to batch query , You can only optimize a single query sql Implementation efficiency .
Start with the index , Because the transformation cost is the lowest .
The first optimization is to optimize the index .
Create a before the evaluation form business_id General index of the field , But at present, the efficiency is not ideal .
Because I decisively added the joint index :
The joint index is made up of :org_code、category_id、business_id and business_type Four fields make up .
alter table user_score add index `un_org_category_business` (`org_code`,`category_id`,`business_id`,`business_type`) USING BTREE;
After this optimization , The effect was immediate .
The bulk evaluation query interface takes the most time , From the initial 20s, It's shortened to 5s about .
4. Second optimization Because of the need in for In circulation , Each record should be based on different conditions , Find the desired data .
Query data in only one thread , Obviously too slow .
that , Why can't we change it to multi-threaded call ?
Second optimization , The query database is changed from single thread to multi thread .
But because the interface is to query all the data , All go back , So get the query results .
Using multithreaded calls , And get the return value , This scenario uses java8 Medium CompleteFuture Very suitable .
The code is adjusted to :
CompleteFuture The essence of is to create threads to execute , To avoid too many threads , So it is very necessary to use thread pool .
CompletableFuture[] futureArray = dataList.stream().map(data -> CompletableFuture.supplyAsync(() -> query(data), asyncExecutor).whenComplete((result, th) -> {})).toArray(CompletableFuture[]::new);CompletableFuture.allOf(futureArray).join();
Preferred use ThreadPoolExecutor class , We customize the thread pool .
The specific code is as follows :
You can also use ThreadPoolTaskExecutor Class to create a thread pool :
ExecutorService threadPool = new ThreadPoolExecutor(8, //corePoolSize Number of core threads in the thread pool10, //maximumPoolSize The maximum number of threads in the thread pool60, // Maximum idle time of a thread in a thread pool , After this time, idle threads will be recycledTimeUnit.SECONDS,// Time unitnew ArrayBlockingQueue(500), // queuenew ThreadPoolExecutor.CallerRunsPolicy()); // Refusal strategy
After this optimization , Interface performance has also been improved 5 times .
@Configurationpublic class ThreadPoolConfig {/*** Number of core threads , Default 1*/private int corePoolSize = 8;/*** Maximum number of threads , Default Integer.MAX_VALUE;*/private int maxPoolSize = 10;/*** Idle thread lifetime*/private int keepAliveSeconds = 60;/*** Thread blocking queue capacity , Default Integer.MAX_VALUE*/private int queueCapacity = 1;/*** Allow core thread timeout*/private boolean allowCoreThreadTimeOut = false;@Bean("asyncExecutor")public Executor asyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize);executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveSeconds);executor.setAllowCoreThreadTimeOut(allowCoreThreadTimeOut);// Set rejection policy , Directly in execute Method to run a rejected task in the calling thread of theexecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// Perform initializationexecutor.initialize();return executor;}}
from 5s about , Shorten to 1s about .
But the overall effect is not ideal .
5. Third optimization After the previous two optimizations , The performance of the batch query evaluation interface has been improved , But it still takes more time than 1s.
The root cause of this problem is : There is too much data to query at one time .
that , Why don't we limit , The number of records per query ?
Third optimization , Limit the number of records queried at one time . In fact, restrictions have been made before , But the biggest is 2000 Bar record , At present, the effect is not good .
Restrict the interface to check only 200 Bar record , If exceeded 200 An error message will appear .
If you restrict this interface directly , It may cause exceptions in the business system .
To avoid this happening , We must discuss the optimization scheme with the business system team .
There are mainly the following two schemes :
5.1 Front end paging In the statement page of the statement , By default, only 1 Order per order , Redundant paging queries .
In this case , If the maximum per page 100 Record calculation , Settlement documents and orders can only be queried at most once 200 Bar record .
This requires the front end of the business system to do paging function , At the same time, the back-end interface should be adjusted to support paging queries .
But the current situation is that there are no redundant development resources at the front end .
Because of the shortage of manpower , This plan can only be put on hold for the time being .
5.2 Call the interface in batches The back-end of the business system calls the evaluation query interface once , Now change the component batch call .
such as : Before the query 500 Bar record , The business system only calls the query interface once .
Now the business system only checks 100 Bar record , branch 5 Batch call , In total, it is also a query 500 Bar record .
Isn't this slowing down ?
answer : If that 5 Batch call the operation of evaluation query interface , Is in for Single threaded sequence in the loop , Of course, the overall time consumption may slow down .
But the business system can also be changed to multi-threaded invocation , Just summarize the final results .
here , Someone may have a problem : In the evaluation query interface of the server multi-threaded call , It is not the same thing as multithreading in other business systems ?
It's better to put the batch evaluation query interface in the server , Increase the maximum number of threads in the thread pool ?
Obviously you have overlooked one thing : Online applications are generally not deployed as a single point . In most cases , In order to avoid the server hanging , Cause a single point of failure , Basically, at least 2 Nodes . In this way, even if a node hangs , The whole application can also be accessed normally .
Of course, this may also happen : Suppose you hang a node , Another node may have too much traffic , Can't bear the pressure , It may also cause death .
let me put it another way , Call the interface through multiple threads in the business system , The traffic load of the access interface can be balanced to different nodes .
They also use 8 Threads , Batch the data , Each batch 100 Bar record , Finally, summarize the results .
After this optimization , Interface performance has been improved again 1 times .
from 1s about , Shorten to less than 500ms.
A warm reminder , Whether it is in the batch query evaluation interface to query the database , Or call the batch query and evaluation interface in the business system , Using multithreaded calls , It's just a temporary plan , Not perfect .
The main reason for this is to quickly solve the problem first , Because the change of this scheme is the smallest .
We should solve the problem fundamentally , This set of functions needs to be redesigned , The table structure needs to be modified , You may even need to modify the business process . But because it involves multiple business lines , Multiple business systems , I can only schedule it slowly .
From the original :
边栏推荐
- [untitled]
- Web: compiling big refactoring from 10 to 1
- Blog Description & message board
- China trifluoroethanol industry research and investment forecast report (2022 Edition)
- MySQL -- index and transaction isolation level
- STM32 Development Notes 118: using CMSIS DSP Library in stm32cube IDE
- 服务器防护的七个建议
- This low code reporting tool is needed for data analysis
- four hundred and forty-four thousand one hundred and forty-one
- Getting started with scratch
猜你喜欢

Completed project series Tutorials - smart campus management system
![[literature notes] pointmlp](/img/8f/654dc6e2f4770b7f12aab49098d3d7.png)
[literature notes] pointmlp

Small case of data analysis: visualize recruitment data and view the most needed technologies in the field~

Leetcode55. Jumping game

Unity LOD

Construction of Seata multilingual system

The interviewer asked MySQL transactions, locks and mvcc at one go. I

【微信小程序】拍卖商品详情页设计与交互实现(包含倒计时、实时更新出价)

盐粒和冰粒分不清

【浅析STM32之GPIO寄存器(CRL/CRH)配置 】
随机推荐
956. Highest billboard pressure DP
The strongest JVM in the whole network is coming!
ES6 -- Methods and extensions of array objects, traversal of arrays, and extension methods of strings
STM32 development note 117: generate IIR low-pass filter coefficients using MATLAB
如何判断是否遭到DDOS攻击
Market regulation
2022-7-15 summary
Style transfer -- CCPL: contrast coherence preserving loss for versatile style transfer
[wechat applet] label (86/100)
实战|记一次攻防演练打点
Deep understanding of pod
Baklib: share some methods about building enterprise knowledge management (km)
Burpsuite爆破之token值替换
Idea2021 installation
Logu p3398 hamsters find sugar solution
Li Kou 731. My schedule II
绕过 Web 应用程序中的 XSS 过滤器
Valley p2420 let's XOR solution
In depth understanding of service
HMS core discovery Episode 16 live broadcast preview | play AI's new "sound" state with tiger pier