Redis features
Why is Redis fast
- Single thread, avoiding thread switching and resource contention
- Non-blocking IO, using ePoll as a technical implementation of IO multiplexing, processing client requests without blocking the main thread
- Pure memory access
Redis threading model
Redis uses a file event handler internally, which is a single-threaded model. It uses IO multiplexing mechanism to listen on multiple sockets. Select the event handler according to the event on the socket. The file event handler structure includes
- Multiple Socket
- IO multiplexing procedures
- File event dispatcher
- Event handlers (connection reply handler, command request handler, command reply handler) Multiple Sockers may concurrently generate different operations, each corresponding to a different file event. But the IO multiplexer listens for multiple sockets, queues messages generated by the Socket, and the event dispatcher takes the event out of the queue one at a time and hands it to the corresponding event handler for processing
Optimizing network latency
Redis performance bottlenecks may be network optimizations:
- In single-machine deployment, Unix interprocess communication is used instead of TCP
- Multi-key to reduce the number of requests. Such as using the mget
- Merge requests and responses using Transaction, Script
- Use pipeline to merge response
Compared with Memcache
Memcache characteristics
- Multi-thread asynchronous IO, can make full use of the CPU multi-core advantage
- Simple function, use memory to store data
- Cache expiration time can be set, and data expiration will be lazy deletion. After the memory limit is exceeded, the expired key will be cleared, and the LRU policy will be used to remove the data. Disadvantages:
- The key cannot exceed 250 bytes and the value cannot exceed 1 MB. The maximum validity period of the key is 30 days. The key supports only the K-V structure and does not provide the persistence and primary/secondary synchronization functions
Compared with Redis
- Redis uses single-threaded mode for processing
- Redis has rich data structures
- Redis supports persistence and can be used not only as a cache but also as a NOSQL database
- Redis provides a master/slave synchronization mechanism, cluster deployment capability, and high availability services
Redis advanced usage
Publish and subscribe
Can be used as a message queue, in the case of a consumer offline, the production of messages will be lost. Data backtracking is not possible
The transaction
Redis provides transactions that guarantee only serial execution of commands and complete execution. However, if the command fails to be executed, it is not rolled back. Atomicity is not guaranteed
The data structure
Redis internally uses a redisObject to represent all keys and values
String
In Redis, String is called Dynamic String (detect SDS Simple Dynamic String). Its internal data structure is similar to ArrayList, which maintains a byte array and allocates certain space internally to reduce frequent memory allocation.
Memory allocation mechanism:
- If the string length is less than 1 MB, the existing space is doubled each time
- If the character string is larger than 1 mbit/s, 1MB space is expanded each time. The maximum length of the character string is 512 mbit/s
The internal encoding
- Int: a long integer of 8 bytes
- Embstr: the value is a string of 39 bytes or less
- Raw: The string contains more than 39 bytes
Data structure:
struct SDS{ T capacity; // Array size T len; // Actual length byte flages; Byte [] content; // Array contents}Copy the code
Capacity and len are both generic, so why not just int? In order to make more reasonable use of memory, Redis uses different data types for strings of different lengths, and len will be the same size as capacity when creating strings, so there is no redundant space. So a String value can be a String, a number (integer, floating point), or binary.
Application scenarios
- The cache
- Count The number of access statistics
- Sharing session
Common commands
set[key] [value] Sets the value of the specified key (setDel [key] Deletes a specified key exists [key] Determines whether a specified key exists. Mset [key1] [value1] [key2] [value2]...... Mget [key1] [key2]...... Expire [key] [time] Sets the expiration time for the specified key in seconds. Setex [key] [time] [value] Is equivalent toset+ expire command combination setnx [key] [value] if the key does not existsetIf the value is an integer, 0 is returned. Incr [key] The incr command increments 1 each time. Incrby [key] [number] The incrby command increments the integer numberCopy the code
List
The List in Redis is very similar to the LinkedList in Java. The underlying structure is LinkedList, and the insertion and deletion operations are very fast and the time complexity is O(1). When the amount of data is small, the underlying structure is a piece of continuous accumulation, called ziplist(compressed list), which says that all elements are stored next to each other, allocating a contiguous piece of memory. It becomes quickList when there is a lot of data. Simple linked lists require a lot of memory to maintain prev and next Pointers. The ziplist+ linked list hybrid structure is adopted after Redis3.2. Referred to as quicklist
The internal encoding
- Ziplist, reduce memory usage when the number of list elements is less than list-max-ziplist-entries(default: 512) and each element in the list is less than list-max-ziplist-value(default: 64)
- Linkedlist: Redis uses linkedList as an internal implementation of a list when the list type does not meet ziplist conditions
Application scenarios
- Message queuing: Queue functionality via LPOP and RPUSH (or RPOP and LPUSH)
- List, paging data shows the lpush and lrange commands to implement the latest list function.
Common commands
rpush [key] [value1] [value2] ...... Insert rPOP [key] to the right of the list to remove the right of the list header element, and return the element lPOP [key] to remove the left of the list header element, Llen [key] Returns the number of elements in the list. Lrem [key] [count] [value] Deletes the elements equal to value in the list. Count is the number of deleted elements. If count<0, delete the same elements from the right. If count=0, delete all the same elements. Index indicates the index of the element. Index can be negative. Index = indicates the penultimate element, and index=-2 indicates the penultimate element. Lindex [key] [index] retrieves the element with the specified index in list. Time complexity: O(n)) lrange [key] [start_index] [end_index] Obtain all elements in the list (time complexity: O(n)) Ltrim [key] [start_index] [end_index] Retain elements within the interval and delete other elements (time complexity is O (n))Copy the code
Hash
A Hash in Redis is similar to a Java HashMap in that it uses an array + list structure to append elements to the list when a Hash collision occurs. But the Redis Hash can only be a String. Both Hash and String can store user data. But Hash can be stored separately for each field of user information; String stores a serialized String. From the perspective of modification, you can modify the network bandwidth based on a field using hash storage. But Hash has a larger memory footprint than String
The internal encoding
- Ziplist (ziplist), the internal implementation of Hash when the Hash element is less than hash-max-ziplist-entries (default: 512) and all values are less than hash-max-ziplist-value(default: 64). Ziplist uses a more compact data structure to store multiple elements consecutively, saving more memory than HashTable
- Hashtable (hashtable) : when the hash type cannot meet the ziplist condition, hashable is used as the internal implementation of the hash because the ziplist read/write efficiency is reduced and the hashtable read/write complexity is O(1).
Application scenarios
- Shopping cart: hset [key] [field] [value] command, you can realize the user Id, product Id as field, product quantity as value, exactly constitute the three elements of the shopping cart.
- Storing objects: Hash (key, field, value) has a structure similar to that of an object (object ID, attribute, value) and can also be used to store objects.
Common commands
Hset [key] [field] [value] New field information hget [key] [field] Obtain field information hdel [key] [field] Delete field hlen [key] Number of fields saved hgetall [key] Hmset [key] [field1] [value1] [field2] [value2]...... obtain all the fields and values in the specified key dictionary Batch creation Hincr [key] [field] Pair Value increment Hincrby [key] [field] [number] Number increment of field valueCopy the code
Set
Set in Redis is similar to HashSet in that the internal key-value pairs are unordered and unique. Its internal implementation is equivalent to a special dictionary in which all vlaues are null. When the last element of the collection is removed, the data structure is automatically deleted and the memory is reclaimed.
The internal encoding
- Intset (integer set),Redis uses intset as the internal implementation of the set when all elements are integers and the number of elements is less than the set-max-intset-entries configuration (512 by default) to reduce memory usage.
- Hashtable. Redsi uses hashtable as an internal implementation of the collection when the collection cannot satisfy intSet
Application scenarios
- Friend set
- Random presentation. It is recommended that merchants select several randomly from SrandMember
- To restore function
Common commands
Sadd [key] [value] Specifies the keysetSismember [key] [value] Scard [key] Get the length of the set spop [key] popup an element Srem [key] [value] Deletes the specified elementCopy the code
Zset ordered set
Zset ensures the uniqueness of internal values. In addition, score can be assigned to each value, representing the weight of the value. The internal implementation uses a data structure called a skip list.
The internal encoding
- Ziplist: If the number of ordered list elements is smaller than zset-max-ziplist-entries(default: 128) and each element value is smaller than zset-max-ziplist-value(default: 64), use ziplist to reduce memory
- Skiplist (skiplist), ordered collections use skiplist as an internal implementation when ziplist conditions are insufficient, because ziplist reads and writes become less efficient
Application scenarios
- Leaderboards, Zset can dynamically rank against data
- A weighted queue
Common commands
Zadd [key] [score] [value] add element to set with specified key zrange [key] [start_index] [end_index] Zrevrange [key] [start_index] [end_index] Zrank [key] [value] Get the rank of the elements in the set zrangebyScore [key] [score1] [score2] Zrem [key] [value] Delete element zscore [key] [value] Obtain element scoreCopy the code
Advanced usage
BITMAP
Store information by bit and record active users
HyperLogLog
The use of minimal memory space to complete the statistics of data deduplication. Such as UV
Geospatial
Save the location and calculate the distance
persistence
RDB
RDB persistence is the process of saving a snapshot of the current process data to disk. RDB persistence can be triggered manually (bgsave command).
RDB configuration
- Save: The RDB file is saved in the specified dir configuration directory. The filename can be configured using dbfilename.
- Compression: Redis uses the LZF algorithm to compress the generated RDB files by default. The compressed files are far smaller than the memory size, which is enabled by default
- Automatic trigger configuration
Save 900 1 Save 300 10 Save 60 10000 900 seconds If more than one key is changed, the snapshot is saved. If more than 10 keys are modified within 300 seconds, a snapshot is initiated and saved. If 10,000 keys are changed within one minute, snapshots are initiated for saving.Copy the code
Bgsave process description
- By executing the bgsave command, the Redis parent thread determines if there are other executing children (such as RDB/AOF children).
- Parent thread fork child process. The parent thread blocks during the fork operation
- After the fork completes, bgSave returns the “background Saving Started” message and no longer blocks the parent process
- The child process creates an RDB file, generates a temporary snapshot file from the parent thread’s memory, and then atomic replaces the original file
- The child sends a signal to the parent indicating completion, and the parent updates the statistics
The advantages and disadvantages
advantages
- RDB uses a tightly compressed binary file that represents a snapshot of Redis data at one point in time, making it ideal for scenarios such as backup and full replication
- Redis loads RDB recovery data far more than AOF method shortcomings
- There is no way to do real-time persistence/second persistence. The bgsave command forks a child process every time it is run. This is a heavyweight operation that is expensive to execute frequently
- In binary format, the old redis service is not compatible with the new RDB format
AOF
AOF(Append only file) persistence; Each write command is recorded in an independent log, and the AOF command file is flushed after the restart to recover data.
AOF configuration
appendfsync yes This function is disabled by default
appendfsync always The AOF file is written every time a data change occurs.
appendfsync everysec This policy is the default policy of AOF.
Copy the code
AOF usage process
- All write commands are appended to the aOF_buf (buffer)
- The AOF buffer is synchronized to the hard disk according to the corresponding policy
- As AOF files grow larger, they need to be rewritten periodically
- When the Redis server restarts, you can pretend to be an AOF file for data recovery
The advantages and disadvantages
It can save real-time data, store large data files, and the speed is slower than RDB
thinking
- Why does AOF use file protocol format? File protocols have good compatibility. After AOF is enabled, all write commands include apend operations, and the protocol format is directly adopted, avoiding the overhead of secondary processing. File protocols are feasible and convenient for direct modification and processing
- Redis uses single-threaded response commands. If you append to disk every time you write AOF, the performance is entirely dependent on the load on the disk. Multiple buffer synchronization strategies for disk balancing performance and security.
Copy On Write
To execute the BGSAVE or BGREWRITEAOF command, Redis creates a child of the current server process. Most operating systems use copy-on-write to optimize the use of the child process, so the server raises the threshold of the load factor while the child process exists. In this way, hash table expansion operations can be avoided during the existence of the child process, and unnecessary memory writing operations can be avoided to maximize memory saving.
Technical Implementation Principle
After fork(), the kernel sets the permissions of all memory pages in the parent process to read-only, and the child’s address space points to the parent process. When both parent and child processes read only memory, nothing happens. When one of these processes writes to memory, the CPU hardware detects that the memory page is read-only and triggers a page-fault, falling into one of the kernel’s interrupt routines. In the interrupt routine, the kernel makes a copy of the page that triggered the exception, so that the parent process keeps a separate copy.
advantages
- COW technology can reduce the instant delay when allocating and copying a large number of resources.
- COW technology can reduce unnecessary resource allocation. For example, when forking, not all pages need to be copied, and the parent’s code segments and read-only data segments are not allowed to change, so there is no need to copy.
disadvantages
If both parent and child processes need to continue writing after fork(), the result will be a lot of paging errors (page exceptions break page-fault), which is not worth the cost.
conclusion
- Fork The child process shares the parent process’s physical space. When the parent process writes to memory, read-only the page is interrupted and a copy of the page is made (the rest of the page is shared).
- Fork the child process implements the same functionality as the parent process. If necessary, we use exec() to replace the current process image with a new process file to do what we want.
COW in Redis
- If redis persists using BGSAVE or BGREWRITEAOF, then Redis forks a child process to read the data and write it to disk.
- In general, Redis still does a lot of reads. If a lot of writes occur during the life of the child process, there may be a lot of paging errors (page exceptions interrupt page-faults), which can cost performance in replication.
- In the Rehash phase, writes are unavoidable. Therefore, after forking out the child process, Redis increases the load factor threshold to minimize write operations, avoid unnecessary memory write operations, and save memory to the maximum extent.
High availability
copy
Replication process
Slave node slaveof Master node
- The slave node holds the master node message
- The slave node establishes the socket, and the master node establishes the connection
- The secondary node sends the ping command to the primary node
- Permission to verify
- Synchronize data sets. The master node sends all the data sets it has to the slave node. After Redis2.8, the new replication command psync is used for synchronization. To ensure compatibility between new and old versions, Sync remains
- Continuous command replication
Data synchronization
- The primary and secondary nodes participating in replication maintain their respective offsets
- When the master writes a command, it not only sends the command to the slave node, but also writes the command to the replication backlog buffer (first-in, first-out queue, saving the latest replicated data). The user partially replicates the data or the replication command fails to recover the data
- A redis node is assigned a string as its permit ID when it is started, and the ID will change upon restart
psync
Run the psync command from the node to complete partial and full replication. Psync {runId} offset
- Full replication 2. Receive the response data from the primary node and save the run ID and offset offset 5. The primary node sends the RDB file to the secondary node, and the secondary node receives the RDB file and saves it locally as data of the secondary node. 6. The slave node receives data from the RDB from the snapshot until the slave node receives data. During this period, write data is put into the client buffer (64 MB by default). 7. Clear old data from the node
- Partial replication Partial replication is used to solve the problem of intermittent network disconnection or command loss. The secondary node requests the primary node to send the lost command data. If the primary node has some data in the replication buffer, it sends the data to the secondary node directly
The sentry
Redis Sentinel automates fault discovery and failover and notifies applications for true high availability.
- Monitoring: Regularly check whether Redis data nodes and other Sentinel nodes are reachable
- Notification: The Sentinel node notifies the application of the result of the failover
- Failover of the primary node: To promote the secondary node to the primary node and maintain the correct relationship between the primary and secondary nodes
- Configuration provider: In the Redis Sentinel architecture, the client connects to a Sentinel node collection during initialization to obtain master node information
- The Sentinel node set is composed of several Sentinel nodes, so the whole Sentinel node is still robust even if some Sentinel nodes are not available
- The fault judgment of nodes is accomplished by several Sentinel nodes, which can prevent misjudgment
- The Sentinel node itself is a separate Redis node that does not store data and only supports partial commands
Election Process (Raft algorithm)
- Every Sentinel node that is online is eligible to be a leader. When it confirms that the primary node is objectively offline (the number of master downlines exceeds quorum), it sends is-master-down-by-addr to other sentinels to request that it be set as a leader
- The other Sentinel nodes receive the command, and if they have not agreed to the command of the other Sentinel nodes, they will agree to the request, otherwise they will refuse
- If a node finds itself with a quorum greater than or equal to Max (Quorum, Num (Sentinels)/2+1), it becomes the leader
- If no leader is elected, the next election is held
failover
The elected Sentinel nodes are responsible for failover as follows:
- To select a node from the node list as the new master node, do as follows
- The Sentinel leader node executes the Slaveof no one command on the slave node selected by ① to make it the master node
- The Sentinel leader sends commands to the remaining slave nodes to become slave nodes of the new master
- The Sentinel node collection updates the original master node to a slave node, keeping an eye on it and ordering it to copy the new node when it replies
Deployment techniques
- Sentinel nodes should not be deployed on the same physical machine. Avoid hardware failures on a single machine
- At least three and an odd number of sentinels. The leader election requires at least half plus one node, and an odd number of nodes can save one node on the basis of satisfying this condition
- One Sentinel can be used or one Sentinel can be configured for each master node. One Sentinel is used if a collection of master nodes monitoring the same business, another is used otherwise
The cluster
Data distribution theory
1. Obtain the redundancy zone of the node.
Hash (key) %N to figure out which node is on. When nodes change, recalculation is required. You can double capacity expansion and migrate 50% of the data
2. Consistent hash partition
Arrange all storage nodes on the Hash ring, and each key will find the first storage node clockwise after computing the Hash. If a node is added or deleted, only the subsequent nodes clockwise next to the node on the Hash ring are affected.
Disadvantages:
- When adding or removing nodes, some data cannot be matched. Therefore, you need to manually process or ignore the data. So consistent hashing only works with cache scenarios
- When a small number of nodes are used, the nodes are not evenly distributed across the hash ring. The virtual node mechanism is introduced to compute multiple hashes for each service node and place one service node in each result location, which is called the virtual node. It makes the distribution more even
- When a small number of nodes are used, node changes will massively affect the data mapping in the hash ring and are not suitable for distributed schemes with a small number of data nodes
- Common consistency hashing requires doubling or reducing half of the number of nodes in order to balance the data load
Virtual slot algorithm
All data is mapped to a fixed set of integers defined as hash slots slot. Used to manage relationships between data and nodes. Slot = CRC16 (key) % 16383 advantages
- The relationship between data and nodes is decoupled, simplifying node expansion and contraction
- The node maintains slot mapping, and the client or proxy service does not need to maintain metadata of slot partitions
- Supports query of mappings between nodes, slots, and keys for data routing and online scaling
Cluster Function Restrictions
- The support for key batch operation is limited. Mset and mget can only be performed on keys in the same slot.
- Limited support for key transaction operations. Only multiple keys can be synchronized to a node
- As a minimum partition granularity, key cannot map large key-value objects, such as hash/list, to different nodes
- The cluster supports only DB0 operations
- The replication structure supports only one layer. The secondary node can replicate only the primary node. The nested tree replication structure is not supported
Memory management
Setting memory Online
Maxmemory limits the amount of memory actually used by Redis, that is, the memory corresponding to the usED_memory statistic item. Due to the existence of memory fragmentation rate, the actual consumption of memory may avoid the maxMemory setting larger.
purpose
- For buffering scenarios, when maxMemory is exceeded, a deletion strategy such as LUR is used to free up space
- Prevents the memory used from exceeding the server’s physical memory
Dynamically set the memory upper limit
config set maxmemory 6GB
Memory reclamation policy
Delete the expired key object
- Lazy delete: When a client reads a key with a timeout attribute, if the expiration time of the key has exceeded, the client executes the delete command and returns null
- Scheduled task deletion: Redis maintains a scheduled task internally, which runs for 10 seconds per second by default. The deletion logic in the scheduled task adopts an adaptive algorithm
Timed deletion adaptive algorithm (running in slow mode by default)
- The scheduled task randomly checks 20 keys in each database space and deletes the corresponding keys when they are found to be expired
- If a key that exceeds 25% of the number of checks expires, the loop executes the recycle logic until it is less than 25% or runs out of time, which is 25 milliseconds in slow mode
- If the recycle times out, Redis triggers the internal time to run the recycle key task again in fast mode. In fast mode, the timeout time is 1 millisecond and the task can only run once within 2 seconds (the internal delete logic in fast and slow modes is the same, but the timeout time is different).
Memory overflow control policy
- Volatile – lRU: Selects the least recently used expires data from a set with an expiration date (server.db[I].expires)
- Volatile – TTL: Selects expired data from a set (server.db[I].expires) to be discarded
- Volatile -random: Selects any data from a set with an expiration date (server.db[I].expires) to be discarded
- Allkeys-lru: removes allkeys- from the least recently used dataset (server.db[I].dict)
- Random: Selects any data from the dataset (server.db[I].dict) to flush out
- No-enviction (default) : rejects all write requests and responds only to read requests
Expiration keys in persistence
- RDB files are divided into two stages, the RDB file generation stage and the loading stage.
- When a key is persisted from a memory state to an RDB (file), an expiration check is performed on the key. Expired keys are not saved to a new RDB file, so expired keys in Redis do not affect the generation of a new RDB file.
- If Redis is running in primary mode, the RDB file will be checked when it is loaded. Expired keys will not be loaded into the database. So the expiration key does not affect the primary server that loads the RDB file;
- If Redis is running from the server, the RDB file is loaded into the database regardless of whether the key is out of date. However, during data synchronization between the primary and secondary servers, data on the secondary server will be cleared. So in general, the expiration key does not affect the slave server that loads the RDB file.
Cache avalanche, cache penetration, cache penetration, cache degradation and other issues
Cache avalanche
Cache avalanche is the problem of a cache set failing over a period of time. All queries fall on the database, causing great pressure on the DATABASE CPU and memory, or even database downtime. Solution:
- The cache time is increased by a random factor to disperse the cache expiration time
- The message queue ensures that no large number of threads will read or write data at one time
The cache to penetrate
Cache penetration refers to the fact that there is no data in the cache or database and the user queries the data twice each time. If someone maliciously attacks, the pressure on the database may overwhelm the database. Solution:
- Bloom filtering is used to store keys that are likely to be accessed. Bloom filtering is used to determine whether elements exist in sets with large amounts of data (must not exist or may exist).
- For data not available from the database, write to the cache. The cache time can be set appropriately short.
Cache hit through
Cache penetration refers to data that does not exist in the cache but exists in the database. Due to a large amount of concurrency, data is fetched from the database at the same time because there is no data in the cache, causing excessive pressure on the database. Solution:
- Hotspot data does not expire
- Set mutex to lock when fetch cache is empty and whether to lock after loading from database. If another thread acquires the lock, sleep for 50ms and try again. The lock here needs to consider Java and distributed locks in the package and cluster environment
Cache the drop
Cache degradation refers to the need to wrap a service to remain available when there is a sudden surge in traffic, service problems occur, or non-core business affects core business performance. The system can be degraded based on some key data to ensure the availability of the core business. For example, redis deletes non-critical cache data appropriately.
Refer to the article
Fu Lei, Zhang Yijun “Redis development and operation” Redis performance analysis Redis data structure and the corresponding use scenarios, see a whole understand the Redis interview overview, read this can and the interviewer war several rounds of MemCache COW COW! Copy On Write Redis Copy On Write