Programming Technology cache writing (1)

Source: Internet
Author: User
Tags lock queue
I. basic syntax 2: cache avalanche 1: Global lock, instance lock 2: string Lock 3: cache penetration 4: Talk about cache avalanche 5: Summary

Introduction

This article mainly describes cache usage experience and problems encountered in normal projects.

Directory

I. basic writing

II. cache avalanche

1: Global lock, instance lock

2: string lock

III. cache penetration

IV. cache avalanche

V. Summary

I. basic writing

To facilitate the demonstration, we use Runtime. Cache as the Cache container and define a simple operation class. As follows:

public class CacheHelper   {       public static object Get(string cacheKey)       {           return HttpRuntime.Cache[cacheKey];       }       public static void Add(string cacheKey, object obj, int cacheMinute)       {           HttpRuntime.Cache.Insert(cacheKey, obj, null, DateTime.Now.AddMinutes(cacheMinute),               Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);       }   }

Simple read:

Public object GetMemberSigninDays1 () {const int cacheTime = 5; const string cacheKey = "mushroomsir"; var cacheValue = CacheHelper. Get (cacheKey); if (cacheValue! = Null) return cacheValue; cacheValue = "395"; // here the data is generally queried by SQL. Example: 395 sign-in days CacheHelper. Add (cacheKey, cacheValue, cacheTime); return cacheValue ;}

There are many such expressions in the project. There is no error in this writing, but there will be problems after the concurrency comes up. Continue watching

II. cache avalanche

The cache avalanche is caused by cache failure (expiration), and the new cache is not yet in progress.

During this intermediate time, all requests are directed to the database, which puts a lot of pressure on the CPU and memory of the database. the number of frontend connections is insufficient and the query is blocked.

The intermediate time is not that short, for example, 1 second for SQL query, and 0.5 seconds for transmission parsing. That is to say, all user queries within 1.5 seconds are directly queried from the database.

In this case, the most important thing we think of is lock queuing.

1: Global lock, instance lock

Public static object obj1 = new object (); public object GetMemberSigninDays2 () {const int cacheTime = 5; const string cacheKey = "mushroomsir"; var cacheValue = CacheHelper. get (cacheKey); if (cacheValue! = Null) return cacheValue; // lock (obj1) // Global lock // {// cacheValue = CacheHelper. Get (cacheKey); // if (cacheValue! = Null) // return cacheValue; // cacheValue = "395"; // here the data is generally queried by SQL. Example: 395 sign-in days // CacheHelper. Add (cacheKey, cacheValue, cacheTime); //} lock (this) {cacheValue = CacheHelper. Get (cacheKey); if (cacheValue! = Null) return cacheValue; cacheValue = "395"; // here the data is generally queried by SQL. Example: 395 sign-in days CacheHelper. Add (cacheKey, cacheValue, cacheTime);} return cacheValue ;}

First, lock (obj1) is A global lock that can be satisfied, but we need to declare an obj for each function. otherwise, when function A and function B lock obj1, it will surely block one of them.

Second, lock (this) locks the current instance and does not work for other instances. Use the Singleton mode to lock.

But in the current instance: function A locks the current instance, and the function reads and writes of other locks of the current instance are also blocked. Not available

2: string lock

Since the lock object does not work, we can use the character string feature to directly lock the cache key. Let's see

Public object GetMemberSigninDays3 () {const int cacheTime = 5; const string cacheKey = "mushroomsir"; var cacheValue = CacheHelper. Get (cacheKey); if (cacheValue! = Null) return cacheValue; const string lockKey = cacheKey + "n (* ≧ ▽ ≦ *) n"; // lock (cacheKey) // {// cacheValue = CacheHelper. get (cacheKey); // if (cacheValue! = Null) // return cacheValue; // cacheValue = "395"; // here the data is generally queried by SQL. Example: 395 sign-in days // CacheHelper. Add (cacheKey, cacheValue, cacheTime); //} lock (lockKey) {cacheValue = CacheHelper. Get (cacheKey); if (cacheValue! = Null) return cacheValue; cacheValue = "395"; // here the data is generally queried by SQL. Example: 395 sign-in days CacheHelper. Add (cacheKey, cacheValue, cacheTime);} return cacheValue ;}

First, there is a problem with lock (cacheName), because the string is also shared, it will block other operations using this string. For details, refer to the previous blog post c # language-multi-thread lock system (1 ).

Update: because the string is temporarily stored by the Common Language Runtime Library (CLR), this means that there is only one instance for any given string in the entire program. So the second type is used.

The second type: lock (lockKey) can meet the requirements. In fact, the goal is to ensure the minimum granularity and global uniqueness of the lock, and only lock the query behavior of the current cache.

III. cache penetration

For example, we generally cache user search results. If the database cannot be queried, no cache will be performed. However, if this keyword is frequently queried, the database will be directly queried each time.

This makes no sense to cache, which is also a frequently asked cache hit rate problem.

Public object GetMemberSigninDays4 () {const int cacheTime = 5; const string cacheKey = "mushroomsir"; var cacheValue = CacheHelper. Get (cacheKey); if (cacheValue! = Null) return cacheValue; const string lockKey = cacheKey + "n (* ≧ ▽ ≦ *) n"; lock (lockKey) {cacheValue = CacheHelper. get (cacheKey); if (cacheValue! = Null) return cacheValue; cacheValue = null; // The database cannot be queried. it is null. // If (cacheValue2 = null) // {// return null; // generally, this parameter is null and is not cached. //} if (cacheValue = null) {cacheValue = string. empty; // if it is found to be Empty, set a default value and cache it. } CacheHelper. Add (cacheKey, cacheValue, cacheTime);} return cacheValue ;}

In this example, we cache the results that cannot be found. This avoids cache penetration when the query is empty.

Of course, we can also set a separate cache area for the first layer of control validation. So that it is separated from the normal cache.

IV. cache avalanche

Isn't it solved by locking the queue? In fact, the lock queue is only used to reduce the DB pressure and does not increase the system throughput.

In high concurrency: During cache reconstruction, you are locked and 1000 requests are blocked. Poor user experience and a waste of resources: congested threads can handle subsequent requests.

Public object GetMemberSigninDays5 () {const int cacheTime = 5; const string cacheKey = "mushroomsir"; // cache tag. Const string cacheSign = cacheKey + "_ Sign"; var sign = CacheHelper. Get (cacheSign); // Obtain the cache value var cacheValue = CacheHelper. Get (cacheKey); if (sign! = Null) return cacheValue; // return directly if it has not expired. Lock (cacheSign) {sign = CacheHelper. Get (cacheSign); if (sign! = Null) return cacheValue; CacheHelper. add (cacheSign, "1", cacheTime); ThreadPool. queueUserWorkItem (arg) => {cacheValue = "395"; // here the data is generally queried by SQL. Example: 395 sign-in days CacheHelper. Add (cacheKey, cacheValue, cacheTime * 2); // Set the cache time to 2 times for dirty read. });} Return cacheValue ;}

In the code, we use multiple cache-marked keys for dual-check lock verification. It is set to a normal time. after expiration, other threads are notified to update the cached data.

Because the actual cache time is set to 2 times, dirty data can still be used for front-end display.

This will increase the throughput of many systems.

V. Summary

Supplement: blocking other functions here refer to locking the same object in high concurrency.

In actual use, cache layer encapsulation is often more complicated. To update the cache, you can open a single thread to run these tasks. you can easily throw the thread pool.

The specific application scenarios can be balanced based on the actual number of users.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.