主頁 > 資料庫 > redis 5.0.7 原始碼閱讀——跳躍表skiplist

redis 5.0.7 原始碼閱讀——跳躍表skiplist

2020-09-13 09:14:33 資料庫

redis中并沒有專門給跳躍表兩個檔案,在5.0.7的版本中,結構體的宣告與定義、介面的宣告在server.h中,介面的定義在t_zset.c中,所有開頭為zsl的函式,

一、資料結構

單個節點:

typedef struct zskiplistNode {
    //key,唯一
    sds ele;

    //分值,可重復
    double score;

    //后退指標
    struct zskiplistNode *backward;

    //
    struct zskiplistLevel {
        //前進指標
        struct zskiplistNode *forward;
        //到本層下一節點的跨度,用于計算rank
        unsigned long span;
    } level[];
} zskiplistNode;

zskiplistNode定義了跳躍表中每個節點的資料結構,它是一個變長結構體,

 1 /*
 2 +------------------------+
 3 |sds ele                 |     /+-----------------------------+
 4 +------------------------+    / |struct zskiplistNode *forward|
 5 |double score            |   /  +-----------------------------+
 6 +------------------------+  /   |unsigned long span           |
 7 |zskiplistNode * backward| /    +-----------------------------+
 8 +------------------------+/     .                             .
 9 |zskiplistLevel  level[] |      .                             .
10 +------------------------+\     .                             .
11                            \    +-----------------------------+
12                             \   |struct zskiplistNode *forward|
13                              \  +-----------------------------+
14                               \ |unsigned long span           |
15                                \+-----------------------------+
16 */

將用以下結構表示:

 1 /*
 2 +--------+
 3 |level[1]|
 4 |1(span) |
 5 +--------+
 6 |level[0]|
 7 |1(span) |
 8 +--------+
 9 |backward|
10 +--------+
11 |score   |
12 +--------+
13 |ele     |
14 +--------+
15 */

如:

 1 /*
 2 +--------+                +--------+                +--------+
 3 |level[1]|--------------->|level[1]|--------------->|level[1]|
 4 |2       |                |2       |                |0       |
 5 +--------+   +--------+   +--------+   +--------+   +--------+
 6 |level[0]|-->|level[0]|-->|level[0]|-->|level[0]|-->|level[0]|
 7 |1       |   |1       |   |1       |   |1       |   |0       |
 8 +--------+   +--------+   +--------+   +--------+   +--------+
 9 |backward|<--|backward|<--|backward|<--|backward|<--|backward| 
10 +--------+   +--------+   +--------+   +--------+   +--------+
11 |1       |   |2       |   |3       |   |4       |   |5       |
12 +--------+   +--------+   +--------+   +--------+   +--------+
13 |a       |   |b       |   |c       |   |d       |   |e       |
14 +--------+   +--------+   +--------+   +--------+   +--------+
15 */

跳表:

1 typedef struct zskiplist {
2     //頭/尾節點
3     struct zskiplistNode *header, *tail;
4     //總長度
5     unsigned long length;
6     //總層數
7     int level;
8 } zskiplist;

因其頭節點固定為空節點,固整體結構:

 1 /*
 2     +--------+                +--------+                +--------+
 3     |level[1]|--------------->|level[1]|--------------->|level[1]|
 4     |2       |                |2       |                |0       |
 5     +--------+   +--------+   +--------+   +--------+   +--------+
 6     |level[0]|-->|level[0]|-->|level[0]|-->|level[0]|-->|level[0]|
 7     |1       |   |1       |   |1       |   |1       |   |0       |
 8     +--------+   +--------+   +--------+   +--------+   +--------+
 9     |backward|<--|backward|<--|backward|<--|backward|<--|backward| 
10     +--------+   +--------+   +--------+   +--------+   +--------+
11     |0       |   |2       |   |3       |   |4       |   |5       |
12     +--------+   +--------+   +--------+   +--------+   +--------+
13     |NULL    |   |b       |   |c       |   |d       |   |e       |
14 +-->+--------+   +--------+   +--------+   +--------+   +--------+<--+
15 |                                                                    |
16 |   +--------+                                                       |
17 +---|header  |                                                       |
18     +--------+                                                       |
19     |tail    |-------------------------------------------------------+
20     +--------+
21     |length=4|
22     +--------+
23     |level=2 |
24     +--------+
25 */

