Programming technology cache writing method (3)
We talked about multi-level cache last time. This chapter introduces in detail how to design the memory cache.
1: Analysis and Design
Suppose there is a project with a certain amount of concurrency, which requires the use of multi-level cache, as follows:
Before actually designing a memory cache, we need to consider issues:
1: Memory Data replacement with Redis improves the data hit rate in memory as much as possible and reduces the pressure on the next level.
2: Memory capacity limit, the number of caches needs to be controlled.
3: Hotspot data updates are different and a single key expiration time needs to be configurable.
4: Good cache expiration deletion strategy.
5: Keep the complexity of the cache data structure as low as possible.
About replacement and hit rate: We use the LRU algorithm because it is simple to implement and the cache key hit rate is also very good.
LRU means: eliminate the data that has been accessed least recently, and the data that is frequently accessed is hot data.
About LRU data structure: Because of key priority promotion and key elimination, a sequential structure is required. I have seen that most implementations adopt a linked list structure, that is: new data is inserted into the head of the linked list, and the data when hit is moved to the head. Adding complexity is O(1) and moving and getting complexity is O(N).
Is there anything less complex? There is Dictionary, whose complexity is O(1) and has the best performance. So how to ensure that the cache priority is improved?
Two: O(1) LRU implementation
We define a LRUCache
Use ConcurrentDictionary as our cache container and ensure thread safety.
public class LRUCache<TValue> : IEnumerable<KeyValuePair<string, TValue>> { private long ageToDiscard = 0; //淘汰的年龄起点 private long currentAge = 0; //当前缓存最新年龄 private int maxSize = 0; //缓存最大容量 private readonly ConcurrentDictionary<string, TrackValue> cache; public LRUCache(int maxKeySize) { cache = new ConcurrentDictionary<string, TrackValue>(); maxSize = maxKeySize; } }
The two self-increasing parameters ageToDiscard and currentAge are defined above. Their function is to mark the newness of each key in the cache list.
The core implementation steps are as follows:
1: Each time a key is added, currentAge is incremented and the currentAge value is assigned to the Age of this cache value. CurrentAge always increases.
public void Add(string key, TValue value) { Adjust(key); var result = new TrackValue(this, value); cache.AddOrUpdate(key, result, (k, o) => result); } public class TrackValue { public readonly TValue Value; public long Age; public TrackValue(LRUCache<TValue> lv, TValue tv) { Age = Interlocked.Increment(ref lv.currentAge); Value = tv; } }
2: When adding, if the maximum quantity is exceeded. Check whether there is an ageToDiscard age key in the dictionary. If there is no cyclic auto-increment check, the deletion and addition will be successful.
ageToDiscard+maxSize= currentAge, so that the design can ensure that old data can be eliminated under O(1) instead of using linked list movement.
public void Adjust(string key) { while (cache.Count >= maxSize) { long ageToDelete = Interlocked.Increment(ref ageToDiscard); var toDiscard = cache.FirstOrDefault(p => p.Value.Age == ageToDelete); if (toDiscard.Key == null) continue; TrackValue old; cache.TryRemove(toDiscard.Key, out old); } }
Expired deletion strategy
In most cases, the LRU algorithm has a high hit rate for hotspot data. However, if a large number of sporadic data accesses occur suddenly, a large amount of cold data will be stored in the memory, which is cache pollution.
will cause LRU to be unable to hit hotspot data, causing the cache system hit rate to drop sharply. Variant algorithms such as LRU-K, 2Q, and MQ can also be used to improve the hit rate.
Expiration configuration
1: We try to avoid cold data resident in memory by setting the maximum expiration time.
2: In most cases, the time requirements of each cache are inconsistent, so the expiration time of a single key is increased.
private TimeSpan maxTime; public LRUCache(int maxKeySize,TimeSpan maxExpireTime){} //TrackValue增加创建时间和过期时间 public readonly DateTime CreateTime; public readonly TimeSpan ExpireTime;
Deletion strategy
1: Regarding key expiration deletion, it is best to use scheduled deletion. This can release the occupied memory as quickly as possible, but obviously, a large number of timers are too much for the CPU.
2:所以我们采用惰性删除、在获取key的时检查是否过期,过期直接删除。
public Tuple<TrackValue, bool> CheckExpire(string key) { TrackValue result; if (cache.TryGetValue(key, out result)) { var age = DateTime.Now.Subtract(result.CreateTime); if (age >= maxTime || age >= result.ExpireTime) { TrackValue old; cache.TryRemove(key, out old); return Tuple.Create(default(TrackValue), false); } } return Tuple.Create(result, true); }
3:惰性删除虽然性能最好,对于冷数据来说,还是没解决缓存污染问题。 所以我们还需定期清理。
比如:开个线程,5分钟去遍历检查key一次。这个策略根据实际场景可配置。
public void Inspection() { foreach (var item in this) { CheckExpire(item.Key); } }
惰性删除+定期删除基本能满足我们需求了。
总结
如果继续完善下去,就是内存数据库的雏形,类似redis。
比如:增加删除key的通知,增加更多数据类型。 本篇也是参考了redis、Orleans的实现。

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

How to remove duplicate values from PHP array using regular expressions: Use regular expression /(.*)(.+)/i to match and replace duplicates. Iterate through the array elements and check for matches using preg_match. If it matches, skip the value; otherwise, add it to a new array with no duplicate values.

1. Programming can be used to develop various software and applications, including websites, mobile applications, games, and data analysis tools. Its application fields are very wide, covering almost all industries, including scientific research, health care, finance, education, entertainment, etc. 2. Learning programming can help us improve our problem-solving skills and logical thinking skills. During programming, we need to analyze and understand problems, find solutions, and translate them into code. This way of thinking can cultivate our analytical and abstract abilities and improve our ability to solve practical problems.

Build browser-based applications with Golang Golang combines with JavaScript to build dynamic front-end experiences. Install Golang: Visit https://golang.org/doc/install. Set up a Golang project: Create a file called main.go. Using GorillaWebToolkit: Add GorillaWebToolkit code to handle HTTP requests. Create HTML template: Create index.html in the templates subdirectory, which is the main template.

Python is an ideal programming introduction language for beginners through its ease of learning and powerful features. Its basics include: Variables: used to store data (numbers, strings, lists, etc.). Data type: Defines the type of data in the variable (integer, floating point, etc.). Operators: used for mathematical operations and comparisons. Control flow: Control the flow of code execution (conditional statements, loops).

Java Made Simple: A Beginner's Guide to Programming Power Introduction Java is a powerful programming language used in everything from mobile applications to enterprise-level systems. For beginners, Java's syntax is simple and easy to understand, making it an ideal choice for learning programming. Basic Syntax Java uses a class-based object-oriented programming paradigm. Classes are templates that organize related data and behavior together. Here is a simple Java class example: publicclassPerson{privateStringname;privateintage;

Java is a popular programming language that can be learned by both beginners and experienced developers. This tutorial starts with basic concepts and progresses through advanced topics. After installing the Java Development Kit, you can practice programming by creating a simple "Hello, World!" program. After you understand the code, use the command prompt to compile and run the program, and "Hello, World!" will be output on the console. Learning Java starts your programming journey, and as your mastery deepens, you can create more complex applications.

Pythonempowersbeginnersinproblem-solving.Itsuser-friendlysyntax,extensivelibrary,andfeaturessuchasvariables,conditionalstatements,andloopsenableefficientcodedevelopment.Frommanagingdatatocontrollingprogramflowandperformingrepetitivetasks,Pythonprovid

C is an ideal choice for beginners to learn system programming. It contains the following components: header files, functions and main functions. A simple C program that can print "HelloWorld" needs a header file containing the standard input/output function declaration and uses the printf function in the main function to print. C programs can be compiled and run by using the GCC compiler. After you master the basics, you can move on to topics such as data types, functions, arrays, and file handling to become a proficient C programmer.
