41 Lesson 3540 Post Lecture Thinking Problems, Answers, and Common Questions

41 Lesson 3540 Post-lecture Thinking Problems, Answers, and Common Questions #

Today is our final Q&A session, and I will analyze the questions posed in the exercises after lectures 35-40 together with you. Additionally, I will address two typical issues: the usage of atomic operations and a comparison between Redis and other key-value databases.

Lecture 35 #

Question: Assuming that 80% of the key-value pairs stored in the Codis cluster are of the Hash type, with each hash set containing between 100,000 to 200,000 elements, and each set element being 2KB in size. Do you think migrating such hash set data would affect the performance of Codis?

Answer: Actually, the impact is not significant. Although the total data size of a hash set is between 200MB to 400MB (2KB * 0.1M ≈ 200MB to 2KB * 0.2M ≈ 400MB), Codis supports asynchronous and batch migration of data. Therefore, Codis can migrate the elements in the set in multiple batches, with each batch containing a small amount of data. As a result, it won’t have a significant impact on the source instance.

Lecture 36 #

Question: Suppose the inventory of a product is 800. We use a slice cluster with 4 instances to serve spike requests. Each instance maintains an inventory of 200. We distribute spike requests from clients to different instances for processing. Do you think this is a good method?

Answer: Whether this method can achieve good results mainly depends on whether the client requests can be evenly distributed to each instance. If so, each instance can help share some of the workload and avoid overwhelming a single instance.

When storing product inventory, the key is generally the product ID. Therefore, in a spike scenario, when the client queries the inventory of the same product, it will request the same key from the cluster. The cluster needs to evenly distribute the client’s requests for the same key to multiple instances.

To solve this problem, there needs to be a proxy layer between the client and the instance to handle request forwarding. For example, in Codis, the codis proxy is responsible for request forwarding. If we configure the codis proxy to distribute requests to different instances in a round-robin manner (we can modify Codis to add forwarding rules), we can utilize multiple instances to share the request load.

If there is no proxy layer, the client will send the request directly to the unique instance that stores the key based on the mapping relationship between the key and the slot, as well as the slot and the instance. In this case, the request load cannot be shared by multiple instances. The method described in the question will not achieve good results.

Lecture 37 #

Question: When there is data access skew, what problems will occur if the hot data in Redis suddenly expires, assuming that the data in Redis is cached and the final value of the data is stored in the backend database?

Answer: In this case, cache breakdown will occur, which means that the hot data suddenly becomes invalid, resulting in a large number of access requests being sent to the database, thereby putting immense pressure on the database.

We can use the method introduced in [Lecture 26] to not set an expiration time for the hot data, which can avoid the breakdown caused by expiration.

In addition, it is best to add flow control mechanism at the database access layer. Once a large flow of requests is detected accessing the database, throttling should be immediately activated. This is also done to prevent the database from being overwhelmed by heavy traffic pressure. Because once the database goes down, it will have a serious impact on the entire business application. Therefore, we would rather reject the request directly when it is about to access the database.

Lecture 38 #

Question: If we use a method similar to Codis to save Slot allocation information and cluster instance status information in a third-party storage system (such as Zookeeper), what impact will this method have on the scale of the cluster?

Answer: Assuming we use Zookeeper as the third-party storage system to save cluster instance status information and Slot allocation information, then the instances only need to communicate with Zookeeper to exchange information, and they do not need to send a large number of heartbeat messages to synchronize the cluster status with each other. This approach reduces the network communication volume used by instances for heartbeat and helps achieve large-scale clusters. Moreover, the network bandwidth can be concentrated on serving client requests.

However, in this case, when instances need to obtain or update the cluster status information, they must interact with Zookeeper. This will increase Zookeeper’s network communication bandwidth requirements. Therefore, when using this method, it is necessary to ensure a certain level of network bandwidth for Zookeeper to avoid its communication with instances being hindered by limited bandwidth.

Lecture 39 #

Question: What new features of Redis 6.0 do you think will be helpful to you?

Answer: This depends on your specific needs. From the perspective of performance improvement, the multiple I/O threads feature in Redis 6.0 can alleviate the network request processing pressure. By increasing the capacity to handle network requests through multiple threads, the overall performance of the instance can be further improved. It has been evaluated by the industry that compared to the single-threaded Redis before version 6.0, the multi-threaded performance of version 6.0 has indeed improved. Therefore, this feature will be quite helpful for business applications.

In addition, the granular ACL (Access Control List) control mechanism based on users is also very useful. When Redis provides services externally in a cloud-based manner, it will face scenarios with multiple tenants (such as multiple users or multiple microservices). With the new ACL feature, we can safely support shared access to Redis services for multiple tenants.

Lecture 40 #

Question: Do we still need a Redis master-slave cluster after the introduction of persistent memory?

Answer: Although persistent memory can quickly recover data, in addition to providing master-slave failover, a master-slave cluster can also achieve read-write separation. Therefore, we can improve the read performance of Redis by adding multiple slave instances to share a large number of read requests. This cannot be provided by persistent memory alone. Therefore, if the business layer has high requirements for read performance, we still need a master-slave cluster.

Frequently Asked Questions #

Alright, let’s wrap up the discussion on the thought question. Next, I’ll address some questions I’ve received recently and talk to you about the differences caused by local variables and globally shared variables in atomic operation development, as well as a comparison of the advantages and disadvantages of Redis and two other common key-value databases, Memcached and RocksDB.

