How many libraries does Redis have? How to cut the warehouse?

Redis provides 16 libraries by default.

Using the select command to cut a library, such as select2, is to switch to a third library, because Redis’s libraries are sorted from 0.

What are the data structures of Redis?

In terms of redis data structures, there are String strings, list lists, hash tables, set sets, and sorted set ordered sets. This is the basic data type of Redis.

A String is a simple dynamic String.

Then there is the list, which is different from our List in Java. It can be understood as a linked list. Its underlying data structure is a bidirectional linked list and a compressed list.

Hash is the most common data structure in Redis. The bottom layer is hash table. All keys and their corresponding data in Redis are composed of hash tables. It uses hash to form a data structure.

And then sorted set and set, which is an ordered set, which is a regular set, which is a hop table, which is an array.

In addition to these five basic data types, Redis also provides three advanced data structures: bitMaps, HyperLogLogs, and GEO. Bigmap is a good choice if we are recording only 0 and 1 values of the data, because the data in bitmap is recorded with only one bit, which saves memory. For cardinality statistics, that is, the number of non-repeating elements in a set. If the number of elements in a set reaches hundreds of millions, and precise statistics are not required, Hypeloglogs can be used.

Redis inside the jumper data structure

As we know, one of the basic data structures of Redis is called sorted set, which is an ordered set. Its underlying structure is the hop table structure.

When the amount of data is relatively sparse, the sorted set uses compressed linked list to store data at the bottom level. However, once the amount of data is increased, the ordered linked list can only search for elements one by one, which leads to very slow operation, and then hops appear.

Skip table is on the basis of linked list, add a multi-level index, that is, on the linked list, and then add a level of index, if it is still a little slow, then add a level of index on this level, so the data structure, is our skip table.

The advantage of a skip list is that it is much faster to query than a linked list.

Why does Redis have such high performance? Or why is single-threaded Redis performing so well?

First of all, why is Redis single threaded?

Single threading of Redis refers to the fact that the network IO and key pair reads and writes of REids are performed by one thread, which is the main process of Redis to provide services. However, other functions of Redis, such as persistence and asynchronous deletion, are actually performed by additional threads.

So why is Redis single-threaded? One thing to realize is that all data in Redis is, in a sense, shared data. That is to say, if you use multiple threads to manipulate these variables, you will inevitably have concurrent access control problems, and the switching of threads will be expensive, so Redis ended up using a single thread.

So why is single-threaded Redis performing so well?

In my opinion, this should be a comprehensive result. On the one hand, most operations of Redis are done in memory, and it also uses efficient data structures, such as compressed linked lists, hops, hash tables and so on, which is an important reason for its high performance. On the other hand, even though Redis is single-threaded, it uses a multiplexing mechanism.

As we know, Redis uses sockets to communicate with clients, so there will be listening sockets and connected sockets. In general, IO operations, a thread will block on a listening socket or a connected socket.

IO multiplexing, however, is a different mechanism. It refers to the process of multiple IO streams by a single thread. It is also known as the SELECT /epoll mechanism, which allows the operating system kernel to have multiple listening sockets and multiple connected sockets simultaneously. The single thread of Redis does not block on a single listening socket or connected socket. Instead, when the listening socket hears a request coming in, it fires a response event and places the event in an event queue, which redis processes continuously.

In this case, Redis will perform well.

What are the performance bottlenecks for Redis single-threaded IO requests? 六四事件

