Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to handwrite Java Redis server

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

Editor to share with you how Java handwritten Redis server, I hope you will learn something after reading this article, let's discuss it together!

First, redis communication and Netty1,tcp

The client connected to the Redis server establishes a TCP connection to port 6379.

Although RESP is not technically specific to TCP, in the context of Redis, the protocol is only used for TCP connections (or similar stream-oriented connections, such as unix sockets).

Netty is used as the communication framework.

2, protocol

Redis client and server communicate using a protocol called RESP (REdis Serialization Protocol). Although this protocol is specifically designed for Redis, it can also be used in other client-server communication mode software. The RESP protocol was introduced in Redis1.2 and did not become a standard for communicating with Redis servers until Redis2.0. This protocol needs to be implemented on your Redis client.

RESP is a serialization protocol that supports multiple data types: simple strings (Simple Strings), errors (Errors), integers (Integers), bulk strings (Bulk Strings), and arrays (Arrays).

RESP is used as a request-response protocol in Redis as follows:

The client sends commands to the server in the form of a large string RESP array. The server returns a certain RESP data type according to the specific implementation of the command. In RESP, the type of data depends on the first byte:

Single-line string (Simple Strings): the first byte of the response is "+" error (Errors): the first byte of the response is "-" integer (Integers): the first byte of the response is ":" multiline string (Bulk Strings): the first byte of the response is the "$" array (Arrays): the first byte of the response is "*" in addition, the RESP can use large-capacity strings or special variables of array types to represent null values It will be explained in detail below. Different parts of the RESP protocol always end with "\ r\ n" (CRLF). The string "foobar" is encoded as follows:

"$6\ r\ nfoobar\ r\ n"

What does the actual redis command look like, such as SET lhjljh lhjkjhkh

* 3\ r\ nroom3\ r\ nSET\ r\ nroom6\ r\ nlhjljh\ r\ nroom8\ r\ nlhjkjhkh3, codec

Because RESP is naturally command-oriented, there is no way to serialize and deserialize redis messages directly like grpc or dubbo. And each content is limited in length, which is suitable for just-in-time serialization, zero copy, deserialization and serialization directly for the input stream, which is very similar to the design of the Protostuff serialization protocol. So serialization directly converts the stream received by the server into a value.

The codec entity class is directly added to redis server's pipeline to deal with a long-connected tcp client.

4, command processing

To decode the message into RESP, you also need to convert the RESP into a Command object, which is easier to write and understand because it is a java language and the method is bound to the class. But it will add some overhead.

Second, the data structure of redis 1, the underlying main structure

The underlying main tree is implemented using jump table ConcurrentSkipListMap. The reason why hash type map is not used is that after the server is clustered, the client may use hash routing, which will lead to serious hash conflicts on the server side and greatly reduce the performance.

Key is encapsulated "String" and overrides the equals method to avoid the same key but different pointers in jvm

Value is an interface, and implementation classes are the five basic types of redis. All data types contain timeouts.

2,key

The reason for using encapsulated values as value is to facilitate unified management.

3,list

The reason for using LinkedList at the bottom is that LinkedList implements a variety of interfaces, and various commands can directly call their off-the-shelf implementation methods.

4,set

It is not very special to use set in HashSet,redis at the bottom.

5,hash

The underlying layer uses HashMap, which does not conflict with the HashMap mentioned at the beginning. Why don't you jump the meter? Compressed list is very ingenious, which probably means that the array received by communication is directly populated into list, and list is directly used as map in order, mainly the idea of 0 copy, there is no need to create new resources, and the performance is extremely high, but note that compressed list has nothing to do with compression.

6,zset

First, you need to encapsulate an object with values and scores.

Then use TreeMap to rewrite the compare method. The reason for using TreeMap is that it naturally has a good sorting function, and many hash consistent routing algorithms use TreeMap.

Third, redis AOF persistence 1 Permiaof thread is decoupled from tcp thread, namely write buffer

When parsing the redis command, add the redis write command to the queue for writing the aof log

A congestion queue is encapsulated here, and the throughput of a single thread can reach 3000W / s, which is 6 to 10 times that of LinkedBlockingQueue, which is completely suitable for this scenario.

The reason for the very high throughput of RingBlockingQueue is the use of memory contiguous pages mechanism.

2Precaof persistence protocol

The summary of the aof protocol is to append the write command to the log, read the command at the beginning, and execute it as if it had received a command from the network. Because the agreement is too simple, the link will not be posted here. The format of the date of aof is as follows:

Implementation of loading and storage of 3djinaof

Here, both read and write memory are mapped by memory files. The advantage is that the read and write performance is good, but the disadvantage is that there may be memory leaks, which is troublesome during debugging.

4, memory file mapping and object-oriented

The code here to store and load aof files is process-oriented and looks very complex. In fact, it was written according to object-oriented and encapsulated into a line object, and commands in aof can be written and read by calling drop character and pick-up method, but TPS is only 10w/s. Later, it is changed to process-oriented, and the throughput is improved to more than 100W TPS.

Fourth, the cluster feature of redis 1, master and slave

It is easy to think of the slave-only of mysql. In many scenarios, read-write separation based on mysql master-slave is used, or master-slave of zk. But in fact, the master and slave of redis do not guarantee consistency. I think that the master and slave of redist mainly consider the distributed fault tolerance of cap. Because the redis master never guarantees consistency, using redis to separate reading and writing may cause some inconsistent problems. Writing and writing are consistent, but reading is inconsistent, so you can make a choice according to the needs of the project.

2, master-slave replication

The master-slave copy of redis is not understood by the author here (maybe there is no motivation to read it in terms of consistency), so he didn't write it.

3. Slicing cluster

Redis cluster is mainly divided into several unique: master-slave, partition cluster, agent. Generally, from the perspective of redis clients, it is mainly partitioned clusters, doing hash, md5 and other operations according to the key sent to redis, taking a common value of all clients, and sending key and value, that is, the cluster implementation of client routing distributed software JD.com 's redis cluster is designed to redis a specific shard.

Fifth, stress testing and tuning of redis 1. Memory leak

When aof stress test is enabled, a memory leak is found, which is later found to be caused by frequent new memory pools, so the memory pool is pooled, that is, there is only one bytebuff memory pool in the aof object.

2. Memory reuse improves performance

Here, there is no separate development of byte data receiving bytebuff data for codec, codec directly reads bytebuff for codec, there is no memory copy, only a new BytesWrapper object is created, but the stored data are all using BytesWrapper objects, and there is little overhead for memory creation / destruction.

3Be 0.05% message delay super 200ms troubleshooting

The following picture shows the redis stress test data of c language version:

The following figure shows the redis stress test data of java language version:

4, performance

The performance of the original redis is about 4-5w of the E5 series CPU. The figure above is the data tested using the amd chip. Using redis's own stress testing tool to maintain 100 client connections, the performance of the java version is about 75-90% of the performance of the original c language, and the performance is still strong.

After reading this article, I believe you have a certain understanding of "Java how to handwrite Redis server". If you want to know more about it, you are welcome to follow the industry information channel. Thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report