主頁 > 資料庫 > redis 5.0.7 原始碼閱讀——動態字串sds

redis 5.0.7 原始碼閱讀——動態字串sds

2020-09-13 09:13:57 資料庫

redis中動態字串sds相關的檔案為:sds.h與sds.c

一、資料結構

redis中定義了自己的資料型別"sds",用于描述 char*,與一些資料結構

 1 typedef char *sds;
 2 
 3 /* Note: sdshdr5 is never used, we just access the flags byte directly.
 4  * However is here to document the layout of type 5 SDS strings. */
 5 struct __attribute__ ((__packed__)) sdshdr5 {
 6     unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
 7     char buf[];
 8 };
 9 struct __attribute__ ((__packed__)) sdshdr8 {
10     uint8_t len; /* used */
11     uint8_t alloc; /* excluding the header and null terminator */
12     unsigned char flags; /* 3 lsb of type, 5 unused bits */
13     char buf[];
14 };
15 struct __attribute__ ((__packed__)) sdshdr16 {
16     uint16_t len; /* used */
17     uint16_t alloc; /* excluding the header and null terminator */
18     unsigned char flags; /* 3 lsb of type, 5 unused bits */
19     char buf[];
20 };
21 struct __attribute__ ((__packed__)) sdshdr32 {
22     uint32_t len; /* used */
23     uint32_t alloc; /* excluding the header and null terminator */
24     unsigned char flags; /* 3 lsb of type, 5 unused bits */
25     char buf[];
26 };
27 struct __attribute__ ((__packed__)) sdshdr64 {
28     uint64_t len; /* used */
29     uint64_t alloc; /* excluding the header and null terminator */
30     unsigned char flags; /* 3 lsb of type, 5 unused bits */
31     char buf[];
32 };

定義結構體時,加上了 __attribute__ ((__packed__)) 關鍵字,用于取消位元組對齊,使其按照緊湊排列的方式,占用記憶體,這樣做的目的并不僅僅只是為了節約記憶體的使用,結構體最后有一個 char buf[],查了資料之后了解到,其只是定義一個陣列符號,并沒有任何成員,不占用結構體的記憶體空間,其真實地址緊隨結構體之后,可實作變長結構體,由此可以只根據sds字串的真實地址,取到sds結構體的任意成員變數資料,如flags:

1 void func(const sds s)
2 {
3     unsigned char flags = s[-1];      
4 }

這個flags,從原始碼的注釋上看,其低三位用于表示sds型別,高五位是當sds型別為sdshdr5時,表明字串長度的,對于非sdshdr5的型別,有專門的成員變數描述當前已使用的長度,及總buffer長度,

sds型別:

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

sds定義了兩個宏,用于獲取sds結構體首地址:

1 #define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
2 #define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))

由此可見sds結構體的大致結構為:

 1 /*
 2 sdshdr5
 3 +--------+----...---+
 4 |00011000|abc\0     |
 5 +--------+----...---+
 6 |flags   |buf
 7 
 8 sdshdr8
 9 +--------+--------+--------+----...---+
10 |00000011|00000011|00000001|abc\0     |
11 +--------+--------+--------+----...---+
12 |len     |alloc   |flags   |buf
13 */

sds的一些常規操作,如獲取字串長度、獲取剩余buf長度等,都是其于以上操作,首先根據sds字串地址獲取其flags的值,根據flags低三位判斷sds型別,接著使用宏SDS_HDR_VAR或SDS_HDR進行操作,如:

 1 #define SDS_TYPE_MASK 7   //0000,0111
 2 
 3 static inline size_t sdslen(const sds s) {
 4 //獲取flags
 5     unsigned char flags = s[-1];
 6 //根據flags低三位取型別,根據型別做不同處理
 7     switch(flags&SDS_TYPE_MASK) {
 8         case SDS_TYPE_5:
 9             return SDS_TYPE_5_LEN(flags);
10         case SDS_TYPE_8:
11             return SDS_HDR(8,s)->len;
12         case SDS_TYPE_16:
13             return SDS_HDR(16,s)->len;
14         case SDS_TYPE_32:
15             return SDS_HDR(32,s)->len;
16         case SDS_TYPE_64:
17             return SDS_HDR(64,s)->len;
18     }
19     return 0;
20 }