Once any request takes time in the server, it will affect the performance of the entire server. That is to say, the subsequent requests can only be processed after the previous time-consuming request processing is completed. Time-consuming operations include: 1.1 Operating a Bigkey: Writing a Bigkey consumes more time to allocate memory. Deleting a Bigkey also consumes more time to release memory. 1.2 Using a complex command, such as SORT/SUNION/ZUNIONSTORE or O(N) command, but the N is very large, such as lrange key 0-1 To query all data at one time. 1.3 A large number of Key Expiration: The expiration mechanism of Redis is also implemented in the main thread. A large number of key expiration will lead to the time-consuming deletion of expired keys when processing a request, which will become longer. 1.4 Elimination strategy: The elimination strategy is also implemented in the main thread. When the memory exceeds the Redis memory limit, some keys need to be eliminated each time, which will also lead to a longer time. 1.5 AOF Flush Enable the Always mechanism: The operation is flushed to the disk every time data is written. The write speed of the disk is much slower than that of the memory, which slows down the performance of Redis. 1.6 RDB Generation in full/Master Synchronization: Although fork process is used to generate data snapshot, the whole thread will be blocked at the moment of fork. The larger the instance is, the longer the blocking time will be. When the number of concurrent operations is very large, the performance of single-thread read/write client I/O data suffers from a performance bottleneck. Although THE I/O multiplexing mechanism is adopted, the read/write client data is still synchronous I/O, and the data can only be read from the client in sequence by a single thread, which cannot utilize the MULTIPLE CPU cores. For problem 1, on the one hand, business personnel should avoid it. On the other hand, Redis introduced lazy-free mechanism in 4.0, which puts time-consuming operation of bigkey releasing memory into asynchronous thread to reduce the impact on the main thread. In view of problem 2, Redis introduced multithreading in 6.0, which can use CPU multi-core multithreading to read and write client data in high concurrency scenarios, further improving server performance. Of course, only reading and writing for the client is parallel, and the real operation of each command is still single thread.

Please talk a little bit about redis persistence.

Redis has two main persistence strategies, AOF logs and RDB snapshots.

First let’s talk about AOF log, AOF log after write, that is to say, redis needs to execute command first, write data to memory, then record a log, this is different from mysql, mysql is before write log. There are two main reasons why AOF is a post-write log. First, if it is a pre-write log, when we write a log, we must check whether the log is correct, so the post-write log is not needed, which saves a lot of overhead. The second point is that the post-write log does not block the current write operation, which does not affect Redis performance. Of course, there is a risk of post-logging, if redis is down while executing the command before writing to the AOF log, then we will permanently lose this operation. In addition, although the log after writing does not block the current write operation, it may block the next write operation, which also affects the performance of Redis to some extent.

Redis provides three AOF persistence strategies. The first is to write logs directly to disk every time a command is executed. In the second case, after the command is executed, the log is stored in the memory and written to the disk every second. The third option is to write logs to the memory after the command is executed. The specific time of writing logs to the disk depends on the operating system.

As we know, AOF records the received commands in the form of files, so as time goes by, our AOF files will definitely become bigger and bigger. At this time, we should pay attention to the problems caused by the large SIZE of AOF files.

So with AOF out of the way, let’s talk about RDB.

We know that AOF is a saved command, which means that if our Redis is down, we have to execute commands one by one when we use AOF file to restore, which takes too long and will affect the normal use of our Redis. Therefore, Redis also provides RDB snapshot to achieve persistence.

RDB is a memory snapshot, which records the data status of redis at a certain time and saves it to disk. Before Redis6.0, Redis used a single-thread model, but the RDB saves all the data of Redis to disk, so it will cause the thread to block, so in order not to block the main thread, when implementing the RDB, we will reproduce a child process (note the process). Specifically used to write to RDB files, thus avoiding blocking on the main thread.

Redis can modify the data in memory when taking snapshots of the data in memory. If it can’t be modified, it means redis performance is degraded, but if it can be modified, how to implement the snapshot is very troublesome. Therefore, at this time, Redis will make use of the copy-on-write technology provided by the operating system. When Redis has a command to perform a modification operation, the main thread will make a copy of the modified data and make a copy of the data. Then the main thread will modify the data on this copy. This data is then written to the Redis database.

So, how often do YOU do an RDB? In fact, this time is not very good to grasp, if the time is too short, frequent disk operations and fork out the child process, is bound to affect the performance of Redis, but too long, then if Redis down, the loss of data is too much, unacceptable.

In ReDIS4.0, a hybrid method of using AOF logs and memory snapshots is proposed. In simple terms, the RDB is executed at a certain frequency, and in between, all command actions are recorded using AOF logs, and the AOF logs are cleared on the second RDB. The advantage is that you don’t have to fork and RDB frequently, and AOF files don’t get too big.

