redis数据结构

redis全名(Remote Dictionary Server),即远程字典服务

redis的值的数据结构类型有String、List、Set、Hash、zset(sorted set,有序集合)、Bitmaps(位图)、HyperLogLogs

注意:我使用的版本是6.0.10,不同版本可能略有差别

redis中key的最大长度为512M

对象

server.h

任何value对象都会被包装成一个redisObject,redisObject能指定value类型,编码方式等数据属性

typedefstructredisObject{
//对象的类型字符串、列表、集合、哈希表
unsignedtype:4;
//编码方式,也就是存储方式,提供多种方式来保存一个数据
unsignedencoding:4;
//记录最后一次被访问的时间
unsignedlru:LRU_BITS;/*LRUtime(relativetogloballru_clock)or
*LFUdata(leastsignificant8bitsfrequency
//引用计数*andmostsignificant16bitsaccesstime).*/

intrefcount;
//指向底层实现的指针
void*ptr;
}robj;
类型总览

redis中的数据类型,即为redisObject的type属性

//string
#defineOBJ_STRING0/*Stringobject.*/
//list
#defineOBJ_LIST1/*Listobject.*/
//set
#defineOBJ_SET2/*Setobject.*/
//zset
#defineOBJ_ZSET3/*Sortedsetobject.*/
//hash
#defineOBJ_HASH4/*Hashobject.*/
//module
#defineOBJ_MODULE5/*Moduleobject.*/
//stream
#defineOBJ_STREAM6/*Streamobject.*/
#可以使用type命令来查看该键所对应值的类型
typekey
redis的编码分类

对应于redisObject的ecoding属性,encoding是决定对象底层实现数据结构的

//简单动态字符串raw
#defineOBJ_ENCODING_RAW0/*Rawrepresentation*/
//long类型的整数int
#defineOBJ_ENCODING_INT1/*Encodedasinteger*/
//哈希表hashtable
#defineOBJ_ENCODING_HT2/*Encodedashashtable*/
//压缩不再使用
#defineOBJ_ENCODING_ZIPMAP3/*Encodedaszipmap*/
//双向链表不再使用该结构
#defineOBJ_ENCODING_LINKEDLIST4/*Nolongerused:oldlistencoding.*/
//压缩列表ziplist
#defineOBJ_ENCODING_ZIPLIST5/*Encodedasziplist*/
//整数集合intset
#defineOBJ_ENCODING_INTSET6/*Encodedasintset*/
//跳表skiplist
#defineOBJ_ENCODING_SKIPLIST7/*Encodedasskiplist*/
//embstr编码的简单动态字符串embstr
#defineOBJ_ENCODING_EMBSTR8/*Embeddedsdsstringencoding*/
//快表quicklist
#defineOBJ_ENCODING_QUICKLIST9/*Encodedaslinkedlistofziplists*/
//流stream
#defineOBJ_ENCODING_STREAM10/*Encodedasaradixtreeoflistpacks*/

可以使用命令来查看存储方式

objectencodingkey

来查看该key使用的是哪种编码

127.0.0.1:6379>settest_int1
OK
127.0.0.1:6379>objectencodingtest_int
"int"
127.0.0.1:6379>settest_rawzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
OK
127.0.0.1:6379>strlentest_raw
(integer)44
127.0.0.1:6379>objectencodingtest_raw
"embstr"
127.0.0.1:6379>settest_rawzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
OK
127.0.0.1:6379>objectencodingtest_raw
"raw"
127.0.0.1:6379>strlentest_raw
(integer)45
#查看key的内部结构和编码等信息
>debugobjectk4
Valueat:0x7ffc97c044f0refcount:1encoding:embstrserializedlength:3lru:11351195lru_seconds_idle:5363

String类型

string类型属于单值单value,是一个可变的字节数组,就像StringBuilder似的,可以追加、获取长度、截取等操作

