文章目录
目录
文章目录
一、Redis是什么?
二、使用步骤
1.编译安装
2.启动与登录
三、Redis数据结构
四、string类型
一、Redis是什么?
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写的Key-Value内存数据库。
Redis应用非常广泛,如Twitter、暴雪娱乐、Github、Stack Overflow、腾讯、阿里巴巴、京
东、华为、新浪微博等,很多中小型公司也在使用。
二、使用步骤
1.编译安装
git clone https://gitee.com/mirrors/redis.git -b 6.2
cd redis
make
make test
make install
# 默认安装在 /usr/local/bin
# redis-server 是服务端程序
# redis-cli 是客户端程序
2.启动与登录
修改redis.conf,把配置文件放到/usr/local/bin/目录下(和redis-server同级目录)
- 可配置登录密码 requirepass 123456
- 可设置为守护进程方式打开: daemonize yes
启动redis:
cd /usr/local/bin
./redis-server
使用客户端登录redis:
cd /usr/local/bin
./redis-cli -h 127.0.0.1 -a 123456
三、Redis数据结构
redis的内部整体的存储结构就是一个大的dict,内部实现是数组实现hash。其中,string/list/hash/set/zset都是该数组的value。
对于地址冲突是通过链地址法解决的
Redis包含五种常用的数据结构:string、list、hash、set、zset
四、string类型
字符串类型是redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据(可存储图片等)。
字符串长度小于1M时,加倍扩容;超过1M每次只多扩1M;
字符串最大长度为512M。
常用操作:
# 设置 key 的 value 值
SET key val
# 获取 key 的 value
GET key
# 执行原子加一的操作
INCR key
# 执行原子加一个整数的操作
INCRBY key increment
# 执行原子减一的操作
DECR key
# 执行原子减一个整数的操作
DECRBY key decrement
# 如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做
SETNX key value
# 删除 key val 键值对
DEL key
# 设置或者清空key的value(字符串)在offset处的bit值。
SETBIT key offset value
# 返回key对应的string在offset处的bit值
GETBIT key offset
# 统计字符串被设置为1的bit数.
BITCOUNT key
string存储结构:
如图所示:
* 当string长度小于等于20,且可以转换为整数时,使用int类型存储
* 当string长度小于等于44时,使用embstr存储
* 当string长度大于44,使用raw存储
思考:为什么使用44为边界(注:redis3.2以前的版本,边界值是39)?这么做有什么好处?
//server.h
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;
void *ptr;
} robj;
//sds.h 大于等于3.2版本
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
// 小于3.2版本
struct sdshdr {
unsigned int len;
unsigned int free;
char buf[];
};
//object.c
/* Create a string object with EMBSTR encoding if it is smaller than
* OBJ_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is
* used.
*
* The current limit of 44 is chosen so that the biggest string object
* we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
robj *createStringObject(const char *ptr, size_t len) {
if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
return createEmbeddedStringObject(ptr,len);
else
return createRawStringObject(ptr,len);
}
从redis源码中可以看到,“The current limit of 44 is chosen so that the biggest string object we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc.”
即EMBSTR适用于redis的内存分配器jemalloc的64字节的分配管理区域arena,也就是说和和jemalloc的机制相关。x64系统中,sizeof(redisObject) = (4+4+24)/8 +4 + 8 = 16 byte, 对于字符串类型,ptr指向sdshdr8结构体,sizeof(sdshdr8) = 1 + 1 +1 + X +1 = 4 byte,此处 X 的最大值就是44 byte。
redis 内存分配器认为 大于 64个字节为大字符串;所以留给小字符串的大小为 64 - 16 - 3 - 1 = 44 (小于3.2版本:64 - 16 - 4 - 4 - 1 = 39) ;
这么做的好处:
查看createStringObject函数可知:
1.embstr申请或释放内存,只需要一次操作(一次性分配 robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1); ),而raw需要两次(一次为raw分配sdshdr对象,另一次为redisObject分配对象(ptr指向sds对象))
2.embstr是内存连续的,读写更高效
应用场景:
累加器:
# 统计阅读数 累计加1
incr reads
# 累计加100
incrby reads 100
分布式锁(该方式不安全,不推荐使用),分布式锁是一个很大的课题,此处不扩展了。
# 加锁
setnx lock 1
# 释放锁
del lock
位运算
# 月签到功能 10001 用户id 202106 2021年6月份的签到 6月份的第1天
setbit sign:10001:202106 1 1
# 计算 2021年6月份 的签到情况
bitcount sign:10001:202106
# 获取 2021年6月份 第二天的签到情况 1 已签到 0 没有签到
getbit sign:10001:202106 2