每個level層都是一條單身鏈表,其中level[0]中包含所有元素,

 

二、創建

根據指定的level,創建一個跳表節點:

1 zskiplistNode *zslCreateNode(int level, double score, sds ele) {
2     zskiplistNode *zn =
3         zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel));
4     zn->score = score;
5     zn->ele = ele;
6     return zn;
7 }

創建一個跳表:

 1 #define ZSKIPLIST_MAXLEVEL 64 /* Should be enough for 2^64 elements */
 2 
 3 zskiplist *zslCreate(void) {
 4     int j;
 5     zskiplist *zsl;
 6 
 7     zsl = zmalloc(sizeof(*zsl));
 8     zsl->level = 1;
 9     zsl->length = 0;
10     zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
11     for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
12         zsl->header->level[j].forward = NULL;
13         zsl->header->level[j].span = 0;
14     }
15     zsl->header->backward = NULL;
16     zsl->tail = NULL;
17     return zsl;
18 }

redis中定義的最大層數為64層,且在剛創建時,會生成一個空的頭節點,這樣就可以不用再考慮節點數從0至1或者從1至0時要處理的各種特殊情況,

剛創完的跳表結構(結構中以4做為最大層數,后同):

 1 /*
 2       +--------+
 3       |level[3]|-->NULL
 4       |0       |
 5       +--------+
 6       |level[2]|-->NULL
 7       |0       |
 8       +--------+
 9       |level[1]|-->NULL
10       |0       |
11       +--------+
12       |level[0]|-->NULL
13       |0       |
14       +--------+
15 NULL<-|backward|
16       +--------+
17       |0       |
18       +--------+
19       |NULL    |
20   +-->+--------+
21   |           
22   |   +--------+
23   +---|header  |
24       +--------+
25       |tail    |-->NULL
26       +--------+
27       |length=0|
28       +--------+
29       |level=1 |
30       +--------+
31 */

 

三、插入節點

1 #define ZSKIPLIST_P 0.25      /* Skiplist P = 1/4 */
2 
3 int zslRandomLevel(void) {
4     int level = 1;
5     while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
6         level += 1;
7     return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
8 }

redis中使用的決定新插入節點層資料的方法是拋硬幣法,且“硬幣”只有25%的幾率是正面,

插入方法:

 1 zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {
 2     //update陣列,用于存盤查找路徑
 3     zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
 4 
 5     //rank陣列,用于存盤每層路徑節點的排名
 6     unsigned int rank[ZSKIPLIST_MAXLEVEL];
 7     int i, level;
 8 
 9     serverAssert(!isnan(score));
10     x = zsl->header;
11 
12     //先查找插入位置
13     for (i = zsl->level-1; i >= 0; i--) {
14         /* store rank that is crossed to reach the insert position */
15         rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
16         while (x->level[i].forward &&
17                 (x->level[i].forward->score < score ||
18                     (x->level[i].forward->score == score &&
19                     sdscmp(x->level[i].forward->ele,ele) < 0)))
20         {
21             rank[i] += x->level[i].span;
22             x = x->level[i].forward;
23         }
24         update[i] = x;
25     }
26 
27     //隨機一個level
28     level = zslRandomLevel();
29 
30     //若當前最大level不夠,則補齊update與rank陣列
31     if (level > zsl->level) {
32         for (i = zsl->level; i < level; i++) {
33             rank[i] = 0;
34             update[i] = zsl->header;
35             update[i]->level[i].span = zsl->length;
36         }
37         zsl->level = level;
38     }
39 
40     //創建一個節點,并插入
41     x = zslCreateNode(level,score,ele);
42     for (i = 0; i < level; i++) {
43         x->level[i].forward = update[i]->level[i].forward;
44         update[i]->level[i].forward = x;
45 
46         x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);
47         update[i]->level[i].span = (rank[0] - rank[i]) + 1;
48     }
49 
50     //update陣列中,比插入節點level更高的各成員的跨度增加
51     for (i = level; i < zsl->level; i++) {
52         update[i]->level[i].span++;
53     }
54 
55     x->backward = (update[0] == zsl->header) ? NULL : update[0];
56     if (x->level[0].forward)
57         x->level[0].forward->backward = x;
58     else
59         zsl->tail = x;
60     zsl->length++;
61     return x;
62 }

 

從注釋可知,redis的跳表允許同score的情況發生,但是不允許同ele,且是由呼叫者在外部保證,若插入順序為e,b,c,d,則插入e時:

step1、定義update陣列與rank陣列,

 1 /*
 2 update         rank
 3 +--------+     +--------+
 4 |NULL    |     |0       |
 5 +--------+     +--------+
 6 |NULL    |     |0       |
 7 +--------+     +--------+
 8 |NULL    |     |0       |
 9 +--------+     +--------+
10 |NULL    |     |0       |
11 +--------+     +--------+
12 */

 

實際在linux環境運行時,不會默認初始化,應該是一堆臟資料,此處是為了方便處理結構

step2、查找位置后

 1 /*
 2 update         rank
 3 +--------+     +--------+
 4 |NULL    |     |0       |
 5 +--------+     +--------+
 6 |NULL    |     |0       |
 7 +--------+     +--------+
 8 |NULL    |     |0       |
 9 +--------+     +--------+
10 |header  |     |0       |
11 +--------+     +--------+
12 */

step3、e的level為2,位元表的大,故要補齊update與rank陣列

 1 /*
 2 update         rank
 3 +--------+     +--------+
 4 |NULL    |     |0       |
 5 +--------+     +--------+
 6 |NULL    |     |0       |
 7 +--------+     +--------+
 8 |header  |     |0       |
 9 +--------+     +--------+
10 |header  |     |0       |
11 +--------+     +--------+
12 */

step4、插入節點,與單身鏈表插入相同,將新節點e各層,插入到update陣列中記錄的各層節點之后,并使用rank陣列,計算跨度

 1 /*
 2       +--------+
 3       |level[3]|-->NULL
 4       |0       |
 5       +--------+
 6       |level[2]|-->NULL
 7       |0       |
 8       +--------+   +--------+
 9       |level[1]|-->|level[1]|-->NULL
10       |1       |   |0       |
11       +--------+   +--------+
12       |level[0]|-->|level[0]|-->NULL
13       |1       |   |0       |
14       +--------+   +--------+
15 NULL<-|backward|   |backward|
16       +--------+   +--------+
17       |0       |   |5       |
18       +--------+   +--------+
19       |NULL    |   |e       |
20   +-->+--------+   +--------+
21   |
22   |   +--------+
23   +---|header  |
24       +--------+
25       |tail    |
26       +--------+
27       |length=0|
28       +--------+
29       |level=1 |
30       +--------+
31 */

step5、處理新插入節點的backward指標,與跳表的tail指標:

 1 /*
 2       +--------+
 3       |level[3]|-->NULL
 4       |0       |
 5       +--------+
 6       |level[2]|-->NULL
 7       |0       |
 8       +--------+   +--------+
 9       |level[1]|-->|level[1]|-->NULL
10       |1       |   |0       |
11       +--------+   +--------+
12       |level[0]|-->|level[0]|-->NULL
13       |1       |   |0       |
14       +--------+   +--------+
15 NULL<-|backward|   |backward|
16       +--------+   +--------+
17       |0       |   |5       |
18       +--------+   +--------+
19       |NULL    |   |e       |
20   +-->+--------+   +--------+<--+
21   |                             |
22   |   +--------+                |
23   +---|header  |                |
24       +--------+                |
25       |tail    |----------------+
26       +--------+
27       |length=1|
28       +--------+
29       |level=2 |
30       +--------+
31 
32 */

