Redis principle - RedisObject object mechanism

The address of the original text is updated, and the reading effect is better!

Redis principle - RedisObject object mechanism | CoderMast programming mast icon-default.png?t=N5F7https://www.codermast.com/database/redis/redis-object.html

Why is RedisObject designed?

In Redis, our operations are performed using instructions, and among these commands, commands for key processing occupy a large part. Some instructions can only target certain types, while some instructions can target all types. But to implement these commands correctly, different handling must be set for different types of keys. For example, the operation process of deleting a list key is different from that of deleting a string key, and different view methods need to be called at the bottom layer.

There are two different bottom-level implementations for collection types: dictionary and integer collection. When users operate on collections, they don't want to care about the specific bottom-level implementation. As long as Redis can complete the corresponding functions according to its own instructions, such as adding and deleting elements, the specific bottom-level implementation is transparent and invisible to users.

Therefore, Redis must have type information for each key, as well as its underlying encoding method. Only with these two pieces of information can Redis accurately implement user instructions. Then the RedisObject object should contain at least 3 attributes, type information, encoding method, and actual data.

#RedisObject

The key and value of any data type in Redis will be encapsulated as a RedisObject, also called a Redis object, which is /src/server.himplemented in the file as follows:

typedef struct redisObject {
    unsigned type:4;        
    unsigned encoding:4;    // 共有 11 种编码方式,占据 4 个比特位
    unsigned lru:LRU_BITS;  /* LRU 表示该对象最后一次被访问的时间,其占用 24 个 bit 位,
                               便于判断空闲时间太久的key */
    int refcount;           // 对象引用计数器,计数器为 0 则说明对象无人引用,可以被回收。
    void *ptr;              // 指针,指向数据的真实存储空间地址。一般为 8 个字节
} robj;
  • unsigned type: 4 occupies 4 bits, which are string, list, set, zset, hash corresponding to 0 1 2 3 4
  • unsigned encoding: 4 There are 11 encoding methods, occupying 4 bits
  • unsigned lru:LRU_BITSLRU indicates the last time the object was accessed, which occupies 24 bits, which is convenient for judging the key that has been idle for too long
  • int refcount object reference counter, if the counter is 0, it means that no one references the object and can be recycled.
  • void *ptr pointer, pointing to the real storage space address of the data. Usually 8 bytes

# encoding method

Redis will choose different encoding methods according to the different types of stored data, including 11 different types in total:

serial number Encoding illustrate
1 OBJ ENCODING RAW raw encoding dynamic string
2 OBJ ENCODING INT String of integers of type Long
3 OBJ_ENCODING_HT hash table (dictionary dict)
4 OBJ ENCODING ZIPMAP obsolete
5 OBJ_ENCODING_LINKEDLIST double-ended linked list
6 OBJ ENCODING ZIPLIST compressed list
7 OBJ_ENCODING INTSET set of integers
8 OBJ ENCODING SKIPLIST jump table
9 OBJ_ENCODING EMBSTR dynamic string for embstr
10 OBJ_ENCODING QUICKLIST quick list
11 OBJENCODING STREAM Stream

#data type

In Redis, different encoding methods are selected according to the type of data stored. The encoding used for each data type is as follows:

type of data Encoding serial number illustrate
OBJ_STRING int、embstr、raw 0 string
OBJ_LIST LinkedList and ZipList (before 3.2), QuickList (after 3.2) 1 the list
OBJ_SET intset、HT 2 gather
OBJ_ZSET ZipList、HT、SkipList 3 ordered set
OBJ_HASH ZipList、HT 4 hash table

Notice

There are only 5 basic types here, and 3 special types are not mentioned, because the bottom layer of these three special types is OBJ_STRINGimplemented by using, and there is no new bottom layer implementation.

# command processing

According to the previous description, when Redis executes a command, it needs to judge the data type and encoding method to be executed. When Redis executes a data type processing command, Redis performs the following steps:

  1. According to the given key, look up the corresponding redisObject in the database dictionary, if not found, return NULL
  2. Check whether the type attribute of redisObject matches the type required to execute the command, if not, the return type is wrong
  3. According to the encoding specified by the encoding attribute of redisObject, select the appropriate operation function to process the underlying data structure
  4. Returns the result of the operation on the data structure as the return value of the command

For example, execute the LPOP command now:

# object sharing

Redis generally puts some common values ​​into a shared object, which saves the program from the trouble of repeated allocation and saves some CPU time.

Redis pre-allocated value objects are as follows

  • The return value of various commands, such as OK returned when successful, ERROR returned when an error occurs, QUEUE returned when a command enqueues a transaction, etc.
  • Including 0, all integers less than REDIS_SHARED_INTEGERS (the default value of REDIS_SHARED_INTEGERS is 10000)

Notice

Shared objects can only be used by data structures such as dictionaries and doubly linked lists that can have pointers, and only pointers can point to arbitrary addresses. However, integer collections and compressed lists, which can only store actual data such as strings and integers, cannot be shared.

Why does redis not share list objects, hash objects, collection objects, ordered collection objects, but only string objects?

  • List objects, hash objects, collection objects, and ordered collection objects can themselves contain string objects, which have high complexity.
  • If the shared object is to hold a string object, then the complexity of the verification operation is O(1)
  • If the shared object is a string object holding a string value, then the complexity of the validation operation is O(N)
  • If the shared object is an object containing multiple values, and the value itself is a string object, that is, string objects are nested in other objects, such as list objects and hash objects, then the complexity of the verification operation will be O(N squared)
  • If you create a shared object for an object with high complexity, it needs to consume a lot of CPU, and it is not appropriate to exchange this consumption for memory space. And if the complexity of the object is too high, it means that the object has more personality and less commonality, so the number and frequency of using the object will be very low.

#reference counter

There is a refcount attribute in RedisObject, which is an object reference counter and is used to record the number of object references.

When the counter is 0, it means that the object is not referenced and will not be used again, which means that the object can be deleted and destroyed.

When an object is newly created, its refcount property is set to 1.

When sharing an object, Redis adds one to the refcount of the object.

When an object is used, or the reference to an object is eliminated, the program decrements the object's refcount by one.

 

Guess you like

Origin blog.csdn.net/qq_33685334/article/details/131278579