1. Cache penetration
Cache penetration refers to whenWhen the requested data is neither in the cache nor in the database, the request passes directly through the cache layer to the database layer。This is usually caused by malicious attacks or bugs, such as an attacker deliberately requesting a large amount of data that does not exist, resulting in a cache failure and all requests falling to the database, which can put a huge strain on the database, affect its performance and even cause a crash, usually thread running skyrocketing.
Solution
Bloom filter:A bloom filter is a data structure that can be used to detect whether an element is in a set. Before the request reaches the cache, it is checked by a bloom filter, and if the bloom filter determines that the data does not exist, it directly returns an error response to avoid access to the database.
Caching empty results:When you query the database and find that the data does not exist, you can use this"Empty result"Also cache it up and set a short expiration time. This way, when the same data is requested again, it can be fetched directly from the cache"Empty result"to avoid access to the database. It should be noted that this approach may cause the cache to be filled with a large number of useless empty results, so you need to set the expiration time reasonably.
Throttling Requests:For unusually frequent access behaviors, you can restrict them by means such as throttling and blocking IP addresses. For example, you can limit the frequency of each user's access, the speed of requests, and so on, and temporarily block their requests if the limit is exceeded.
API Authentication:Authentication and parameter verification are done at the interface layer to prevent illegal requests or incorrectly formatted requests from accessing the database.
Database indexing:For some scenarios where it is necessary to access the database, to ensure that the database has good query performance, you can improve query efficiency by establishing reasonable indexes.
L2 Cache:Use the local cache as the first-level cache and Redis as the second-level cache. If the local cache fails, then query the database. This reduces the number of direct query requests to Redis and reduces the pressure on Redis.
Front-end control:Strengthen verification in front-end applications, such as form verification and validity check of input content, to avoid sending invalid requests to the backend.
Second, the cache avalanche
A cache avalanche is an avalanche in a caching systemBecause a large amount of cached data expires at the same time, or the cache service goes down, all requests fall directly to the database, resulting in the database being under huge access pressure in an instant, thus becoming unstable or even crashing. This is similar to an avalanche that, once it happens, can lead to a chain reaction that leads to a drastic drop in the performance of the entire system.
Solution
Expiration time randomization of cached data:When setting the expiration time of cached data, don't let a large amount of cached data expire at the same point in time. You can add a random value to the expiration time to spread out the expiration time of the cached data and prevent a large area of cache failure at the same time.
Use persistence:If the cache service supports persistence, such as RDB and AOF for Redis, make sure that these features are enabled and properly configured. In this way, even if the cache service is restarted, it can recover from persistent data, reducing the risk of cache avalanches.
Set hotspot data to never expire:For some hot data, you can set it to never expire, or you can use a strategy to manually update the cache to avoid the collective expiration of these hot data.
Use a multi-level caching strategy:You can use a multi-level caching strategy that combines local caches (e.g., ehcache) and distributed caches (e.g., Redis) to provide services even if the distributed cache is unavailable, reducing the direct pressure on the database.
Improve the high availability of the cache service:High-availability schemes, such as master-slave replication, sentinel mechanism, and clustering, are used to ensure the stability of the cache service. Even if a single node fails, it can quickly switch to a normal node to ensure that the cache service is not interrupted.
Current Limiting and Fusing Mechanisms:Implement the throttling and circuit breaker mechanism in the system to temporarily block some requests when the traffic or errors exceed a certain threshold, protecting the database and the system from being overloaded.
Asynchronous queues:After the cache is invalidated, you can put the read operations of the database into an asynchronous queue and use asynchronous processing to mitigate the impact of instantaneous traffic on the database.
3. Cache breakdown
Cache breakdown refers to:At the moment when the cache is invalidated, there are a large number of concurrent requests for this data point, and these requests will directly penetrate the cache and all fall to the database, causing high pressure on the database in a short period of time. This is different from cache pass-through, which queries data that doesn't exist, and cache breakdown, which queries data that exists but the cache just expires.
Solution
Use mutex:For the same data point, when the cache is invalidated, the lock or synchronization mechanism is used to ensure that no matter how many concurrent requests, only one request is allowed to query the data in the database and update the cache, and other requests wait for the cache to be updated and get the data directly from the cache. A common practice is to use distributed locks.
Set hotspot data to never expire:For some hot data that is accessed very frequently, you can set the cache to never expire, or the background maintenance thread is responsible for updating after the cache expires, rather than being triggered by the user's request.
Use the Cache Aside patternWhen a cache is invalidated, the cache is not deleted immediately, but another cache is used for the update operation. Until the new cache update is complete, all read requests will still access the old cache. Switch after the update is complete.
Update the cache in advance:For data that is about to expire, you can use a scheduled task to detect and update it. When it detects that cached data is about to expire, the cache can be updated asynchronously in advance.
Set a reasonable expiration time for the cache:For some hot data, set a reasonable expiration time based on business scenarios to prevent a large number of concurrent requests from breaking down the cache at the same time.
Distributed Cache + Local Cache:You can implement a layer of caching locally to reduce the frequency of access to the Distributed Cache service, which can still be served even if the data of the Distributed Cache service expires.
Read/write splitting and load balancing:The database uses a read/write splitting architecture and a load-balancing strategy to distribute read operations across multiple slaves to reduce direct pressure on the primary database.
Fourth, the data is inconsistent
Cache and database data inconsistencies are often caused byThe data synchronization policy between the cache layer and the database layer is inappropriatecaused. This can happen in several situations:
1.Writes do not update the cache and database at the same time.
2.The cache expires or is deleted, while the data in the database is modified during that time.
3.Delays in data synchronization due to network latency or other issues in distributed systems.
4.The database transaction is rolled back, but the cache update has already occurred.
These issues can lead to outdated data for users, impact the user experience, and potentially lead to more serious data consistency issues.
Solution
1.Cache update policy
Cache Delay Double Deletion:After the database data is updated, the cache is deleted and then deleted again with a short delay to ensure that if the request reads the old data during this time, the cache is also deleted again to read the latest data.
write/read through cache:Use the writethrough or read through policies provided by the cache to let the cache manager read and write data to ensure data consistency.
write behind caching:The update operation is first performed in the cache and then asynchronously bulk updated to the database, a strategy that takes into account the risk of data loss and data consistency.
2.Database triggers:Ensure data consistency by using database triggers to automatically update the cache when data changes.
3.Transactional Messages:By using a transaction-enabled message queue, you can put cache operations and database operations in the same transaction, ensuring that both succeed or fail.
4.Eventual consistency:Accept that the cache is inconsistent with the data in the database within a certain time window, but the data is periodically proofread and synchronized by a background asynchronous process to ensure eventual consistency.
5.Use a distributed caching solution:Choose a distributed caching solution, such as Redis Cluster, that supports consistent hashing and data synchronization, to ensure data consistency across multiple nodes.
6.Version number Timestamp check:Add a version number or timestamp to the database record, cache the version information together with the cached data, check whether the version or timestamp matches each time the cached data is read, and load it from the database again if it does not.
7.Force Cache Expiration:Set a short cache expiration time to ensure that data is regularly refreshed from the database.
5. Concurrent competition for data
The problem of concurrent competing access to data is often referred to as manyWhen multiple clients or threads read and write the same data at the same time, data inconsistencies or loss occur due to improper concurrency control measuressituation. This problem is especially common in distributed and multi-user systems, especially when using caching systems like Redis.
The scenario where the problem occurs
Counter Update:For example, if multiple requests update the counter at the same time, the counter may be lost because the read and write operation is not atomic.
Inventory Deductions:In the e-commerce scenario, multiple users place orders at the same time to deduct inventory, which may lead to overselling.
Distributed locks:When multiple processes need to operate on the same resource, locks are required to ensure that only one operation can be performed at the same time.
session sharing:In a distributed web application, concurrent requests on multiple servers need to share session information, which may lead to inconsistent session data.
Solution
Working with Transactions:Redis transactions can be executed with the multi and exec commands to ensure the atomic execution of a series of commands.
Use lua script:Redis can execute Lua scripts, and Lua scripts are executed as a whole during execution, which ensures the atomicity of operations.
Using Distributed Locks:A distributed lock based on Redis can be implemented to control concurrent access to resources. For example, use the setnx command to obtain and release locks.
optimistic locking:Use the watch command to monitor one or more keys, and the transaction will only be executed if the keys have not been changed by other commands before the transaction is executed.
pessimistic locking:For critical services, you can lock the data first and unlock it after the service is processed to prevent access by other clients.
Current Restriction Measures:The number of concurrent access to a resource is controlled through rate-limiting algorithms, such as token buckets and leaky buckets, to reduce concurrency conflicts.
Message Queuing:Use message queues to serialize concurrent requests to ensure that access to shared resources is ordered.
Author丨yangyidba**丨***yangyidba(id:yangyidba)dbaplus community welcomes contributions from technical personnel, and the submission email: editor@dbapluscn