此時插入b:

找到位置后的update與rank陣列:

 1 /*
 2 update         rank
 3 +--------+     +--------+
 4 |NULL    |     |0       |
 5 +--------+     +--------+
 6 |NULL    |     |0       |
 7 +--------+     +--------+
 8 |header  |     |0       |
 9 +--------+     +--------+
10 |header  |     |0       |
11 +--------+     +--------+
12 */

插入b節點后:

 1 /*
 2       +--------+
 3       |level[3]|-->NULL
 4       |0       |
 5       +--------+
 6       |level[2]|-->NULL
 7       |0       |
 8       +--------+                +--------+
 9       |level[1]|--------------->|level[1]|-->NULL
10       |2       |                |0       |
11       +--------+   +--------+   +--------+
12       |level[0]|-->|level[0]|-->|level[0]|-->NULL
13       |1       |   |1       |   |0       |
14       +--------+   +--------+   +--------+
15 NULL<-|backward|   |backward|<--|backward|
16       +--------+   +--------+   +--------+
17       |0       |   |2       |   |5       |
18       +--------+   +--------+   +--------+
19       |NULL    |   |b       |   |e       |
20   +-->+--------+   +--------+   +--------+<--+
21   |                                          |
22   |   +--------+                             |
23   +---|header  |                             |
24       +--------+                             |
25       |tail    |-----------------------------+
26       +--------+
27       |length=2|
28       +--------+
29       |level=2 |
30       +--------+
31 */

需要注意的是,update陣列idx = 1的節點并沒有新的插入操作,span要自增,表示本層跨度增加了1,

插入c時的update與rank陣列:

 1 /*
 2 update         rank
 3 +--------+     +--------+
 4 |NULL    |     |0       |
 5 +--------+     +--------+
 6 |NULL    |     |0       |
 7 +--------+     +--------+
 8 |header  |     |0       |
 9 +--------+     +--------+
10 |b       |     |1       |
11 +--------+     +--------+
12 */

插入c后:

 1 /*
 2       +--------+
 3       |level[3]|-->NULL
 4       |0       |
 5       +--------+
 6       |level[2]|-->NULL
 7       |0       |
 8       +--------+                +--------+   +--------+
 9       |level[1]|--------------->|level[1]|-->|level[1]|-->NULL
10       |2       |                |1       |   |0       |
11       +--------+   +--------+   +--------+   +--------+
12       |level[0]|-->|level[0]|-->|level[0]|-->|level[0]|-->NULL
13       |1       |   |1       |   |1       |   |0       |
14       +--------+   +--------+   +--------+   +--------+
15 NULL<-|backward|   |backward|<--|backward|<--|backward|
16       +--------+   +--------+   +--------+   +--------+
17       |0       |   |2       |   |3       |   |5       |
18       +--------+   +--------+   +--------+   +--------+
19       |NULL    |   |b       |   |c       |   |e       |
20   +-->+--------+   +--------+   +--------+   +--------+<--+
21   |                                                       |
22   |   +--------+                                          |
23   +---|header  |                                          |
24       +--------+                                          |
25       |tail    |------------------------------------------+
26       +--------+
27       |length=3|
28       +--------+
29       |level=2 |
30       +--------+
31 /*

最后插入d:

update與rank陣列:

 1 /*
 2 update         rank
 3 +--------+     +--------+
 4 |NULL    |     |0       |
 5 +--------+     +--------+
 6 |NULL    |     |0       |
 7 +--------+     +--------+
 8 |c       |     |2       |
 9 +--------+     +--------+
10 |c       |     |2       |
11 +--------+     +--------+
12 */

