Heim >Datenbank >Redis >Redis studiert das Notes-String-Prinzip

Redis studiert das Notes-String-Prinzip

Golang菜鸟
Golang菜鸟nach vorne
2023-08-08 16:19:281609Durchsuche

String ist der grundlegendste Datentyp von Redis. Nicht nur alle Schlüssel sind String-Typen, sondern auch die Elemente, die aus mehreren anderen Datentypen bestehen. Beachten Sie, dass die Länge der Zeichenfolge 512 MB nicht überschreiten darf.

Zunächst einmal: Wer hat festgelegt, dass es 512 M nicht überschreiten darf? Oder warum nicht mehr als 512 Millionen?

// 源码定义(检查字符串长度)
static int checkStringLength(redisClient *c, long long size) {
    if (size > 512*1024*1024) {
        addReplyError(c,"string exceeds maximum allowed size (512MB)");
        return REDIS_ERR;
    }
    return REDIS_OK;
}

Durch Quellcodeprüfung behoben und darf 512 M nicht überschreiten.

Werfen wir einen Blick auf die Redis-String-Struktur:

struct sdshdr{
    // 记录 buf 数组中已使用字节的数量
    // 等于 SDS 所保存字符串的长度
    int len;
    // 记录 buf 数组中未使用字节的数量
    int free;
    // 字节数组,用于保存字符串
    char buf[];
}

Es ist direkt ersichtlich, dass int 32 Bit hat und daher maximal 4G-Strings unterstützen sollte, aber das ist nicht die tatsächliche Situation .

Um herauszufinden, warum es 512 M nicht überschreiten darf, habe ich eine offizielle Antwort gefunden:

Redis studiert das Notes-String-Prinzip

Dann stellte ich fest, dass die Redis-Informationen, die ich gelesen hatte, veraltet waren!

Redis studiert das Notes-String-Prinzip

Sehen Sie, es gibt auch andere, die ausgetrickst wurden. Die in dieser Diskussion besprochenen Versionen stammen alle vor 3.2.

话不多说,继续学习 redis5.0 版本的资料。不过之前学习了的也没事,我们可以一起来看下 redis 的字符串是怎么优化的。

用如下结构来存储长度小于32的短字符串:

struct __attribute__((__packed__)) sdshdr5 {
        unsigned char flags; /* 低3位存储类型,高5位存储长度*/
        char buf[]; /* 柔性数组,存放实际内容*/
}

sdshdr5 结构中,flags占1个字节,其低3位(bit)表示type,高5位(bit)表示长度,能表示的长度区间为0~31(25-1), flags后面就是字符串的内容。

而对于长度大于31的字符串,这个结构就不够用了,所以对于不同长度的字符串,有不同的处理方式:

#define SDS_TYPE_5  0
#define SDS_TYPE_8  1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4

struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* used */
    uint16_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len; /* used */
    uint32_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* used */
    uint64_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};

可以看到,这4种结构的成员变量类似,唯一的区别是len和alloc的类型不同。

结构体中4个字段的具体含义分别如下:

1)len:表示buf中已占用字节数。

2)alloc:表示buf中已分配字节数,不同于free,记录的是为buf分配的总长度。

3)flags:标识当前结构体的类型,低3位用作标识位,高5位预留。

4) buf: flexibles Array, ein Datenraum, der tatsächlich Zeichenfolgen speichert.

Der Prozess zum Erstellen einer Zeichenfolge:

Redis erstellt SDS über die sdsnewlen-Funktion. In der Funktion wird der entsprechende Typ basierend auf der Länge der Zeichenfolge ausgewählt. Nach der Initialisierung des entsprechenden statistischen Werts wird ein Zeiger auf den Inhalt der Zeichenfolge zurückgegeben und verschiedene Typen werden basierend auf der Länge der Zeichenfolge ausgewählt .

Für den Typ sdshdr5 wird beim Erstellen einer leeren Zeichenfolge diese in sdshdr8 umgewandelt. Der Grund kann sein, dass nach dem Erstellen einer leeren Zeichenfolge deren Inhalt möglicherweise häufig aktualisiert wird und eine Erweiterung verursacht, sodass er beim Erstellen direkt als sdshdr8 erstellt wird.

Strings spleißen:

sdscatsds ist eine Methode, die der oberen Ebene ausgesetzt ist und letztendlich sdscatlen aufruft. Da die Erweiterung von SDS beteiligt sein kann, wird sdsMakeRoomFor in sdscatlen aufgerufen, um die Kapazität der gespleißten Zeichenfolge s zu überprüfen. Wenn keine Erweiterung erforderlich ist, wird die erweiterte neue Zeichenfolge s zurückgegeben. Die Längenwerte wie len und curlen in der Funktion enthalten keine Abschlusszeichen. Beim Spleißen werden die beiden Zeichenfolgen mit memcpy zusammengefügt und die relevanten Längen angegeben, sodass dieser Prozess die binäre Sicherheit gewährleistet. Am Ende muss ein Abschlusszeichen hinzugefügt werden.

String-Erweiterung

  1. Wenn die verbleibende freie Länge in SDS größer ist als die Länge des neuen Inhaltsaddlens, hängen Sie ihn einfach ohne Erweiterung direkt an das Ende des flexiblen Array-Bufs an.

  2. Wenn die verbleibende freie Länge im SDS kleiner oder gleich der Länge des neuen Inhalts addlen ist, werden wir dies von Fall zu Fall besprechen: Wenn die Gesamtlänge nach der Hinzufügung len+ beträgt addlen1MB ist, wird die Kapazität durch Hinzufügen von 1MB zur neuen Länge erweitert.

  3. Wählen Sie abschließend den Speichertyp entsprechend der neuen Länge neu aus und weisen Sie Platz zu. Wenn der Typ hier nicht geändert werden muss, erweitern Sie einfach das flexible Array über Realloc. Andernfalls müssen Sie den Speicher erneut öffnen und den Pufferinhalt der ursprünglichen Zeichenfolge an einen neuen Speicherort verschieben.

Das war's auch schon mit der Saite.

In Version 5.0 gibt es keine Zeichenfolgenbeschränkung von 512 MB. Die Verarbeitungsmethoden von Zeichenfolgen sind je nach Typ unterschiedlich, wodurch mehr Speicher gespart wird

Das obige ist der detaillierte Inhalt vonRedis studiert das Notes-String-Prinzip. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:Golang菜鸟. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen