High-performance ASP. NET Site build series Article Directories
It was once because of a small negligence that caused the server to crash. It was discovered that it was originally caused by a loop, I am deeply touched by the remark "Pay attention to details.
The topics in this article are as follows:
Problem description
Importance of details
Problem description
First, describe the background of the story: I hope you can read the story patiently)
On the website, the page control in the webpage displays 10 data records each time. Each time you click the next page, the next 10 data records are retrieved again. As for how to do paging, there are many methods, and we believe that everyone knows this.
The process is as follows: when a user requests data, the user's operations and website traffic are taken into account.) for the first time, I will retrieve 500 pieces of data and put the data in the cache. That is to say, I took 50 pages of data and put it in the cache. In this way, if the user requests the first page to 49th pages, the data will be taken directly from the cache.
For example:
The first data block:
Saved in the form of a key-Value Pair: Dictionary
If the user requests 49 pages, the next data block will be retrieved from the database again, which contains 501 to 1000 data records.) then, there will be 1000 data records in the memory.
We will not talk about how long the cache will take, what data will expire, and what will happen after it expires. The website runs well under this cache policy ).
The Code is as follows:
- List<Product> products=GetDataFromCacheOrDatabase(condition,pageIndex,count….);
The meaning of the Code is clear: get data from the cache. If there is no corresponding data in the cache, get 500 pieces of data from the database and then put it in the cache, finally, 10 data records are returned.
Later, due to the needs of some functions, we need to return the first 6 pages of data and the last 6 pages of data on the current page. For example, if the current page is 12th pages, returns the data on the first 6 pages of the Product (page 6, page 6, page 7, page 8, page 9, page 10, and page 11), and the Product (page 13, 14, page 15, and page 16) after page 6, 17, 18 pages of data ).
As follows:
Of course, if the current page is 5th pages, then all the data on the previous 5 pages will be returned, and 6 pages of data after the first 5th pages will be added.
This may involve cross-block data acquisition, for example:
If the current page is 48th pages, there is no problem in returning the first 6 pages of data, and the data on the last 6 pages is insufficient, because and 40 also obtain data from the cached data blocks, as for, 54 pages of data, you need to read the data from the database again, and then cache the data again if it is not cached in advance ).
Finally, the data in the cache is as follows:
Then call the method: pseudo code)
- List<Product> products=GetDataFromCacheOrDatabase(condition,42, 126….);
The data imported above is the data starting from 42nd pages, that is, the data on the first 6 pages and the last 6 pages of the 48th page.
The internal implementation of this method is as follows:
1. First retrieve 42 pages to 50 pages of data from the first data block
Store the data in a List <Product> firstProductList;
2. retrieve from the second data block from 51 to 54 pages. If the second data block does not exist in the cache, retrieve 50-entries from the database, and then put it in the second cached data block ).
Save it in the second List <Product> secondProductList
3. merge the two lists and return the results. For example
- secondProductList.Foreach(u=>firstProductList.Add(u));
The basic implementation is like this. It looks okay and reasonable, but this operation causes the server memory overflow.
Let's see why.
Importance of details
In fact, there are not many cached data, which is insufficient to overflow the server memory, but the server still suffers an out of memory exception. It has been running well before, but the problem occurs only after the code is changed.
In fact, this is caused by a basic error: reference type.
The following is an analysis:
First, extract data from the first data block, and then use
List <Product> firstProductList references the Retrieved Data
Then retrieve the data from the second data block and use
List <Product> secondProductList: Data Reference
For example
Use
- secondProductList.Foreach(u=>firstProductList.Add(u));
Add the data in secondProductList to firstProductList because it is a reference type. In fact, the actual operation result is: constantly changing the data in the first data block, gradually increase the data in the first data block.
Currently, the current page is 48 pages, and the above operation is used, resulting in 60 more data records in the first data block,
If you flip the page again to 49 pages, the number of data records in the first data block increases by 60.
In the end, the server memory is insufficient, causing the server to crash. The original "hero"-Cache has become the culprit.
To solve this problem, you only need to change the code a little bit:
- List<Product> firstProductList;
- List<Product> secondProductList;
Then
List <Product> resultProductList = new List <Product>); then traverse firstProductList and secondProductList respectively and add them to resultProductList.
That's simple.
A small detail causes a big problem.