AOF file is too large, resulting in performance problems, what is the solution?

The first thing we need to know is, what are the performance problems caused by large AOF files? The main problem is three aspects, the first is the file system itself has a limit on the size of files, can not save too large files. Second, if the file is too large, and then add command records to it, the efficiency will become low. Third, if Redis breaks down, AOF record commands need to be executed one by one, but the AOF file is too large, resulting in a long recovery time, which will affect the normal use of REDis.

The solution is the AOF rewrite mechanism. As we know, AOF files are appended, and each time the database operates on a key, an AOF log is generated, so that each key command generates a large number of AOF logs. Then the solution is related to the, redis will according to the current situation of the database, create a new AOF file, then read all key/value pair in the database, then each key value with the current value of a command to record it, so that you can put all previous AOF about the key values of the old log, Merge into an AOF log, so the AOF is much smaller.

However, the process of rewriting is to write the latest operation log of the entire database to disk. If the main thread is used to write the operation log, it will take a long time and block the main thread, so Redis will rewrite the process through the backend process bgrewriteaof (note that this is a process, not a thread). To avoid blocking the main thread.

When does rewriting happen? In Redis there is a configuration item that can be handled, a value that sets the minimum size of the AOF file. The default is 64MB. Another configuration is the difference between the size of the current AOF file and the size of the AOF file since the last rewrite, divided by the value of the size of the file since the last rewrite. When the log size of AOF exceeds both of these configurations, overwriting is triggered.

How is the final consistency of master/slave replication data achieved in Redis?

Redis provides the master-slave mode. In order to ensure consistency between data copies, the master-slave mode is read and write separated between the two libraries.

First, redis let the master database can be read to write, but in the library can only read can’t write, the reason is that when the client for the same key data modification operations of many times, so every action to the different libraries, then it can lead to inconsistent data, redis, when reading may be read into the old value, Even if data is synchronized between libraries, the method of synchronization can be very complicated, and the implementation will affect the performance of Redis.

How does redis synchronize data between master and slave libraries? First of all, when we start multiple instances of Redis, they can form the relationship between the master library and the slave library through relicaof command, and then the slave library will tell the master library to start full synchronization, that is, the master library will synchronize all its data, generate RDB snapshot, and then the slave library will load the RDB file. Generate data in memory. During this full synchronization, the master library is still running, so it puts the write commands it receives into its own memory area, the Replication Buffer, and when the full synchronization is complete, the master informs the slave library of the commands in the Replication buffer for incremental synchronization. Subsequent write commands to access the main library do the same.

And our redis in order to alleviate the main library at the same time synchronization under pressure from several from the library, is also equipped with master-slave – from pattern, also said that when a master database synchronization to the one from the library, the library from the data synchronization to another from the library, so that to avoid the main library at the same time synchronization under pressure from a few from the library, which has brought the redis performance improvement.

However, it is also important to note that when our master and slave are fully synchronized, a long connection will be maintained between the master and slave for incremental synchronization. However, if the link is broken due to network problems, then some changes to the master database are definitely not synchronized to the master database.

Redis’s solution is to place the write commands after the link is broken into a repl_backlog_buffer buffer, which the master will synchronize to the slave when the link is restored. Note, however, that repl_Backlog_buffer is a circular buffer, and when the link is down for so long that the buffer is overwritten, full synchronization between the master and slave will occur when the link is reconnected.

Can you briefly describe the cache flushing mechanism of Redis?

Redis provides us with three cache flushing mechanisms,

The first type is that when redis is full, there is access to the time, Redis will directly report an error, can no longer operate.

The second type is related to expiration time, including volatile- lRU, volatile- lFU, etc. The premise of these policies is to delete the key value pairs with expiration time.

The third type is to select data to delete on the basis of all data, such as allkey-LRU, Allkey-LFU and other strategies we often use.

In general, the policy we use is the allkey-LRU policy of the third type, which is to delete the least recently used policy.