關于sds結構體中的len與alloc,len表示的是sds字串的當前長度,alloc表示的是buf的總長度,

二、一些操作,

首先是一個根據字串長度來決定sds型別的方法

 1 static inline char sdsReqType(size_t string_size) {
 2     if (string_size < 1<<5)    //flags高五位最大數字為 1<<5 - 1
 3         return SDS_TYPE_5;
 4     if (string_size < 1<<8)    //uint8_t 最大數字為 1<<8 - 1
 5         return SDS_TYPE_8;
 6     if (string_size < 1<<16)  //uint16_t 最大數字為 1<<16 - 1
 7         return SDS_TYPE_16;
 8 #if (LONG_MAX == LLONG_MAX)  //區分32位/64位系統
 9     if (string_size < 1ll<<32)
10         return SDS_TYPE_32;
11     return SDS_TYPE_64;
12 #else
13     return SDS_TYPE_32;
14 #endif
15 }

創建一個新的sds結構體:

 1 sds sdsnewlen(const void *init, size_t initlen) {
 2     void *sh;
 3     sds s;
 4     char type = sdsReqType(initlen);
 5     if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
 6     int hdrlen = sdsHdrSize(type);
 7     unsigned char *fp; /* flags pointer. */
 8 
 9     sh = s_malloc(hdrlen+initlen+1);
10     if (init==SDS_NOINIT)
11         init = NULL;
12     else if (!init)
13         memset(sh, 0, hdrlen+initlen+1);
14     if (sh == NULL) return NULL;
15     s = (char*)sh+hdrlen;
16     fp = ((unsigned char*)s)-1;
17     switch(type) {
18         case SDS_TYPE_5: {
19             *fp = type | (initlen << SDS_TYPE_BITS);
20             break;
21         }
22         case SDS_TYPE_8: {
23             SDS_HDR_VAR(8,s);
24             sh->len = initlen;
25             sh->alloc = initlen;
26             *fp = type;
27             break;
28         }
29         case SDS_TYPE_16: {
30             //同SDS_TYPE_8,略
31         }
32         case SDS_TYPE_32: {
33             //同SDS_TYPE_8,略
34         }
35         case SDS_TYPE_64: {
36             //同SDS_TYPE_8,略
37         }
38     }
39     if (initlen && init)
40         memcpy(s, init, initlen);
41     s[initlen] = '\0';
42     return s;
43 }

由外部指定初始字串與初始長度,先根據長度獲取sds型別,然后根據不同型別,可以獲得實際需要的總記憶體空間大小(包括sds結構體長度),值得注意的是,如果初始長度為0的情況下,若為SDS_TYPE_5,則會被強制轉為SDS_TYPE_8,根據原始碼的注釋,空串的定義,通常是為了向后追加內容,SDS_TYPE_5并不適合這種場景,分配完記憶體空間之后,設定好sds結構體的值,再把初始字串拷至sds字串的實際初始位置上(如果有),就可以了,

本方法做為最底層的sds字串初始化介面,被其它介面所呼叫,如:

 1 //空string
 2 sds sdsempty(void) {
 3     return sdsnewlen("",0);
 4 }
 5 
 6 //指定string
 7 sds sdsnew(const char *init) {
 8     size_t initlen = (init == NULL) ? 0 : strlen(init);
 9     return sdsnewlen(init, initlen);
10 }
11 
12 //從現有sds string拷貝
13 sds sdsdup(const sds s) {
14     return sdsnewlen(s, sdslen(s));
15 }

sds的釋放也不是簡單地free sds字串,同樣,它要先找到sds結構體的首地址,再進行free:

1 void sdsfree(sds s) {
2     if (s == NULL) return;
3     s_free((char*)s-sdsHdrSize(s[-1]));
4 }