扩容:当字符串长度小于1M时,扩容是现有空间进行加倍;当字符串长度超过1M,扩容只会多扩1M的空间。且字符串最长为512M

源码结构

sds.h其内部使用的是SDS简单动态字符串,保存了长度信息,获取字符串长度只需要O(1)

struct__attribute__((__packed__))sdshdr5{
//存储了字符串的类型和长度,3位存类型,5位存长度
unsignedcharflags;/*3lsboftype,and5msbofstringlength*/
charbuf[];
};
//暂时应该是没有用到5的,只用到了8、16、32、64
struct__attribute__((__packed__))sdshdr8{
//header中进行存储len、alloc、flags
//当前使用空间大小,即字符串的长度
uint8_tlen;/*used*/
//去掉header和结尾空字符后的最大空间
uint8_talloc;/*excludingtheheaderandnullterminator*/
//8位的标记,3位存类型,5位没有使用
unsignedcharflags;/*3lsboftype,5unusedbits*/
//数组进行存储
charbuf[];
};
struct__attribute__((__packed__))sdshdr16{
uint16_tlen;/*used*/
uint16_talloc;/*excludingtheheaderandnullterminator*/
unsignedcharflags;/*3lsboftype,5unusedbits*/
charbuf[];
};
struct__attribute__((__packed__))sdshdr32{
uint32_tlen;/*used*/
uint32_talloc;/*excludingtheheaderandnullterminator*/
unsignedcharflags;/*3lsboftype,5unusedbits*/
charbuf[];
};
struct__attribute__((__packed__))sdshdr64{
uint64_tlen;/*used*/
uint64_talloc;/*excludingtheheaderandnullterminator*/
unsignedcharflags;/*3lsboftype,5unusedbits*/
charbuf[];
};
编码格式
编码对象
OBJ_ENCODING_INT使用整数值实现的字符串对象
OBJ_ENCODING_EMBSTR使用embstr编码的简单动态字符串实现的字符串对象
OBJ_ENCODING_RAW使用简单动态字符串实现的字符串对象

string有三种编码格式

  • int 整数值

  • embstr 用于存储短字符串的编码方式,字符串长度小于等于44字节使用,数据保存在一块连续的内存里

  • raw 字符串值长度大于44字节使用

embstr和raw两种编码的区别

embstr编码用于保存短字符串,与raw编码一样,都是使用redisObject结构和sdshdr结构来表示字符串对象,但是raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的内存空间,空间中依次包含redisObject和sdshdr两个结构

操作命令

值拼接


#
给key对应的value进行拼接,返回的是拼接之后的字符长度
appendk1qwe
(integer)5

值长度

strlenk1

数字运算操作

#加一
INCRk2
#减一
DECRk2
#加3,第二个参数是步长
INCRBYk23
#减2,第二个参数是步长
DECRBYk22

注意:这几个命令只能对数字进行操作,范围是Long.MIN~Long.MAX

获取值

getk1

#
只获取该key所对应value的部分字符
getrangek102

判断值是否存在

#返回0则为不存在
existstest

设置值

#setkeyvalue
settest123

#
setrange覆盖部分值其中0为从下标为0的字符开始替换
setrangek10zx
(integer)5

#
设置值时设置过期时间
#setexkeysecondsvalue
setexk320b

#
如果key不存在设置值,防止覆盖(setifnotexists)
#setnxkeyvalue
setnxk11

#
设置key的值,并返回key的旧值
getsetk1vv1

多值操作

#同时set多个键值
#msetkeyvalue[keyvalue...]
msetk4v4k5v5
#同时获取多个键的值
#mgetkey[key...]
mgetk4k5
#同时set多个键值(全部不存在时才会设置值)
#msetnxkeyvalue[keyvalue...]
msetnxk6v6k7k8

List类型

List属于单值多value,链表用的是双向链表结构,list支持pop、push来操作头部和尾部,既可以用做栈也可以用做队列

在3.2版本之前使用的是ziplist和linkedlist,在3.2版本之后使用的是quicklist

