redis Learning (Five): Common Problems and Solutions

First, how to ensure double buffer write to the database consistency

1.1, the most classic database read and write cache + mode


Reading time: first read cache, cache not, attend the database, and then removed after the data into the cache, and returns the response
time updates: first update the database, and then delete the cache
Why delete cache, instead of updating the cache:
more complex cache cache scene is not just a database directly taken out of value, such as might update a field in a table, then the corresponding cache, the other two is the need to query data tables and operations, in order to calculate the cache date value; updating the cache can be expensive, and some scenes may be modified each time the database are sure to update a corresponding cache, but this cache may not be frequently accessed. For example, a cache is a table field one minute update the cache 100 is updated 100 times but only read once, there is a lot of cold data , delete the cache only if the cache is only 1 minute to recalculate only once, use the cache only to count the cache (lazily thought)


1.2, the primary cache inconsistency problems and solutions (to update the database, and then delete the cache)


Question: After the first update the database to delete the cache, delete cache fails, the database will lead to new data, the cache is old data, there have been inconsistencies
solution: delete the cache, and then update the database . If the database update fails, then the database is old data, the cache is empty, then the data is not inconsistent, because when the cache is not read, so read the old data in the database, and then update the cache


1.3, inconsistencies and complex caching solutions (to delete the cache, and then update the database)


Question: delete the cache, and then modify the database, they will not modify a request over and read the cache was found empty the cache, query the database to be found in the old data before the modification and placed in the cache. Subsequent data change program finished modifying the database, but inconsistent data in the database and cache the ( concurrent read and write will appear this inconsistency problem)
Solution: update the data when, according to the unique identification data after operating the route, send a jvm internal queue, reading the data in the cache data is not found, re-execute "+ updated read data cache" operation, in accordance with the unique identifier after the routing, it is also sent to the same jvm internal queue. A queue corresponding to a working thread , each worker thread to get the corresponding serial operation, then a one is performed.
If a read request over not read cache, the cache can first update request is sent to the queue, then the backlog in the queue will then wait for the cache update complete synchronization. After that queue corresponding work to be done to modify the database thread on one operation, will perform the operation to the next cache update, then reads the latest values from the database, and then write cache.
If the request waiting time range, to continue the polling can take values found, then return directly; if the waiting time exceeds a certain length of time request, then this time the old value of the current read directly from the database.


1.4, a highly concurrent scenarios, the complex caching solutions to problems should be noted


(1) blocking read request long (read timeout):
The program may be data updated very frequently, resulting in the queue backlog is a significant update operations on the inside, and then the read request a lot of time out will occur, leading to a large number of requests go directly to the database, so to simulate a real test (pressure test, and simulated online environment);
for example: if a queue memory 100 extruded product inventory modify operation, modify the operation of each stock-consuming to complete 10ms, then the last commodity after the read request may wait 10 * 100 = 1000ms = 1s, to get the data, this time leading to long blocking read request.
Solution: deploying a plurality of service (plus machine), each serving a number of update operations share data; stress testing, simulation and online environment;
(2) the amount of high concurrent read requests
do stress testing
(3) multiple service instances request routing deployed
deployed under conditions of a plurality of instances, and performs data cache update operations must Nginx server via the same route to the service instances
such as: read and write requests for the same item, all routes to the same machine, do between services in accordance with a hash routing request parameter, you can also use the hash routing Nginx

 

Two, redis how to solve the problem of concurrent competition

When 'Ali Development Manual "provides concurrent modification of the same record, avoid lost updates, need to lock:

要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。
说明:如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次
数不得小于 3 次

Problem :
the problem of redis; multi-client concurrent write a key, after probably should have first come to the data, leading to the wrong version of the data; or multiple clients simultaneously read a key, then go back and write the modified value, As long as the order is wrong, wrong data.
And there redis own natural solution to this problem  CAS kind of optimistic locking scheme (CAS redis affairs program)
Solution:
If at some point, multiple system instances to update a key. Can be achieved based zookeeper distributed lock . Each system acquired by zookeeper distributed lock to ensure the same time, only one instance of the operating system a key, others are not allowed to read and write.
To write cache data, all from inside sql check out, I had to write sql, the sql written in when necessary to save a timestamp, check out the mysql time, also check out the time stamp. Before each write, first determine what the current value of the timestamp is newer than the timestamp of the value of the cache. If so, you can write, otherwise, the old data can not be used to cover the new data.

 