做為一個變長字串,與傳統c字串,最大的區別,是可以動態擴展,就像c++ stl里的變長陣列 vector一樣,sds的擴容有自己的機制:

 1 sds sdsMakeRoomFor(sds s, size_t addlen) {
 2     void *sh, *newsh;
 3     size_t avail = sdsavail(s);
 4     size_t len, newlen;
 5     char type, oldtype = s[-1] & SDS_TYPE_MASK;
 6     int hdrlen;
 7 
 8     /* Return ASAP if there is enough space left. */
 9     if (avail >= addlen) return s;
10 
11     len = sdslen(s);
12     sh = (char*)s-sdsHdrSize(oldtype);
13     newlen = (len+addlen);
14     if (newlen < SDS_MAX_PREALLOC)
15         newlen *= 2;
16     else
17         newlen += SDS_MAX_PREALLOC;
18 
19     type = sdsReqType(newlen);
20 
21     /* Don't use type 5: the user is appending to the string and type 5 is
22      * not able to remember empty space, so sdsMakeRoomFor() must be called
23      * at every appending operation. */
24     if (type == SDS_TYPE_5) type = SDS_TYPE_8;
25 
26     hdrlen = sdsHdrSize(type);
27     if (oldtype==type) {
28         newsh = s_realloc(sh, hdrlen+newlen+1);
29         if (newsh == NULL) return NULL;
30         s = (char*)newsh+hdrlen;
31     } else {
32         /* Since the header size changes, need to move the string forward,
33          * and can't use realloc */
34         newsh = s_malloc(hdrlen+newlen+1);
35         if (newsh == NULL) return NULL;
36         memcpy((char*)newsh+hdrlen, s, len+1);
37         s_free(sh);
38         s = (char*)newsh+hdrlen;
39         s[-1] = type;
40         sdssetlen(s, len);
41     }
42     sdssetalloc(s, newlen);
43     return s;
44 }

本方法用于擴容sds,并可以指定長度,首先其先取出了當前還空閑的buf長度,方法如下:

 1 static inline size_t sdsavail(const sds s) {
 2     unsigned char flags = s[-1];
 3     switch(flags&SDS_TYPE_MASK) {
 4         case SDS_TYPE_5: {
 5             return 0;
 6         }
 7         case SDS_TYPE_8: {
 8             SDS_HDR_VAR(8,s);
 9             return sh->alloc - sh->len;
10         }
11         case SDS_TYPE_16: {
12             SDS_HDR_VAR(16,s);
13             return sh->alloc - sh->len;
14         }
15         case SDS_TYPE_32: {
16             SDS_HDR_VAR(32,s);
17             return sh->alloc - sh->len;
18         }
19         case SDS_TYPE_64: {
20             SDS_HDR_VAR(64,s);
21             return sh->alloc - sh->len;
22         }
23     }
24     return 0;
25 }

若當前空閑的長度,比需要的長度大,則認為不用再額外分配空間,直接return,否則就啟用擴容操作,

擴容時,先根據當前已使用的長度len與需要增加的長度addlen,算出一個初始新長度newlen,然后對其進行判斷,若newlen大于1M,則在newlen的基礎上,繼續增加1M,否則直接翻倍,然后再根據newlen的最終大小,獲取sds的新型別,此時,若型別依然為SDS_TYPE_5,也要強行修正為SDS_TYPE_8,因為SDS_TYPE_5型別并不知道當前空閑空間的大小,此時,若sds的新型別與原來相同,則只需要呼叫realloc重新分配一下空間即可,此方法會分配出一塊新空間的同時,把原來空間的內容拷過去,并釋放原有空間,而sds型別發生改變的時候,就需要手動新造一個新的sds了,擴容完成之后,需要修正一下當前已使用的空間len,與總buf大小 alloc,

擴容完成之后,或者是其它什么操作,如人工修改了sds字串,并更新的len的情況下,會存在空閑空間太大的情況,此時如果想釋放這部分空間,sds也提供了相應的操作:

 1 sds sdsRemoveFreeSpace(sds s) {
 2     void *sh, *newsh;
 3     char type, oldtype = s[-1] & SDS_TYPE_MASK;
 4     int hdrlen, oldhdrlen = sdsHdrSize(oldtype);
 5     size_t len = sdslen(s);
 6     size_t avail = sdsavail(s);
 7     sh = (char*)s-oldhdrlen;
 8 
 9     /* Return ASAP if there is no space left. */
10     if (avail == 0) return s;
11 
12     /* Check what would be the minimum SDS header that is just good enough to
13      * fit this string. */
14     type = sdsReqType(len);
15     hdrlen = sdsHdrSize(type);
16 
17     /* If the type is the same, or at least a large enough type is still
18      * required, we just realloc(), letting the allocator to do the copy
19      * only if really needed. Otherwise if the change is huge, we manually
20      * reallocate the string to use the different header type. */
21     if (oldtype==type || type > SDS_TYPE_8) {
22         newsh = s_realloc(sh, oldhdrlen+len+1);
23         if (newsh == NULL) return NULL;
24         s = (char*)newsh+oldhdrlen;
25     } else {
26         newsh = s_malloc(hdrlen+len+1);
27         if (newsh == NULL) return NULL;
28         memcpy((char*)newsh+hdrlen, s, len+1);
29         s_free(sh);
30         s = (char*)newsh+hdrlen;
31         s[-1] = type;
32         sdssetlen(s, len);
33     }
34     sdssetalloc(s, len);
35     return s;
36 }