So how does this strategy work? Redis maintains a linked list at the bottom. The head of the list is the most recently used data, and the tail is the most recently used data. When a data item is newly used in the list, Redis moves that data item to the head, and all other data items are moved one position back.

However, there is a problem with this implementation. When there are a large number of RedIs, because you need to use linked lists to manage all the cached data, and when data is accessed, you need to move the data. If the redis access is very frequent, then there will be a large performance loss.

Therefore, Redis optimized the implementation scheme of Allkey-LRU. Redis will record its own recent access time in each piece of data, and then when Redis decides to eliminate data, it will randomly select N pieces of data for the first time. This amount of data is configured by ourselves, and Redis provides configuration items. Redis will compare the N data times and remove the smallest data from the cache.

The next time there is a need to cull data, Redis will re-select N data, but note that the current N data must be shorter than the minimum time in the previous collection, that is, to select earlier unused data for cache culling.

How to maintain data consistency between Redis and mysql?

Generally speaking, we double write redis and database to maintain the consistency of our data. When our data is modified, we delete the cache in Redis first, and then modify it in mysql. When a subsequent request comes, we will visit Redis and find no data, and then go to mysql to read the data. And then cache to Redis, so as to maintain the consistency of the data, but this data consistency, must be controlled through transactions, double write redis and mysql, either succeed or fail.

However, since we are using Redis at the business level and we haven’t implemented distributed transactions yet for technical reasons, this solution is not suitable for us.

Therefore, our solution is a retry mechanism. How does this retry mechanism work? First, we write some redis operation request, temporary to the message queue, when the application is not successful to delete cache or modify the cache, or say, modify, or delete mysql so we will throw an exception, trigger retry mechanism of mq, again, when try again a few times was not successful, then we would trigger nailing news, Notify our developers to check to see where the problem occurred. When we are successful, we remove the operation from MQ to ensure that we do not repeat the operation.

However, this scheme still brings some data inconsistency problems. If we delete the cache first and then delete the database, then thread A comes in and deletes the cache, but due to network reasons, we haven’t had time to delete the database. When thread B reads data, it finds that Redis has no data, so it reads data from the database. As a result, thread B reads the old data and writes the old data to Redis. As a result, when the subsequent thread reads data, it reads the old data in Redis. Even our mysql has removed this old data.

Our solution is that when thread A deletes the cache, it deletes the database, then it sleeps for A short time, and then deletes the cache again.

This is our solution for data inconsistencies between Redis and mysql.

What do I mean by cache penetration, cache breakdown and cache avalanche?

Cache avalanche, a cache avalanche is when a large number of requests are processed in Redis and redis cannot handle them, so the requests are processed in mysql, resulting in a surge of database pressure and even database downtime. Cache avalanche in general because redis key expired at the same time, this kind of problems, the solution is the key of the expiration date of the set, can meet their business needs, on the expiration date of plus a small random time, meet the demand, already so will not appear again at the same time, a large number of key expired. But cache avalanche also has a potential that redis instance to hang out, the solution is in the business system implementation services fuse, the plan we can implement in our system package redis, when redis is down, we request return directly, no longer to access the database, or because the fuse this kind of situation, It will have a great impact on our business system, so we can carry out traffic limiting in the platform service layer of accessing database, and only 1000 of 10,000 requests will enter our service.

Cache breakdown refers to the sudden expiration of hotspot data that has been accessed by a large number of requests. As a result, all requests to access the hotspot data are accessed by the database at the same time, causing great pressure on the database. The solution is not to set an expiration date for these hot data.

Cache penetration means that the data accessed is neither Redis nor mysql, so if a large number of requests come in, it will put a lot of pressure on both Redis and mysql. Generally, there are two reasons for cache penetration. One is that data is mistakenly deleted by the service layer, and the other is malicious attacks from outside. The general solution is that if there is an access redis median value that does not exist, then we can cache a null value in Redis and return it to the front end. Or we can use the Bloom filter. When we visit Redis and find no value, we will query the Bloom filter to determine whether the data exists, and then we will access the database. At present, the best way, or in the front entrance there for data verification, if unreasonable request we directly back, this is the best performance.