源码结构
quicklist结构
typedefstructquicklist{
quicklistNode*head;
quicklistNode*tail;
unsignedlongcount;/*totalcountofallentriesinallziplists*/
unsignedlonglen;/*numberofquicklistNodes*/
intfill:QL_FILL_BITS;/*fillfactorforindividualnodes*/
unsignedintcompress:QL_COMP_BITS;/*depthofendnodesnottocompress;0=off*/
unsignedintbookmark_count:QL_BM_BITS;
quicklistBookmarkbookmarks[];
}quicklist;

typedefstructquicklistNode{
structquicklistNode*prev;
structquicklistNode*next;
unsignedchar*zl;//对应的是ziplist
unsignedintsz;/*ziplistsizeinbytes*/
unsignedintcount:16;/*countofitemsinziplist*/
unsignedintencoding:2;/*RAW==1orLZF==2*/
unsignedintcontainer:2;/*NONE==1orZIPLIST==2*/
unsignedintrecompress:1;/*wasthisnodepreviouscompressed?*/
unsignedintattempted_compress:1;/*nodecan'tcompress;toosmall*/
unsignedintextra:10;/*morebitstostealforfutureusage*/
}quicklistNode;
ziplist结构

压缩的双链表,以连续的空间来表示双链表,节省前驱和后继指针的空间,在小的list上,压缩效率明显,因为在普通的双链表中,前驱和后继指针在64位机器上分别占用8B,在ziplist.h和ziplist.c中定义

typedefstructzlentry{
unsignedintprevrawlensize;/*Bytesusedtoencodethepreviousentrylen*/
unsignedintprevrawlen;/*Previousentrylen.*/
unsignedintlensize;/*Bytesusedtoencodethisentrytype/len.
Forexamplestringshavea1,2or5bytes
header.Integersalwaysuseasinglebyte.*/

unsignedintlen;/*Bytesusedtorepresenttheactualentry.
Forstringsthisisjustthestringlength
whileforintegersitis1,2,3,4,8or
0(for4bitimmediate)dependingonthe
numberrange.*/

unsignedintheadersize;/*prevrawlensize+lensize.*/
unsignedcharencoding;/*SettoZIP_STR_*orZIP_INT_*dependingon
theentryencoding.Howeverfor4bits
immediateintegersthiscanassumearange
ofvaluesandmustberange-checked.*/

unsignedchar*p;/*Pointertotheverystartoftheentry,that
is,thispointstoprev-entry-lenfield.*/

}zlentry;

typedefstruct{
/*Whenstringisused,itisprovidedwiththelength(slen).*/
unsignedchar*sval;
unsignedintslen;
/*Whenintegerisused,'sval'isNULL,andlvalholdsthevalue.*/
longlonglval;
}ziplistEntry;

而对于quicklist编码的定义是

OBJ_ENCODING_QUICKLIST9/*Encodedaslinkedlistofziplists*/
操作命令

设置值

#lpush(指从左边进,头部,先进后出,像栈)
#lpushkeyelement[element...]
lpushlist112345

#
rpush(指从右边进,尾部,先进先出,像队列)
#rpushkeyelement[element...]
rpushlist212345

#
给某个索引位置赋值
#lsetkeyindexelement
lsetlist10q

#
在某个元素之前或之后插入一个元素
#linsertkeybefore|afterpivotelement
linsertlist1beforeqzz

#
获取指定索引的元素,如果使用负数,则从右边开始计算
lindexlist10

取值

#弹出栈顶元素(从左边开始弹出,弹出之后,list中就不存在该元素了)
#lpopkey
lpoplist1
#弹出栈顶元素(从右边开始弹出,弹出之后,list中就不存在该元素了)
#rpopkey
rpoplist1

#
按照索引位置取值
#lindexkeyindex
lindexlist10

