preface

  • Redis is a kind of cache database that is often used in projects. Understanding its configuration and design ideas will help us to use it more effectively and safely
  • This is an introduction to caching design optimization and performance optimization.

Cache design Parsing

The cache to penetrate

  • Cache penetration refers to querying data that does not exist and cannot be hit at both the cache and database layers.
  • As a result, every query request for non-existent data is finally queried in the database layer. The database cannot find the data and cannot write the data to the cache, which loses the significance of cache filtering requests to protect DB.
  • There are basically two reasons for cache penetration:
    • A problem with your own business code or data
    • Some malicious attacks, crawlers caused a large number of empty data hit
  • Several solutions for cache penetration:
  1. Cache null objects:
/** * @AUTHOR ZRH * @DATE 2021/7/31 */ @Service public class RedisServiceImpl { @Autowired private RedisUtils redisUtils; @Autowired private StorageMapper storageMapper; Private final static EXPIRE = 60000; private final static EXPIRE = 60000; private final static Object DEFAULT_VALUE = new Object(); Public String redisCache(String key) {String value = redisutils.get (key); If (a null value) = = {/ / get the data in the database layer value = storageMapper. GetDataToDB (key); If (null == value) {// save the default data to the cache layer, Redisutils. set(key, DEFAULT_VALUE, 1000, timeunit.milliseconds); } else { redisUtils.set(key, value, EXPIRE, TimeUnit.MILLISECONDS); } } return value; }}Copy the code
  1. Bloom filter:
  • For malicious attacks, if a large amount of non-existent data is requested from the server to cause cache penetration (for example, the data whose user ID is -1 is queried), you can use the Bloom filter to filter first
  • When the Bloom filter says a value exists, the value may not exist. When it says no, it must not exist
  • The specific implementation of bloom filter can refer to the article # Distributed Bloom Filter Practice

Cache breakdown (failure)

  • The cache time of a hot data (such as a hot product information in the second kill activity) expires, at this time there are a large number of requests cannot hit this data and direct to the database, the database pressure may increase instantly resulting in machine downtime, etc
  • Several solutions for cache breakdown:
  1. Setting the hotspot data to never expire (not recommended)
  2. Add a mutex
/** * @AUTHOR ZRH * @DATE 2021/7/31 */ @Service public class RedisServiceImpl { @Autowired private RedisUtils redisUtils; @Autowired private StorageMapper storageMapper; @Autowired private RedissonClient redissonClient; Private final static EXPIRE = 60000; private final static EXPIRE = 60000; private final static Object DEFAULT_VALUE = new Object(); Public String redisCache(String key) {String value = redisutils.get (key); If (null == value) {// use redisson to implement distributed lock RLock lock = redissonclient.getLock (key); try { lock.lock(); / / get the data in the database layer value = storageMapper. GetDataToDB (key); If (null == value) {// save the default data to the cache layer, Redisutils. set(key, DEFAULT_VALUE, 1000, timeunit.milliseconds); } else { redisUtils.set(key, value, EXPIRE, TimeUnit.MILLISECONDS); } } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } return value; }}Copy the code

Cache avalanche

  • Cache avalanche refers to a time when a large number of keys in the cache fail at the same time. As a result, requests directly hit the database, resulting in an instantaneous increase in database pressure or even a breakdown
  • Several solutions to caching avalanches:
  1. Set hotspot data to never expire (not recommended, it always occupies resources)
  2. Use mutex (not recommended, slow blocking)
  3. Cache tag (monitors hotspot data and triggers cache data update if the cache expires)
  4. Set different expiration times for different keys by random number
int nextInt = new Random().nextInt(60000);
redisUtils.set(key, value, EXPIRE + nextInt, TimeUnit.MILLISECONDS);
Copy the code

The data consistency between cache and database is abnormal

  • Operating databases and caches at the same time can cause data consistency problems in high concurrency situations
  1. Dual-write causes data inconsistency

  1. Read and write causes data inconsistency

  • There are several ways to solve the data consistency problem:
  1. In business scenarios where the amount of concurrency is small or data inconsistency can be tolerated over a short period of time, this issue is rarely considered
  2. If the concurrency is high and data inconsistency cannot be tolerated, read/write locks can be added to ensure sequential execution of concurrent read/write and write. Read locks are equivalent to lock-free
  3. Ali’s open source Canal can be used to timely modify the cache data by listening to the binlog log of mysql, and new middleware needs to be introduced

Performance optimization,

The key value design

  • The key name is designed to be readable, manageable, concise, and does not contain special characters
  1. Prefixed with the business name (or database name) (to prevent key conflicts), separated by colons, such as business name: table name: ID
  2. On the premise of ensuring semantics, control the length of keys. When there are many keys, the memory usage cannot be ignored
  • The value design rejects bigkey (prevents nic traffic, slow query), in Redis a maximum of 512M per string, and a secondary cache data structure (hash,list,set,zset) can store 2^32-1 elements. But it is also considered a BigKey in the following cases
  1. String type: it is big in the form of a single value. It is generally considered to be a BigKey if the value exceeds 10KB
  2. Non-string types: hashes, lists, collections, ordered collections, which have big because they have too many elements. Generally speaking, the string type should be less than 10KB, and the number of hash, list, set, and zset elements should not exceed 5000
  • How do I optimize BigKey
  1. Break up
    • Big list: list1, list2,… listN
    • Big hash: You can partition data into sections. For example, a large key (say, 1 million user data) can be split into 200 keys, with 5000 user data stored under each key
  2. If bigKey is inevitable, think about pulling all the elements out at a time (for example, sometimes you just need hmGET, not HGEtall). Delete is the same, and try to do it in an elegant way.

Expiry policies

  • Redis has three expiration policies for expiration keys
1. Passive deletion: When an expired data is read or written, lazy deletion is triggered and the current data is directly deleted. Active deletion: Passive deletion cannot ensure that cold data will be deleted in time, so Redis will periodically delete some expired data 3. When the current used memory exceeds the maxMemory limit, the active cleanup policy is triggeredCopy the code
  • Active cleaning policy Before Redis 4.0, there were six memory flushing policies. After Redis 4.0, two LFU flushing policies are added. There are eight lFU flushing policies.
1. Volatile - TTL: in view of the key/value pair set the expiration time, according to the order of expiration time deleted, the earlier date the first remove 2. Volatile - random: to set the expiration time of key-value pairs, random delete 3. Volatile - lru: Use the keys of the lru algorithm in setting up the expiration time on screening to remove 4. Volatile - lfu: use lfu algorithm in setting up the selection of key/value pair of expiration time delete 5. Allkeys - random: from random delete 6. So the key/value pair allkeys - lru: 8. Noeviction: Does not delete data, refuses to write operations when memory is full and returns a client error messageCopy the code
  • Lru is efficient when hot data is present, but occasional, periodic batch operations can cause LRU hit rates to drop and the cache to pollute validation. It is better to use the LFU.
  • If you want to know about LRU algorithm, you can see this article # LRU algorithm record
  • If you want to know more about lFU algorithm, you can see this article # LFU algorithm code implementation record

The last

  • Study with an open mind and make progress together