Redis is something we’ve all heard of. We use it as a cache in our work and study. Since it’s a cache, our first reaction must be: this guy is fast!

It’s actually fast:), but Redis is single-threaded at the bottom! Some students may have a question, why single-threaded Redis is able to fly fast?

Don’t worry, I will try to use plain language to give you say ~~

Redis is single-threaded, which means that the network IO and read and write of Redis are performed by one thread, but other functions of Redis, such as persistence, asynchronous deletion, cluster data synchronization, etc., are actually performed by additional threads. That’s not the point of this article, just get the impression.

Why does Redis use single threads?

Overhead of multithreading

In general, if you don’t have good system design after multithreading, this is what you see on the left (note the ordinate). As the number of threads increases, throughput increases, and as the number of threads increases further, throughput slows down or even drops.

The key bottleneck is that there are often shared resources that can be accessed by multiple threads at the same time in the system. In order to ensure the correctness of shared resources, additional mechanisms are needed to ensure thread safety, such as locking, which brings additional overhead.

For example, take the most commonly used List type as an example. Suppose that Redis adopts multi-threading design, and there are two threads A and B to perform LPUSH and LPUSH operations on the List respectively. In order to ensure the same result every time, that is, [thread B takes out the data put in by thread A], these two processes need to be executed in serial. This is the problem of concurrent access control of shared resources in multithreaded programming.

Concurrent access control is always a difficult problem in multi-thread development: if a mutex is simply used, it will appear that even if more threads are added, most threads are still waiting to acquire the mutex, and the parallel becomes serial, and the system throughput does not increase with the increase of threads.

The addition of concurrent access control also reduces the readability and maintainability of system code, so Redis simply adopts single-threaded mode.

Why is Redis so fast with single threads?

The use of single threads is the result of a variety of considerations by Redis designers.

  • Redis does most of its operations in memory
  • Efficient data structures such as hash tables and hop tables are used
  • Multiplexing mechanism is adopted to enable it to process a large number of client requests concurrently in network IO operations and achieve high throughput

Since Redis uses a single thread for IO and cannot multiplex if the thread is blocked, it is not surprising that Redis has also designed for potential choke points for network and IO operations.

Potential choke points for network and IO operations

In network communication, in order to process a Get request, the server needs to listen to the client request (bind/listen), establish a connection with the client (accept), read the request from the socket (RECV), parse the client to send the request (parse), and finally send the result (send) to the client.

The most basic single-threaded implementation is to perform the above operations sequentially.

The Accept and RECV operations highlighted in red above are potential choke points:

When Redis listens for a connection but fails to establish a connection, the accept() function blocks, and other clients cannot establish a connection with Redis

When Redis reads data from a client via recv(), it also blocks if the data never arrives

High performance IO model based on multiplexing

To address blocking in IO, Redis uses Linux’s IO multiplexing mechanism, which allows multiple listening and connected sockets (SELECT /epoll) to exist simultaneously in the kernel.

The kernel always listens for connections or data requests on these sockets. As soon as a request arrives, it is handed over to Redis for processing, which implements the effect of one Redis thread handling multiple IO streams.

At this point, the Redis thread does not block on a particular client request processing, so it can connect to multiple clients at the same time and process requests.

Callback mechanism

Once the SELECT /epoll thread detects the arrival of a request on the FD, it triggers the corresponding event to be put into a queue, which is continuously processed by the Redis thread, so the event-based callback is implemented.

For example, Redis registers Accept and GET callbacks for Accept and Read events. When the Linux kernel listens for a connection request or Read request, the Accept and Read events are triggered, and the kernel calls back the corresponding Accept and GET functions of Redis for processing.

Redis performance bottlenecks

Through the above analysis, although the multiplexing mechanism can listen to requests from multiple clients at the same time, Redis still has some performance bottlenecks, which is also the situation we need to avoid in normal programming.

  1. The long-running

If a request takes a long time in Redis, the performance of the entire server will be affected. All subsequent requests are processed by themselves until the previous time-consuming request is completed.

This is something we need to avoid when designing our business scenarios; Redis’s lazy-free mechanism also places time-consuming memory freeing operations on asynchronous threads.

  1. High concurrency scenario

When the number of concurrent requests is very large, the performance of reading and writing I/O data from a single thread client suffers a performance bottleneck. Although I/O multiplexing is adopted, only a single thread can read and write data from the client in sequence, and the multiple CPU cores cannot be utilized.

Redis in 6.0 can use CPU multi-core multi-thread read and write client data, but only for the client’s read and write is parallel, the real operation of each command is single thread.

Other interesting redis-related questions

Take this opportunity to ask some interesting questions about Redis.

  1. Why Redis? Is it bad to access memory directly?

In fact, there is no clear definition of this clause. For some data that does not change frequently, it can be directly put into memory, not necessarily put into Redis, but put into memory. Consistency issues: If a data is modified, it may only be modified on one server if the data is in local memory. If we use Redis inside, we can access Redis server, can solve the consistency problem.

  1. How to store too much data? Let’s say I want to cache 100 gigabytes of data, what do I do?

Tair is an open source distributed KV cache system of Taobao. It inherits rich operations from Redis. Theoretically, the total amount of data is unlimited, and it has been upgraded for availability, scalability and reliability

Recommend more courses:

Java Basics: Java300 set course -Java essential quality tutorial _ Hand by hand graphic learning Java, make learning to be a pleasure _

Python Basics: Getting started with Python! Crash Course Python for beginners! Two months can be the kind of post!

Java Management System Project Collection: a collection of projects that can be written on the resume, the latest version of the 2022 Java initial practice project collection

Java Game Project: [Java Project] Develop a full set of king of Glory tutorials and materials, make King of Glory in Java in less than 2 hours

Front End Foundation: Super dry! A week to build a Xiaomi mall! Web front-end zero basic entry HTML5+ CSS3, learn to build a website to see this is enough!