#
取值,从头部到尾部
#lrangekeystartend(负下标表示的是从后往前,如-1表示倒数第一)
lrangelist10-1
1)"5"
2)"4"
3)"3"
4)"2"
5)"1"

#
blpop和brpop是阻塞版本
#blpopkeytimeout
#timeout表示列表为空时会等3秒后返回,如果timeout=0,则会一直阻塞下去,直到有数据为止
#如果多个客户端对同一个键执行blpop,那么先执行的blpop命令的客户端可以获取到弹出的值
blpoplist13

列表长度

llenlist1

删除值

#删除几个某个元素count>0时,从左边开始删除;count=0时,删除所有值为element的元素;count<0时,从右边开始删除
#lremkeycountelement
lremlist11"hi"

#
截取指定范围的值赋给key(范围是索引)
#ltrimkeystartstop
ltrimlist100

#
从头部删除元素出栈
lpoplist1
#从尾部删除元素
rpoplist1

出栈入栈

#从源列表右出栈压入左目标列表,将一个列表移至另一个列表
#rpoplpushsourcedest
rpoplpushlist2list1

Set类型

set类型是单值多value,与List的区别在于不可重复,且没有顺序,类似于HashSet,通过hash table实现的

set除了基本的增删改查操作之外,还可以使用集合来取并集、交集、差集,可以用来实现好友推荐等功能

编码格式
编码对象
OBJ_ENCODING_INTSET使用整数集合实现的集合对象
OBJ_ENCODING_HT使用的hash table

set有两种编码格式

  • intset 保存的元素全都是整数,且元素数量不超过512
  • hash table 保存的不是整数
#根据该配置项来进行编码转换的
set-max-intset-entries512
源码结构
intset结构

整数集合

typedefstructintset{
//每个整数的类型
uint32_tencoding;
//intset的长度
uint32_tlength;
//整数数组
int8_tcontents[];
}intset;
操作命令

设置值

#设置值
#saddkeymember[member...]
saddset1vvvcvbvv

取值

#取值,集合中的所有元素
#smemberskey
smembersset1
1)"vc"
2)"vb"
3)"vv"

#
判断该元素是否在set
#sismemberkeymember
sismemberset1vv

#
获取随机的元素,不会删除元素(count表示获取的数量,默认为1)
#srandmemberkey[count]
srandmemberset12

查看集合元素个数

#scardkey
scardset1

删除

#sremkeymember[member...]
sremset1vb

#
随机出栈(默认数量为1)
#spopkey[count]
spopset1

随机抽取

#随机从集合中抽取2个(默认1个)
#srandmemberkey[count]
srandmemberset12
#将源集合中的值移至目标集合
#smovesourcedestmember
smoveset1set2test

差集 交集 并集

#差集返回的是其他key与第一个key的差集,属于A且不属于B的(A-B)
#sdiffkey[key...]
sdiffset1set2

#
交集属于A且属于B的(A∩B)
#sinterkey[key...]
sinterset1set2
#并集属于A或属于B的(A∪B)
#sunionkey[key...]
sunionset1set2

Hash类型

value是键值对,相当于HashMap,对于hash碰撞也是采用的HashMap的处理方式,数组+链表

更适合存储对象,将一个对象存储在hash类型中会占用更少的内存,且可以更方便的存取整个对象

编码格式
编码对象
OBJ_ENCODING_ZIPLIST使用ziplist
OBJ_ENCODING_HT使用的hash table

hash有两种编码格式,当键值对数据量比较小时,使用紧凑的数组格式来节省内存空间

  • ziplist 一开始存储使用的ziplist,但是当满足一定条件时会转换为hash table
  • hash table
#根据该配置项来进行编码转换的
#当hash对象的键值对数量大于该值时使用OBJ_ENCODING_HT编码
hash-max-ziplist-entries512
#当hash对象中的键值对存在键或值的长度大于该值时使用OBJ_ENCODING_HT编码
hash-max-ziplist-value64
源码结构

dict.h

