1.原理
短結(jié)構(gòu)
Redis為列表焙畔、集合县遣、散列和有序集合提供了一組配置選項(xiàng)虱咧,讓Redis以跟節(jié)約內(nèi)存的方式存儲(chǔ)這些變量
阿里云主從版提供的選項(xiàng)(全是和短結(jié)構(gòu)有關(guān)的,ziplist可以說(shuō)是除了hash字典之外最常用的結(jié)構(gòu))
在列表种樱、散列蒙袍、有序集合的長(zhǎng)度較短或者體積較小的時(shí)候,redis會(huì)使用壓縮列表(ziplist)代替通常情況下這三種結(jié)構(gòu)的底層實(shí)現(xiàn)方式作為這幾種結(jié)構(gòu)的底層實(shí)現(xiàn)嫩挤。
配置:
- entries:最大元素?cái)?shù)量
- value:壓縮列表的每個(gè)節(jié)點(diǎn)的最大體積
當(dāng)任一條件被突破時(shí)害幅,Redis就會(huì)把底層實(shí)現(xiàn)改為通常的結(jié)構(gòu),而且當(dāng)數(shù)據(jù)被刪除之后也不會(huì)再次使用ziplist
體積較小的集合使用intset來(lái)作為底層實(shí)現(xiàn)
條件:
- 整數(shù)集合包含的所有成員都可以被解釋為十進(jìn)制數(shù)
- 這些整數(shù)又處于平臺(tái)的有符號(hào)整數(shù)范圍之內(nèi)
- 集合成員數(shù)量足夠少
短結(jié)構(gòu)是以上幾種結(jié)構(gòu)的緊湊表示方式
減少鍵的長(zhǎng)度也是應(yīng)該注意的一個(gè)點(diǎn)岂昭。
短結(jié)構(gòu)ziplist
Redis中ziplist的定義(序列化字符串)和接口
unsigned char *ziplistNew(void);
unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where);
unsigned char *ziplistIndex(unsigned char *zl, int index);
unsigned char *ziplistNext(unsigned char *zl, unsigned char *p);
unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p);
unsigned int ziplistGet(unsigned char *p, unsigned char **sval, unsigned int *slen, long long *lval);
unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen);
unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p);
unsigned char *ziplistDeleteRange(unsigned char *zl, unsigned int index, unsigned int num);
unsigned int ziplistCompare(unsigned char *p, unsigned char *s, unsigned int slen);
unsigned char *ziplistFind(unsigned char *p, unsigned char *vstr, unsigned int vlen, unsigned int skip);
unsigned int ziplistLen(unsigned char *zl);
size_t ziplistBlobLen(unsigned char *zl);
壓縮列表由節(jié)點(diǎn)序列和四個(gè)控制位組成以现。
影響性能的因素:每次讀取數(shù)據(jù)時(shí)都需要對(duì)進(jìn)行解碼,寫(xiě)入也需要進(jìn)行局部的重新編碼佩抹,并且有可能觸發(fā)連鎖更新叼风,但是這些操作在對(duì)小列表進(jìn)行處理時(shí)對(duì)性能的損耗并不很明顯(平均O(N))取董。
短結(jié)構(gòu)intset
Redis中整數(shù)集合的定義和接口棍苹,可見(jiàn)其最底層實(shí)現(xiàn)就是一個(gè)有序的C語(yǔ)言數(shù)組。
typedef struct intset {
// 編碼方式
uint32_t encoding;
// 集合包含的元素?cái)?shù)量
uint32_t length;
// 保存元素的數(shù)組
int8_t contents[];
} intset;
intset *intsetNew(void);
intset *intsetAdd(intset *is, int64_t value, uint8_t *success);
intset *intsetRemove(intset *is, int64_t value, int *success);
uint8_t intsetFind(intset *is, int64_t value);
int64_t intsetRandom(intset *is);
uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value);
uint32_t intsetLen(intset *is);
size_t intsetBlobLen(intset *is);
影響性能的因素:對(duì)整數(shù)集合進(jìn)行插入或者刪除操作時(shí)需要進(jìn)行數(shù)據(jù)移動(dòng)茵汰,并有可能引起底層升級(jí)枢里。
隨著短結(jié)構(gòu)的體積變得越來(lái)越大,操作這些結(jié)構(gòu)的速度也會(huì)變得越來(lái)越慢蹂午,所以可以引入分片技術(shù)以追求性能和空間之前的平衡栏豺。
2.分片結(jié)構(gòu)
- 特別適合分片的場(chǎng)景:執(zhí)行分片版命令的時(shí)候只需要訪問(wèn)指定分片即可。
- 特別不適合分片的場(chǎng)景:需要訪問(wèn)指定分片豆胸,完事還得進(jìn)行歸并聚合的操作奥洼。
- 可以通過(guò)分片提升性能的場(chǎng)景:搜索
- 替代分片的一種場(chǎng)景:只對(duì)前n位和后n位操作的有序集合(用單獨(dú)維護(hù)的兩個(gè)最大有序集合和最小有序集合實(shí)現(xiàn))。
對(duì)列表進(jìn)行分片
有序集合進(jìn)行分片:
有序集合的大部分操作都屬于特別不適合分片的場(chǎng)景晚胡。-
分片式散列:將字符串鍵存儲(chǔ)到散列里面也可以明顯降低內(nèi)存占用
- 實(shí)現(xiàn)分片方法即可
asbtract class ShardHlist {
/*
** $base 基礎(chǔ)散列
** $key 將要保存到分片散列里面的鍵
** $total_elements 預(yù)計(jì)元素總量
** $shard_size 預(yù)期分片大小
*/
abstract public function shard_key($base, $key, $total_elements, $shard_size);
abstract public function shard_hset($shard_key, key, value, $total_elements, $shard_size);
abstract public function shard_hset($shard_key, key, $total_elements, $shard_size);
}
如果不是輔助緩存那么不應(yīng)該隨便更改$total_elements 和 $shard_size灵奖,一旦不得不更改需要resharding方法將數(shù)據(jù)從舊的分片遷移到新的分片
- 分片集合
shard_add、shard_rem