Questions about the use of atomic operations #

In Lesson 29, when I was introducing atomic operations, I mentioned an example of multi-threaded rate limiting to explain how to use atomic operations. Let’s review the code of this example again:

// Get the access count for the IP
current = GET(ip)
// If the access count exceeds 20, throw an error
IF current != NULL AND current > 20 THEN
    ERROR "exceed 20 accesses per second"
ELSE
    // If the access count is less than 20, increment the count by 1
    value = INCR(ip)
    // If it's the first access, set the expiration time of the key-value pair to 60s later
    IF value == 1 THEN
        EXPIRE(ip, 60)
    END
    // Do other operations
    DO THINGS
END

When analyzing this example, I mentioned: “When the first thread executes INCR(ip), the second thread also executes INCR(ip) immediately afterwards. At this point, the access count of the IP is increased to 2, and we can no longer set the expiration time for this IP.”

Some students think that since value is a local variable in the thread, when the two threads execute it, each thread will independently check whether value is equal to 1. After checking the value, they can set the expiration time of the IP. Because Redis itself guarantees atomicity when executing INCR, the client threads can achieve atomicity guarantee by using local variables to obtain the access count of the IP and perform the check.

Let me further explain the reason for using Lua scripts to ensure atomicity in this example.

In this example, value is actually a globally shared variable among multiple threads. Therefore, when multiple threads access this variable, a situation may occur: one thread executes INCR(ip), the second thread also executes INCR(ip) while the first thread continues to execute, causing the access count of the IP to become 2. And the condition to set the expiration time is when the access count of the IP equals 1, which means we cannot set the expiration time. In this case, we need to use Lua scripts to ensure the atomicity of the count increment and count check operations.

Comparison of Redis with Memcached and RocksDB #

Memcached and RocksDB are typical in-memory key-value databases and disk-based key-value databases, respectively, and they are widely used. How do they compare to Redis in terms of advantages and disadvantages? Can they replace Redis? Let’s discuss this question.

Comparison of Redis and Memcached #

Like Redis, Memcached is often used as a cache. However, Memcached has a distinct advantage, which is that its cluster scale can be very large. The Memcached cluster does not use slot mapping like Redis Cluster or Codis to allocate the corresponding data and instances. Instead, it uses consistent hashing to distribute the data across multiple instances, and the advantage of consistent hashing is that it can support large-scale clusters. Therefore, if we need to deploy a large-scale cache cluster, Memcached is a good choice.

However, when using Memcached, there is something to note: Memcached supports fewer data types than Redis. Memcached only supports key-value pairs of type String, while Redis can support multiple data types including String. If your business application needs to store rich data types, the advantage of using Memcached as a replacement is lost.

If you need to store multiple data types and want to save a large amount of data with a certain cluster scale, Redis is still a good solution.

I have summarized the comparison between Redis and Memcached in a table for you to see.

Features Redis Memcached
Cluster scale Moderate Large
Data types Multiple data types, including String Only String
Persistence Yes No

Comparison of Redis and RocksDB #

Unlike Redis, RocksDB can directly store data on the disk. As a result, a single RocksDB can store a much larger amount of data than Redis, and all the data can be persisted.

Furthermore, RocksDB can support table structures (i.e., column families), whereas Redis’ basic data model is key-value pairs. So, if you need a large-capacity persistent key-value database and want to store data according to a certain table structure, RocksDB is a good alternative.

However, it’s worth noting that RocksDB needs to write data to the underlying disk, and when querying data, if the data RocksDB needs to read is not cached in memory, RocksDB has to search in the disk files, which will slow down the read/write latency of RocksDB and reduce its bandwidth.

In terms of performance, RocksDB is not on par with Redis. Moreover, RocksDB is just a dynamic link library and does not provide client-server access mode, as well as master-slave and sharding cluster functions like Redis does. Therefore, when replacing Redis with RocksDB, we need to consider the feasibility of replacement based on specific business requirements.

I have summarized the comparison between Redis and RocksDB in the following table:

Features Redis RocksDB
Storage medium In-memory Disk-based
Data capacity Relatively small Relatively large
Data types Multiple data types, focus on key-value pairs Key-value pairs, supports table structures
Performance High Lower than Redis
Cluster support Yes No

Summary #

Cluster is an important requirement in practical business applications. At the end of the course, I would like to give you another suggestion.

Cluster deployment and operation involve a lot of work, so we must pay attention to the selection of cluster solutions.

The scalability of the cluster is an important dimension for evaluating cluster solutions. You must pay attention to whether the metadata in the cluster is maintained through a slot mapping table or consistent hashing. If it is a slot mapping table, you also need to consider whether it is stored in a centralized third-party storage system or spread and stored by each instance. Redis Cluster, Codis, and Memcached adopt different approaches.

  • Redis Cluster: Uses a slot mapping table and is spread and stored by each instance.
  • Codis: Uses a slot mapping table and is stored in a third-party storage system.
  • Memcached: Uses consistent hashing.

In terms of scalability, Memcached is better than Codis, and Codis is better than Redis Cluster. Therefore, if the actual business requires a large-scale cluster, I recommend that you prioritize Codis or a Redis shard cluster solution based on consistent hashing.