操作與擴容類似,同樣是會根據sds型別是否發生變化 ,來決定是使用realloc還是重新造一個sds,

除此之外,sds還實作了一些轉義、資料型別轉換、一些類似c風格的字串操作等,如:strcpy、strcat、strlen、strcmp等,只是其更加多樣化,如sds的strcat實作,就可以支持類似printf的方式,如:

 1 /* Like sdscatprintf() but gets va_list instead of being variadic. */
 2 sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
 3     va_list cpy;
 4     char staticbuf[1024], *buf = staticbuf, *t;
 5     size_t buflen = strlen(fmt)*2;
 6 
 7     /* We try to start using a static buffer for speed.
 8      * If not possible we revert to heap allocation. */
 9     if (buflen > sizeof(staticbuf)) {
10         buf = s_malloc(buflen);
11         if (buf == NULL) return NULL;
12     } else {
13         buflen = sizeof(staticbuf);
14     }
15 
16     /* Try with buffers two times bigger every time we fail to
17      * fit the string in the current buffer size. */
18     while(1) {
19         buf[buflen-2] = '\0';
20         va_copy(cpy,ap);
21         vsnprintf(buf, buflen, fmt, cpy);
22         va_end(cpy);
23         if (buf[buflen-2] != '\0') {
24             if (buf != staticbuf) s_free(buf);
25             buflen *= 2;
26             buf = s_malloc(buflen);
27             if (buf == NULL) return NULL;
28             continue;
29         }
30         break;
31     }
32 
33     /* Finally concat the obtained string to the SDS string and return it. */
34     t = sdscat(s, buf);
35     if (buf != staticbuf) s_free(buf);
36     return t;
37 }
38 
39 /* Append to the sds string 's' a string obtained using printf-alike format
40  * specifier.
41  *
42  * After the call, the modified sds string is no longer valid and all the
43  * references must be substituted with the new pointer returned by the call.
44  *
45  * Example:
46  *
47  * s = sdsnew("Sum is: ");
48  * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
49  *
50  * Often you need to create a string from scratch with the printf-alike
51  * format. When this is the need, just use sdsempty() as the target string:
52  *
53  * s = sdscatprintf(sdsempty(), "... your format ...", args);
54  */
55 sds sdscatprintf(sds s, const char *fmt, ...) {
56     va_list ap;
57     char *t;
58     va_start(ap, fmt);
59     t = sdscatvprintf(s,fmt,ap);
60     va_end(ap);
61     return t;
62 }

其它方法在此不再過多描述

三、sds相比c的標準庫優勢:

1、相比于c標準庫,獲取字串的len復雜讀從O(N)降低到O(1),sds結構中存盤了字串的長度,所以類似strlen(str)的操作不會成為redis的性能瓶頸,
2、在記憶體分配策略上,redis總是會嘗試多分配一些空間,比如小于1MB的字串,總是分配2倍記憶體空間,對于大于1MB的空間追加1MB冗余空間,這對于字串操作(如strcat等)能減少重新記憶體分配的幾率,提升運行性能,
3、SDS總是安全的,sds總是會自動追加字串結尾符號’\0’,有效防止溢位發生,
4、惰性釋放記憶體,改變原字串時,標準庫需要重新分配記憶體的復雜度為O(N),SDS最大為O(N),最優情況下無需重新分配記憶體空間,

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://blog.csdn.net/zzuchengming/article/details/51840067

https://blog.csdn.net/junlon2006/article/details/101369299

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

標籤:NoSQL

上一篇:Redis系列(二):Redis的5種資料結構及其常用命令

下一篇:redis 5.0.7 原始碼閱讀——雙向鏈表

標籤雲
其他(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