//哈希表结构
typedefstructdictht{
//哈希表数组
dictEntry**table;
//哈希表大小
unsignedlongsize;
//哈希表大小掩码,用于计算索引值
unsignedlongsizemask;
//哈希表已有节点数量
unsignedlongused;
}dictht;
//哈希节点
typedefstructdictEntry{
//键
void*key;
//值
union{
void*val;
uint64_tu64;
int64_ts64;
doubled;
}v;
//下一个哈希节点,链表,可以将多个哈希值相同的键值对进行连接,解决hash冲突的问题
structdictEntry*next;
}dictEntry;
//字典结构
typedefstructdict{
//类型
dictType*type;
//私有数据
void*privdata;
//哈希表
//ht[0]:用来存放真实的数据
//ht[1]:用于扩容
dicththt[2];
//rehash如果为-1表示没有进行rehash
longrehashidx;/*rehashingnotinprogressifrehashidx==-1*/
int16_tpauserehash;/*If>0rehashingispaused(<0indicatescodingerror)*/
}dict;


//处处不同的数据结构,使用不同的hash算法,不同的键值比较算法,不同的析构函数
typedefstructdictType{
//hash函数
uint64_t(*hashFunction)(constvoid*key);
void*(*keyDup)(void*privdata,constvoid*key);
void*(*valDup)(void*privdata,constvoid*obj);
//比较函数
int(*keyCompare)(void*privdata,constvoid*key1,constvoid*key2);
//键值析构函数
void(*keyDestructor)(void*privdata,void*key);
void(*valDestructor)(void*privdata,void*obj);
int(*expandAllowed)(size_tmoreMem,doubleusedRatio);
}dictType;
哈希冲突

redis哈希冲突是使用链地址法进行解决的,将新节点添加在链表的表头

扩容

redis的字典源码中的dictht是一个容量为2的数组,其作用就是用于进行扩容的

//哈希表
//ht[0]:用来存放真实的数据
//ht[1]:用于扩容
dicththt[2];

最初始的数据是存放在ht[0]中的,当要进行扩展或收缩时,ht[1]会根据ht[0]的容量来计算容量,ht[1]扩展的大小是比当前ht[0].used值的两倍大的第一个2的整数幂;收缩的大小是ht[0].used的第一个大于等于的2的整数幂。然后将ht[0]的所有键值重新散列到ht[1]中,重新计算所有的数组下标,当数据迁移完后ht[0]就会释放,然后将ht[1]改为ht[0],为下一次扩展或收缩做准备

由于有时候redis中的数据比较多,不能瞬间完成扩容操作,会将rehash操作进行分步进行,其字段rehashidx就用于标识rehash过程,如果是-1表示当前没有进行rehash操作,当进行rehash操作时会将该值改为0,在进行更新、删除、查询操作时会在ht[0]和ht[1]中都进行,先更新ht[0],在更新ht[1],而进行新增操作就直接新增到ht[1]中,保证ht[0]只减不增,直到rehash完成

操作命令

设置值

#Redis4.0之后可以设置多个值,与hmset功能相同
#hsetkeyfieldvalue[fieldvalue...]
#不区分插入和更新,插入时返回1,更新时返回0
hsetuserid123

#
设置多个字段
#hmsetkeyfieldvalue[fieldvalue...]
hmsetusernamezhangsanage18

#
不存在则设置值
#hsetnxkeyfieldvalue
hsetnxuserid12

获取值

#hgetkeyfield
hgetuserid
#获取多个字段的值
#hmgetkeyfield[field...]
hmgetuseridnamesexage

#
可以获取该key所对应的map
#hgetallkey
hgetalluser

#
获取key对应的map有几个字段
#hlenkey
hlenuser

#
判断该key的某个字段是否存在
#hexistskeyfield
hexistsuserid

#
获取该key下所有的字段
#hkeyskey
hkeysuser

#
获取该key下所有的字段值
#hvalskey
hvalsuser