Third, the cache and cache penetrate avalanche

3.1, the cache avalanche

The reason (1) cache avalanche generated

Since the original cache invalidation, which is the key redis all at the same time has expired, all requests for access to the cache are supposed to check the database, causing huge pressure on the database and CPU, serious or even down, causing the system to crash.

(2) resolve caching scheme avalanche

The first : the use of distributed lock or local lock can be guaranteed not to have a large number of threads to the database to read and write a one-time, but will reduce the throughput (lock not recommended);

Second: As redis standby, but the problem related to double buffer will update transactions, but may read the dirty data (not recommended)

Third: the redis key shared equally assigned dead time ;

Fourth: the secondary cache do Redis + Ehcache;

Fifth: The messaging middleware way . If a large number when requesting access, redis if the case is not worth it, this will be the message stored in the MQ (MQ default step one, but use synchronous here ), according to consumer query parameters, and the results ( such as up to consumers receiving message 50, the producer transmits a message 1000, 950 requests waiting , so this approach is best);

 

(3) specific solutions

1: After a cache miss, by locking to control the number of threads or queue database read write cache. For example, a key for allowing only one thread to query the data and write cache, waiting for other threads

@RequestMapping("/getUsers")
	public Users getByUsers(Long id) {
		// 1.先查询redis
		String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()
				+ "-id:" + id;
		String userJson = redisService.getString(key);
		if (!StringUtils.isEmpty(userJson)) {
			Users users = JSONObject.parseObject(userJson, Users.class);
			return users;
		}
		Users user = null;
		try {
			lock.lock();
			// 查询db
			user = userMapper.getUser(id);
			redisService.setSet(key, JSONObject.toJSONString(user));
		} catch (Exception e) {

		} finally {
			lock.unlock(); // 释放锁
		}
		return user;
	}

2: shared equally allocate time to failure. Different key set different expiry time for the cache invalidation point of time as even as possible (more reliable).

3: do secondary cache

 

3.2, buffer penetration

(1) cache causes penetration

Cache penetration refers to the user to search the database, not in the database, naturally there will not be in the cache. When the cause can not be found in the user's query cache, each time to a database and then check it again, and then return empty. So please ask bypassing the cache query the database directly , leading to penetrate the cache!

(2) penetrate caching solutions to solve

The first: gateway determines rule key corresponding to the incoming client, if you do not meet the rules, direct return null;

The first: If you query the database is empty, directly set a default value into the cache , so get there in a second buffer value, while not continue to access the database. That is the space to cache the results so that the next request can be directly returned empty, that is caused when the buffer is empty when the query to avoid penetration;

Third: it may also be provided a separate cache memory control area, to query on key pre-check, and then released to normal caching logic behind.

 

(3) Specific operation is as follows

public String getByUsers2(Long id) {
		// 1.先查询redis
		String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()
				+ "-id:" + id;
        //1.先查询redis
		String userName = redisService.getString(key);
		if (!StringUtils.isEmpty(userName)) {
			return userName;
		}
		System.out.println("######开始发送数据库DB请求########");
		Users user = userMapper.getUser(id);
		String value = null;
        //2.如果数据库中没有对应的数据信息的时候
		if (user == null) {
			// 标识为一个值,防止黑客攻击
			value = SIGN_KEY;
		} else {
			value = user.getName();
		}
		redisService.setString(key, value);
        //3.直接返回
		return value;
	}

Note: When the true value of the stored ip give corresponding need to clear the cache before the corresponding empty.

 

Fourth, the hot key

4.1 What is a hot key

A key visit very often, when the key failure of a large number of threads to build the cache, resulting in increased load, system crashes

4.2, hot key solutions

(1) a lock, single use of synchronized, lock etc., distributed using a distributed lock

(2) the cache expiration time is not set, but in the value in the corresponding key. If the detected stored for longer than the expiration time, asynchronous cache update

(3) disposed on a value of the expiration time t0 t1 smaller than the expiration time expires when the time t1, t1 to extend and make the update cache operation

 

 

 

 

Published 52 original articles · won praise 116 · views 50000 +

Guess you like

Origin blog.csdn.net/RuiKe1400360107/article/details/103706472