插入d:

 1 /*
 2       +--------+
 3       |level[3]|-->NULL
 4       |0       |
 5       +--------+
 6       |level[2]|-->NULL
 7       |0       |
 8       +--------+                +--------+                +--------+
 9       |level[1]|--------------->|level[1]|--------------->|level[1]|-->NULL
10       |2       |                |2       |                |0       |
11       +--------+   +--------+   +--------+   +--------+   +--------+
12       |level[0]|-->|level[0]|-->|level[0]|-->|level[0]|-->|level[0]|-->NULL
13       |1       |   |1       |   |1       |   |1       |   |0       |
14       +--------+   +--------+   +--------+   +--------+   +--------+
15 NULL<-|backward|   |backward|<--|backward|<--|backward|<--|backward|
16       +--------+   +--------+   +--------+   +--------+   +--------+
17       |0       |   |2       |   |3       |   |4       |   |5       |
18       +--------+   +--------+   +--------+   +--------+   +--------+
19       |NULL    |   |b       |   |c       |   |d       |   |e       |
20   +-->+--------+   +--------+   +--------+   +--------+   +--------+<--+
21   |                                                                    |
22   |   +--------+                                                       |
23   +---|header  |                                                       |
24       +--------+                                                       |
25       |tail    |-------------------------------------------------------+
26       +--------+
27       |length=4|
28       +--------+
29       |level=2 |
30       +--------+
31 /*

如果此時要新插入節點a,score為4.5,則update與rank陣列分別為:

 1 /*
 2 update         rank
 3 +--------+     +--------+
 4 |NULL    |     |0       |
 5 +--------+     +--------+
 6 |NULL    |     |0       |
 7 +--------+     +--------+
 8 |c       |     |2       |
 9 +--------+     +--------+
10 |d       |     |3       |
11 +--------+     +--------+
12 */

 

四、洗掉節點

在已經查找到位置,與已知update陣列時的洗掉方法:

 1 void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {
 2     int i;
 3     for (i = 0; i < zsl->level; i++) {
 4         if (update[i]->level[i].forward == x) {
 5             update[i]->level[i].span += x->level[i].span - 1;
 6             update[i]->level[i].forward = x->level[i].forward;
 7         } else {
 8             update[i]->level[i].span -= 1;
 9         }
10     }
11     if (x->level[0].forward) {
12         x->level[0].forward->backward = x->backward;
13     } else {
14         zsl->tail = x->backward;
15     }
16     while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL)
17         zsl->level--;
18     zsl->length--;
19 }

洗掉本節點之后,對應路徑相應得做處理,

從跳表中洗掉指定節點的操作:

 1 int zslDelete(zskiplist *zsl, double score, sds ele, zskiplistNode **node) {
 2     zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
 3     int i;
 4 
 5     //先用score與ele查找,生成update陣列
 6     x = zsl->header;
 7     for (i = zsl->level-1; i >= 0; i--) {
 8         while (x->level[i].forward &&
 9                 (x->level[i].forward->score < score ||
10                     (x->level[i].forward->score == score &&
11                      sdscmp(x->level[i].forward->ele,ele) < 0)))
12         {
13             x = x->level[i].forward;
14         }
15         update[i] = x;
16     }
17 
18     //跳表允許同score,防止誤刪,做一下ele校驗
19     if (x && score == x->score && sdscmp(x->ele,ele) == 0) {
20         zslDeleteNode(zsl, x, update);
21         if (!node)
22             zslFreeNode(x);
23         else
24             *node = x;
25         return 1;
26     }
27     return 0;
28 }