删除字段值

#支持删除多个字段
#hdelkeyfield[field...]
hdeluserage

数值操作

#加2
#hincrbykeyfieldincrement
hincrbyuserid2

#
减2
#hdecrbykeyfieldincrement
hdecrbyuserid2

Zset类型

zset是sorted set,即有序的集合,在set的基础上加了一个score,类似于TreeSet,使用score来进行排序,也可以根据score的范围来获取元素的列表

原本set值为k1 v1 k2 v2,而zset是k1 score1 v1 k2 score2 v2

底层使用的是dict哈希表和skiplist跳表,dict用来关联value和score,保证value的唯一性,同时通过value可以获取到score。skiplist的作用在于给value排序以及根据score的范围来获取元素列表

编码格式
编码对象
OBJ_ENCODING_ZIPLIST使用ziplist
OBJ_ENCODING_SKIPLIST使用的skiplist

zset有两种编码格式

  • ziplist 满足条件使用ziplist,否则使用skiplist
  • skiplist
#根据该配置项来进行编码转换的
zset-max-ziplist-entries128
zset-max-ziplist-value64
源码结构

跳表skiplist相比一般的链表,有更高的查找效率,效率可以比拟二叉查找树

跳表搜索

在存储时会预先间隔地保存了有序链表的节点,从而在查找时能达到类似于二分搜索的效果,可以节省查找时间,但是浪费了空间,数据只存储了一次,只是指针多次存储了

  • 由多层结构组成
  • 每一层都是一个有序链表
  • 最底层的链表包含了所有元素
  • 如果一个元素出现在leveli的链表中,则它在leveli之下的链表也都会出现
  • 每个节点包含两个指针,一个指向同链表中的下一个元素,一个指向下面一层的元素
typedefstructzset{
//哈希表
dict*dict;
//跳表
zskiplist*zsl;
}zset;

typedefstructzskiplistNode{
//节点数据
sdsele;
//分数
doublescore;
//后继指针
structzskiplistNode*backward;
//前驱指针
structzskiplistLevel{
structzskiplistNode*forward;
//调到下一个数据项需要走几步,计算rank时有用
unsignedlongspan;
}level[];
}zskiplistNode;

typedefstructzskiplist{
//跳表头尾指针
structzskiplistNode*header,*tail;
//跳表长度
unsignedlonglength;
//跳表高度
intlevel;
}zskiplist;
操作命令

设置值

#向zset中添加元素,并且会根据score进行排序,如果元素存在,会更新score
#zaddkeyscoremember[scoremember...]
zaddzset11q2w

取值

#WITHSCORES表示查询结果是否带着score,score从小到大
#zrangekeystartstop[WITHSCORES]
zrangezset10-1

#
WITHSCORES表示查询结果是否带着score,score从大到小
#zrevrangekeystartstop[WITHSCORES]
zrevrangezset10-1

#
根据score范围查询
#zrangebyscorekeyminmax[WITHSCORES][LIMIToffsetcount]
zrangebyscorezset280100

#
根据score的范围来计数
#zcountkeyminmax
zcountzset2010

#
根据值来获取下标(根据score从小到大来排的序)
#zrankkeymember
zrankzset2d

#
根据值来获取下标(根据score从大到小来排的序)
#zrevrankkeymember
zrevrankzset2d

#
获取元素的score
#zscorekeymember
zscorezset2c

查看集合元素个数

#该key的元素个数
zcardzset2

删除

#zremkeymember
zremzset2s

#
根据下标区间来删除(根据score从小到大来排的序)
#zremrangebyrankkeystartstop
zremrangebyrankzset158

#
根据score区间来删除
#zremrangebyscorekeyminmax
zremrangebyscorezset1710

数值操作

#如果key中存在该元素,则该元素的score增加increment,否则新增该元素
#zincrbykeyincrementmember
zincrbyzset12b

Bitmap类型

