1.安装
yum -y install gcc gcc-c++
wget https://github.com/redis/redis/archive/7.2.4.tar.gz
tar -zxvf redis-7.2.4.tar.gz
cd redis-7.2.4
make
make install PREFIX=/usr/local/redis
mkdir -p /usr/local/redis/conf/
mkdir -p /usr/local/redis/log/
cp redis.conf /usr/local/redis/conf
更改配置文件
设置密码
sed -i "s/# requirepass foobared/requirepass 123456/g" /usr/local/redis/conf/redis.conf
设置守护进程
sed -i "s#daemonize no#daemonize yes#g" /usr/local/redis/conf/redis.conf
设置日志路径
sed -i 's#logfile ""#logfile "/usr/local/redis/log/redis.log"#g' /usr/local/redis/conf/redis.conf
启动
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
/usr/local/redis/bin/redis-cli
auth 123456
简单字符串
2.redis的数据结构
数据类型数据结构实现的对应关系
1.简单动态字符串(Simple Dynamic String)
struct sdshdr {
len = 11;
free = 0;
buf = "hello world\0";
}
len位实际占用,free位剩余,buf位柔性数组,长度为len+1 allocate位 len+1+free
append且free不够的情况
buf是一个柔性数组(Flexible Array Member),最大的长度为10241024=1M,当执行append操作时,如果newstrlen< 1M redis会动态2newstrlen +1 ,比如追加" happy",如果大于或等于1M,则redis会开辟 newstrlen +1M +1
newstrlen< 1M 情况
newstrlen = 11 + 6 = 17
allocate内存 =newstrlen*2 +1 = 35
新free = allocate -1 - newstrlen = 34 - 17 = 17
所以新结构体为:
struct sdshdr {
len = 17 ;
free = 17;
buf = "hello world happy\0";
}
newstrlen > 1M 情况
newstrlen = 11 + 1024*1024
allocate内存 11 + 10241024 + 10241024 + 1
新free = allocate -1 - newstrlen = 11 + 10241024 + 10241024 + 1 -11 - 10241024 -1 - 10241024 =1M
所以新结构体位:
struct sdshdr {
len = 11 + 1024*1024 ;
free = 1M;
buf = "hello world happy xxxxxxxxxxxxxx......\0";
}
append且free够的情况
如果再追加一个 "!" ,则
struct sdshdr {
len = 18 ;
free = 16;
buf = "hello world happy!\0";
}
2.跳跃表(skiplist)
本质是一种分层有序链表
举例:
以查找31举例
查找原则是聪第1个节点最高层开始,依次往右查找,当遇到下一层节点的值为null或者大于要查找的值时候,往下查找。
跳跃表的结构为:
typedef struct zskiplist {
// 表头节点和表尾节点
struct zskiplistNode *header, *tail;
// 表中节点的数量
unsigned long length;
// 表中层数最大的节点的层数
int level;
} zskiplist;
header指向头节点
tail指向未接点
length为节点数量
level为节点最高层级
跳跃表的节点结构为:
typedef struct zskiplistNode {
// 成员对象
robj *obj;
// 分值
double score;
// 后退指针
struct zskiplistNode *backward;
// 层
struct zskiplistLevel {
// 前进指针
struct zskiplistNode *forward;
// 跨度
unsigned int span;
} level[];
} zskiplistNode;
obj:节点对象
score:节点数值
backward: 指向上一个节点,首节点和第一个节点指向null
zskiplistLevel:柔性动态数字组,元素的值是节点的值每一层有一个指向下一个节点的指针。
forward:指向下一个节点,最后一个节点指向null
span:两个节点的距离,即跨度
3.压缩列表(ziplist)
ziplist是一种经过特殊编码的,由连续多个内存块组成的顺序型数据结构。
struct ziplist<T> {
int32 zlbytes; // 整个压缩列表占用字节数
int32 zltail_offset; // 最后一个元素距离压缩列表起始位置的偏移量,用于快速定位到最后一个节点
int16 zllength; // 元素个数
T[] entries; // 元素内容列表,挨个挨个紧凑存储
int8 zlend; // 标志压缩列表的结束,值恒为 0xFF
}
struct entry {
int<var> prevlen; //前一个元素长度,用于快速定位到下一个元素的位置
int<var> encoding; //元素类型编码
optional byte[] content; //内容
}
4.整数集合(intset)
显而易见的是适用于一个集合只包含整数的情况,并且intset不会出现重复的元素
typedef struct intset{
//编码方式
uint32_t encoding;
//集合包含的元素数量
uint32_t length;
//保存元素的数组
int8_t contents[];
}intset;
5.字典(hash)
也称为哈希表(Hash Table),勇于存储键值对。
typedef struct dictht {
// 哈希表节点指针数组(俗称桶,bucket)
dictEntry **table;
// 指针数组的大小
unsigned long size;
// 指针数组的长度掩码,用于计算索引值
unsigned long sizemask;
// 哈希表现有的节点数量
unsigned long used;
} dictht;
table是一个数组,每一个元素都指向一个dictEntry的指针
size是table数组的大小
sizemask = size - 1
used 是现有节点的数量
dictEntry
typedef struct dictEntry {
void *key; // key
union {
void *val;// value
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next; // 下一个节点
} dictEntry;
键值
6.快表
3.2版本使用快速列表(quicklist)代替了压缩列表(ziplist)和链表(linkedlist)。
快表是由多个快速列表结点构成的一个双向列表,每一个快速列表节点都保存了一个压缩列表
quicklist表头结构
typedef struct quicklist {
//指向头部(最左边)quicklist节点的指针
quicklistNode *head;
//指向尾部(最右边)quicklist节点的指针
quicklistNode *tail;
//ziplist中的entry节点计数器
unsigned long count; /* total count of all entries in all ziplists */
//quicklist的quicklistNode节点计数器
unsigned int len; /* number of quicklistNodes */
//保存ziplist的大小,配置文件设定,占16bits
int fill : 16; /* fill factor for individual nodes */
//保存压缩程度值,配置文件设定,占16bits,0表示不压缩
unsigned int compress : 16; /* depth of end nodes not to compress;0=off */
} quicklist;
quicklist节点结构
typedef struct quicklistNode {
struct quicklistNode *prev; //前驱节点指针
struct quicklistNode *next; //后继节点指针
//不设置压缩数据参数recompress时指向一个ziplist结构
//设置压缩数据参数recompress指向quicklistLZF结构
unsigned char *zl;
//压缩列表ziplist的总长度
unsigned int sz; /* ziplist size in bytes */
//ziplist中包的节点数,占16 bits长度
unsigned int count : 16; /* count of items in ziplist */
//表示是否采用了LZF压缩算法压缩quicklist节点,1表示压缩过,2表示没压缩,占2 bits长度
unsigned int encoding : 2; /* RAW==1 or LZF==2 */
//表示一个quicklistNode节点是否采用ziplist结构保存数据,2表示压缩了,1表示没压缩,默认是2,占2bits长度
unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */
//标记quicklist节点的ziplist之前是否被解压缩过,占1bit长度
//如果recompress为1,则等待被再次压缩
unsigned int recompress : 1; /* was this node previous compressed? */
//测试时使用
unsigned int attempted_compress : 1; /* node can't compress; too small */
//额外扩展位,占10bits长度
unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;
压缩过的ziplist结构——quicklistLZF
typedef struct quicklistLZF {
//表示被LZF算法压缩后的ziplist的大小
unsigned int sz; /* LZF size in bytes*/
//保存压缩后的ziplist的数组,柔性数组
char compressed[];
} quicklistLZF;
7.消息队列
Redis5.0 中还增加了一个数据结构Stream,从字面上看是流类型,但其实从功能上看,应该是Redis对消息队列(MQ,Message Queue)的完善实现。
Consumer Group :消费组,使用 XGROUP CREATE 命令创建,一个消费组有多个消费者(Consumer), 这些消费者之间是竞争关系。
last_delivered_id :游标,每个消费组会有个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。
消息队列相关命令
xadd 添加信息到末尾
xtrim 对流进行裁剪,限制长度(超出的元素会被舍弃)
xdel 删除信息
xlen 获取消息队列的长度
xrange 获取消息列表,会自动过滤掉已经被删除的信息(这个只是获取,XRANGE key start end [COUNT count] )
xreverange 反向获取消息
xread 以阻塞或非阻塞的方式获取消息列表(消费信息)
消费者组的相关命令
xgroup create 创建消费者组
xreadgroup group 读取消费组中的信息
xack 已处理
xgroup setid 为消费者组设置最后递送的消费id,通常勇于重新处理信息用
xgroup delconsumer 删除消费者信息
xpending 显示待处理信息的相关信息
xclaim 转移消费者组的相关信息
xinfo groups 打印消费者组的信息
xinfo stream 打印流信息
8.HyperLogLog
基础统计,用来去重的
PFADD
PFCOUNT
PFMERGE