如以下跳表:

 1 /*
 2       +--------+
 3       |level[3]|-->NULL
 4       |0       |
 5       +--------+
 6       |level[2]|-->NULL
 7       |0       |
 8       +--------+                +--------+                +--------+
 9       |level[1]|--------------->|level[1]|--------------->|level[1]|-->NULL
10       |2       |                |2       |                |0       |
11       +--------+   +--------+   +--------+   +--------+   +--------+
12       |level[0]|-->|level[0]|-->|level[0]|-->|level[0]|-->|level[0]|-->NULL
13       |1       |   |1       |   |1       |   |1       |   |0       |
14       +--------+   +--------+   +--------+   +--------+   +--------+
15 NULL<-|backward|   |backward|<--|backward|<--|backward|<--|backward|
16       +--------+   +--------+   +--------+   +--------+   +--------+
17       |0       |   |2       |   |3       |   |4       |   |5       |
18       +--------+   +--------+   +--------+   +--------+   +--------+
19       |NULL    |   |b       |   |c       |   |d       |   |e       |
20   +-->+--------+   +--------+   +--------+   +--------+   +--------+<--+
21   |                                                                    |
22   |   +--------+                                                       |
23   +---|header  |                                                       |
24       +--------+                                                       |
25       |tail    |-------------------------------------------------------+
26       +--------+
27       |length=4|
28       +--------+
29       |level=2 |
30       +--------+
31 /*

要洗掉節點d,生成的update陣列為:

 1 /*
 2 update       
 3 +--------+   
 4 |NULL    |   
 5 +--------+   
 6 |NULL    |   
 7 +--------+   
 8 |c       |   
 9 +--------+   
10 |c       |   
11 +--------+   
12 */

由于d的level為1,故在level[0]層,使用從單向鏈表中洗掉節點的操作,把d移出,再給高于level[0]的update陣列中所有成員的span自減,節點少了,跨度要跟著降低,

洗掉d之后的跳表:

 1 /*
 2       +--------+
 3       |level[3]|-->NULL
 4       |0       |
 5       +--------+
 6       |level[2]|-->NULL
 7       |0       |
 8       +--------+                +--------+   +--------+
 9       |level[1]|--------------->|level[1]|-->|level[1]|-->NULL
10       |2       |                |1       |   |0       |
11       +--------+   +--------+   +--------+   +--------+
12       |level[0]|-->|level[0]|-->|level[0]|-->|level[0]|-->NULL
13       |1       |   |1       |   |1       |   |0       |
14       +--------+   +--------+   +--------+   +--------+
15 NULL<-|backward|   |backward|<--|backward|<--|backward|
16       +--------+   +--------+   +--------+   +--------+
17       |0       |   |2       |   |3       |   |5       |
18       +--------+   +--------+   +--------+   +--------+
19       |NULL    |   |b       |   |c       |   |e       |
20   +-->+--------+   +--------+   +--------+   +--------+<--+
21   |                                                       |
22   |   +--------+                                          |
23   +---|header  |                                          |
24       +--------+                                          |
25       |tail    |------------------------------------------+
26       +--------+
27       |length=3|
28       +--------+
29       |level=2 |
30       +--------+
31 /*

 

五、銷毀

 1 void zslFreeNode(zskiplistNode *node) {
 2     sdsfree(node->ele);
 3     zfree(node);
 4 }
 5 
 6 void zslFree(zskiplist *zsl) {
 7     zskiplistNode *node = zsl->header->level[0].forward, *next;
 8 
 9     zfree(zsl->header);
10     while(node) {
11         next = node->level[0].forward;
12         zslFreeNode(node);
13         node = next;
14     }
15     zfree(zsl);
16 }

銷毀操作本身只是在level[0]層遍歷所有節點,依次銷毀,

 

redis 5.0.7 下載鏈接

http://download.redis.io/releases/redis-5.0.7.tar.gz

原始碼閱讀順序參考:

https://github.com/huangz1990/blog/blob/master/diary/2014/how-to-read-redis-source-code.rst

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/22948.html

標籤:NoSQL

上一篇:關于mac下redis的安裝和部署

下一篇:redis 5.0.7 原始碼閱讀——整數集合intset

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more