位图不是一个真实的数据类型,是定义在字符串类型之上的面向位操作的集合,每个单元只能存储0和1。位图的最大优势在于节省空间

127.0.0.1:6379>typebittest
string

设置值

#setbitkeyoffsetvalue
#value只能是0或者1
setbitbittest101

取值

#getbitkeyoffset
#如果offset超出范围的话返回0
getbitbittest10

#
bitcountkey[start][end]
#获取指定范围为1的个数
bitcountbittest01000

bitmap适用于大量数据,少量数据的话会导致大部分位都是0,占用的内存数比集合还多

HyperLogLog类型

HyperLogLog是一种基于字符串类型的基数算法。通过HyperLogLog可以利用极小的内存空间完成独立总数的统计

127.0.0.1:6379>typehpl
string
#添加
#pfaddkeyelement[element...]
pfaddhpl123

#
统计
#pfcountkey[key...]
pfcounthpl

#
合并
#pfmergedestkeysourcekey[sourcekey...]
pfmergedestkeysourcekey1sourcekey2

HyperLogLog非常的节省空间,但是HyperLogLog统计的数据是不准确的

GEO类型

地理信息定位功能,支持存储地理位置信息。其底层是zset

127.0.0.1:6379>typekey
zset
#增加地理位置信息
#longitude经度
#latitude纬度
#member成员
#geoaddkeylongitudelatitudemember[longitudelatitudemember...]
geoaddkey116.2839.55bj

#
获取地理位置信息返回经纬度
#geoposkeymember[member...]
geoposkeybj

#
获取两个地理位置的距离unit为单位包含m米、km千米、mi英里、ft尺
#geodistkeymember1member2[unit]
geodistkeybjsjzkm

#
获取指定位置范围内的地理信息集合
#georadiuskeylongitudelatituderadiusm|km|ft|mi[withcoord][withdist][withhash][COUNTcount][asc|desc][storekey][storedistkey]
#longitudelatitude也可以使用成员来替换,此时使用georadiusbymemberkeymember
#radiusm|km|ft|mi表示半径+单位
#withcoord返回结果中包含经纬度
#withdist返回结果中包含里节点位置的距离
#withhash返回结果中包含geohash
#COUNTcount指定返回的数量
#asc|desc按照距离做升序或者降序
#storekey将返回结果的地理位置信息保存到指定键
#storedistkey将返回结果距离节点距离保存到指定键
georadiusbymemberkeybj250km

#
删除地理位置信息
#zremkeymember

各个类型的场景

  • String:

    • 缓存set key value
    • 分布式锁setnx key value
    • 限流/计数器INCR count DECR count
    • 分布式id 使用INCR来生成idINCR id
    • pv/uv统计 可以使用incr来统计文章的访问量,key设置为post:文章ID:view
    • 分布式session
  • List:

    • 消息队列LPUSH list item +brpop list来实现阻塞队列
    • 评论
    • 热点列表 如微博话题LRANGE list 0 10

    lpush+lpop = 栈

    lpush+rpop = 队列

    lpush+ltrim = 有限集合

    lpush+brpop = 消息队列

  • Set: 点赞、标签

    • 标签 文章标签很多,每个人喜好也很多,推送的时候使用交集SINTER set1 set2 set3
  • Hash: 存储对象

  • Zset: 排行榜

    • ZADD 添加元素
    • ZRANGE 按分数从低到高排列,返回区间内的元素
    • ZREVRANGE 按分数从高到低排列,返回区间内的元素
    • ZRANK 返回某个元素的排名
  • Bitmap

    • 可以用来做布隆过滤器
    • 可以用来统计每天的用户数
  • HyperLogLog

    • 可以用来计算独立总数,但是不可以获取用户id(而且数据存在一定的误差)
  • GEO

    • 可以用来做附近位置等依赖于地理位置的功能

https://zhhll.icu/2021/数据库/非关系型数据库/redis/基础/7.redis数据结构/

本文由 mdnice 多平台发布