官网

中文文档

git地址

简介

​ Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。(百度百科)

基础知识

  • Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。
  • redis默认16个数据库,类似数组下表从零开始,默认数据库为0,可以使用SELECT id 命令切换指定数据库。
  • Redis索引都是从零开始
  • 统一密码管理,16个库都是同样密码,要么都OK要么一个也连接不上
  • redis6.0前是单线程的,6.0后支持多线程,默认单线程

redis使用单线程原因

  1. 官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。
  2. 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。
  3. 不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗

Redis的高并发和快速原因

  1. redis是基于内存的,内存的读写速度比硬盘快得多;(CPU高速缓存>内存>外存(硬盘、光盘、U盘等))
  2. redis是单线程的,省去了很多CPU上下文切换线程的时间;(CPU上下文切换是很耗内存的)
  3. redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll(Epoll是Linux内核为处理大批量文件描述符而作了改进的epoll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。)和自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。“多路”指的是多个socket连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。

常用命令

  • keys * :查看所有key(*匹配所有字符,?匹配单个字符,如 keys ?ist可匹配 list,aist,bist……)
  • info 查看redis详细信息,key数量也在里面
  • set key value:存入键值对
  • get key:获取key对应值
  • DBSIZE:查看当前基本数据库大小(当前数据库的key的数量)。
  • Flushdb:清空当前库 | Flushall:通杀全部库
  • exists key : 判断key是否存在(存在返回1,不存在返回2)
  • del key:删除key
  • rename key newname:重命名key
  • move key db_id :将当前数据库的 key 移动到给定的数据库 db 当中。
  • type key :查看当前key存储类型
  • expire key second(秒) 设置超时时间(即几秒后过期)
  • ttl key 查看key剩余时间(-1表示永久有效,-2表示当前key不存在)
  • persist key 移除过期时间,让key永久有效
  • set key value [EX seconds] [PX milliseconds] [NX|XX] (EX 200:200秒后过期,NX:key不存在才操作,XX: key已存在才操作)
  • shutdown:关闭redis

设置修改密码

1.客户端连接修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
##到安装目录下打开命令行
#wingdow下客户端连接 redis-cli.exe -h {ip} -p {端口} [-a {密码}]
#Linux下客户端连接 ./redis-cli -h {ip} -p {端口} [-a {密码}]

##查看密码(默认为空)
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "" //默认空
127.0.0.1:6379>

#设置密码 config set requirepass 123456
127.0.0.1:6379> config set requirepass 123456
OK
127.0.0.1:6379> CONFIG GET requirepass //密码设置后必须先验证通过密码,否则所有命令都不可用
(error) NOAUTH Authentication required.

#验证密码 auth {密码}
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "123456"
127.0.0.1:6379>

2.修改配置文件

1
2
3
4
5
#找到redis.conf配置文件中的requirepass
#requirepass foobared
#去掉注释配置自己密码
requirepass {密码}
保存后重启

五大基本类型

字符串(String)

​ String是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。

​ 底层没有直接使用C字符串(即以空字符’\0’结尾的字符数组)作为默认的字符串表示,而是使用了SDS(简单动态字符串/Simple Dynamic String)

string类型是Redis最基本的数据类型,一个redis中字符串value最多可以是512M

补:String内部编码有三种方式,可使用object encoding key 查看。

  1. int : 长度小于20且保存的是64位有符号整型类型。
  2. embstr:长度小于等于44,对于嵌入式的String,从内存结构上说,就是字符串sds结构体与其对应的redisObject对象分配在同一块连续的内存空间,只需一次内存分配
  3. raw:长度大于44,redisObject内存不在连续,采用指针的形式,实现连接。需要分配两次内存空间(分别为redisObject和sds分配空间)。

注:Redis中每个对象都是由redisObject表示的

image-20210406141632606

常用操作:
  1. append key value :往字符串后面追加字符串(若key不存在,则新建key,相当于set key value)

  2. strlen key :返回字符串长度

  3. incr key: 自增1

  4. decr key:自减1

  5. incrby key num:自增num

  6. decrby key num:自减num

  7. getrange key start end :截取字符串[start,end] [0,-1]表示全部

  8. setrange key start str :用str替换指定位置开始的字符串

  9. setex key seconds value:保存key-value并设置过期时间(set with expire)

  10. setnx key value:不存在则设置(set if not exist),成功返回1,若已存在,则创建失败,返回-1

  11. mset k1 v1 k2 v2 k3 v3:同时设置多个值

  12. mget k1 k2 k3: 同时获取多个值

  13. getset key value:先get后set,如果不存在则返回null,如果存在,则返回旧值,再设置新值

深入理解String

SDS组成结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
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[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
  • len:SDS字符串已使用的空间。
  • alloc:申请的空间,减去len就是未使用的空间,初始时和len一致。
  • flag:只使用了低三位表示类型,细化了SDS的分类,根据字符串的长度的不同选择不同的sds结构体,而结构体的主要区别是len和alloc的类型,这样做可以节省一部分空间大小。
  • buf: 用了C的特性表示不定长字符串。

列表(List)

​ 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。它的底层是压缩列表(ziplist)或双端链表(linkedlist)(Redis3.2后改为快表quicklist,前两个的结合,实际上是个双端链表,链节点上存着压缩列表的引用指针)。

常用操作
  1. LPUSH list value1 value2 value3 …… :将一个或多个值插入列表头部(左部)

  2. LRANGE list start end :[start,end]通过区间获取列表具体值,[0,-1]获取list全部

  3. RPUSH list value1 value2 value3 …… :将一个或多个值插入列表尾部(右部)

  4. LPOP list :移除列表的第一个元素

  5. RPOP list:移除列表的最后一个值

  6. Lindex list index :通过下标获取 元素

  7. Llen list:返回列表长度

  8. Lrem lsit count value:移除list中count个value

  9. ltrim list start end:通过下标截取list,原list已经被改变

  10. rpoplpush sourceList newList:移除sourceList列表的最后一个元素,将他移动到newList列表中

  11. lset list index newvalue: 替换将列表指定下标值(list或index不存在则报错)

  12. linsert list value before|after newValue:将某一个具体的newValue插入到第一个value前面|后面

集合(Set)

Set是string类型的无序集合,不可重复。它是通过整数集合(intset)【当集合中的元素都是整数,且元素个数小于set-max-intset-entries配置值(默认512个)】或哈希表(hashtable)实现的。

常用操作
  1. sadd set value1 value2 value3 ……:往set集合添加元素
  2. smembers set:查看set元素
  3. sismembers set value:是否存在指定元素(存在返回1,不存在返回0)
  4. scard set:查看set集合元素数
  5. srem set value :移除set集合指定元素
  6. srandmember set (count):随机抽取num个元素(count不写默认一个)
  7. spop set (count):随机移除count个元素
  8. smove set1 set2 value:将set1中value移动到set2中
  9. sdiff set1 set2:set1与set2取差集,返回set1中存在,set2不存在的元素集合
  10. sinter set1 set2 :取交集
  11. sunion set1 set2:取并集

哈希(Hash)

hash 是一个键值对集合,是一个string类型的field和value的映射表,hash特别适合用于存储对象。类似Java里面的Map<String,Object>。底层是压缩列表(ziplist)或哈希表(hashtable)实现。

常用操作
  1. hset hash key value :存入hash一个 key-value键值对
  2. hget hash key:获取hash中key的值
  3. hmset hash key1 value1 key2 value2 ……:存入hash多个键值对
  4. hmget hash key1 key2 ……:获取hash多个key字段的值
  5. hgetall hash :获取全部key-value内容
  6. hdel hash key :删除hash中指定key字段
  7. hlen hash :返回hash长度
  8. hexists hash key:判断hash中key字段是否存在
  9. hkeys hash:返回所有key字段
  10. hvals hash:放回所有value
  11. hincrby hash key num:指定key增量num
  12. hsetnx hash key value:不存在则存入

有序集合(Zset)

zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。底层使用压缩列表(ziplist)或跳跃表(skiplist)实现。
redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。

常用操作
  1. ZADD key score1 member1 [score2 member2]:向有序集合添加一个或多个成员,或者更新已存在成员的分数.

  2. ZCARD key 获取有序集合的成员数.

  3. ZCOUNT key min max 计算在有序集合中指定区间分数[min,max]的成员数。

  4. ZINCRBY key increment member:有序集合中对指定成员的分数加上增量 increment。

  5. ZINTERSTORE newkey num key …:计算给定的一个或多(num)个有序集key的交集并将结果集存储在新的有序集合 newkey 中。

  6. ZLEXCOUNT key min max:在有序集合中计算指定字典区间内成员数量。

    min max: { - [a =(-∞,a]; - (a=(-∞,a);[a [b=[a,b];- +=(-∞,+∞)

  7. ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合指定区间内的成员。-inf +inf = -∞ +∞

  8. ZRANGEBYLEX key min max [LIMIT offset count] 通过字典区间返回有序集合的成员。

  9. ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] 通过分数返回有序集合指定区间内的成员。

  10. ZRANK key member 返回有序集合中指定成员的索引。

  11. ZREM key member [member …] 移除有序集合中的一个或多个成员。

  12. ZREMRANGEBYLEX key min max :移除有序集合中给定的字典区间的所有成员。

  13. ZREMRANGEBYRANK key start stop:移除有序集合中给定的排名区间的所有成员。

  14. ZREMRANGEBYSCORE key min max移除有序集合中给定的分数区间的所有成员。

  15. ZREVRANGE key start stop [WITHSCORES]返回有序集中指定区间内的成员,通过索引,分数从高到低。

  16. ZREVRANGEBYSCORE key max min [WITHSCORES]返回有序集中指定分数区间内的成员,分数从高到低排序。

  17. ZREVRANK key member返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序。

  18. ZSCORE key member返回有序集中,成员的分数值。

  19. ZUNIONSTORE destination numkeys key [key …]计算给定的一个或多个有序集的并集,并存储在新的 key 中。

  20. ZSCAN key cursor [MATCH pattern] [COUNT count] 迭代有序集合中的元素(包括元素成员和元素分值)。

​ 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1),其实不太准确。

​ 其实在redis sorted sets里面当items内容大于64的时候同时使用了hash和skiplist两种设计实现。这也会为了排序和查找性能做的优化。所以如上可知:

  • 添加和删除都需要修改skiplist,所以复杂度为O(log(n))。
  • 但是如果仅仅是查找元素的话可以直接使用hash,其复杂度为O(1)
  • 其他的range操作复杂度一般为O(log(n))
  • 当然如果是小于64的时候,因为是采用了ziplist的设计,其时间复杂度为O(n)

五大基本类型底层实现

Snipaste_2021-03-25_00-12-59

hashtable结构图

hashtable结构图

特殊类型

地理空间(geospatial )

​ Redis的Geo,3.2版本推出,可以推算地理位置的信息,两地之间的距离

​ 城市经纬度查询:http://www.jsons.cn/lngcode/

六大操作

geoadd key 经度 维度 坐标名:添加地理位置(两级无法直接添加,可一次添加多个), 先经度后维度(官方文档疑似写错了)

例:geoadd china:city 116.405285 39.904989 beijing 121.4 31.2 shanghai ……

​ key 经度 维度 地理名称

geopos key name1 name2……:获取key中name的地理位置

例:GEOPOS china:city beijing shanghai shenzhen xianggang

georadius key 经度 维度 距离: 以给定的经纬度为中心,找出某一半径内所有的元素

例:GEORADIUS china:city 110 30 1000 km [withcoord] [withdist]

GEORADIUSBYMEMBER key 坐标名(元素名) 距离 :根据给定的元素确定中心点,再进行查找

例:GEORADIUSBYMEMBER china:city beijing 1000 km [withcoord] [withdist]

GEODIST key name1 name2 [单位] :返回指定单位中两个指定成员之间的距离。如果缺少一个或两个成员,该命令将返回NULL。

例:GEODIST china:city beijing xianggang km

GEOHASH key name1 name2……:该命令返回11个字符的Geohash字符串,因此与Redis内部52位表示形式相比,不会损失任何精度。该命令返回一个数组,其中每个元素是与作为参数传递给命令的每个成员名称相对应的Geohash。

返回的Geohashhes具有以下属性:

  1. 以从右侧删除字符来缩短它们。它将失去精度,但仍将指向同一区域。
  2. 可以在geohash.orgURL中使用它们,例如http://geohash.org/<geohash-string>。这是此类URL示例
  3. 前缀相似的字符串在附近,但事实并非如此,前缀不同的字符串也可能在附近。

geo底层实现原理其实是zset,我们可以使用zset命令操作他

zrange key 0 -1:查看地图key中的所有元素

zrem key member:删除key中指定元素

Hyperloglog

简介:Hyperloglog 可用于基数统计(基数:在数学上,是集合论中刻画任意集合集大小的一个概念。即一个集合中不重复的元素数。)

redis2.8.9后更新了hyperloglog数据结构

示例:网页UV

uv(Unique Visitor):网站的独立访客,统计1天内访问某站点的用户数(以cookie为依据);访问网站的一台电脑客户端为一个访客。可以理解成访问某网站的电脑的数量。

访问用户量大的情况下,若用传统的set集合统计将耗费大量内存。使用hyperloglog基数统计占用内存固定,2^64不同的元素,只需要废12kb内存。(官网统计hyperloglog有0.81%的错误率,但在统计UV任务上,我们可以忽略不计)

操作

PFADD keyset value1 value2 value3……往集合keyset中添加元素

PFCOUNT keyset:统计集合keyset的基数

PFMERGE newset keyset1 ketset2:将集合keyset1和keyset2的元素合并(并集)到newset中

Bitmap(位存储)

简介: Biymaps位图,该数据结构都是操作二进制位来记录数据的,就只有0和1两个状态。(适用于只有两个状态的数据)

操作

setbit sign index value:往sign的index(从0开始)位置上存value(0或1)

getbit sign index :获取sign中index位上的值(默认0)

bitcount sign:统计sgin中为1的数量

注:bitcount sign start end 获取sgin中第start字节到end字节的1的数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
127.0.0.1:6379> set k bb
OK
# b的二进制表示0110 0010第7位(从0开始)改为1即为c
127.0.0.1:6379> setbit k 7 1
(integer) 0
127.0.0.1:6379> get k
"cb"
127.0.0.1:6379> setbit k 7 0
(integer) 1
127.0.0.1:6379> get k
"bb"
127.0.0.1:6379> bitcount k 0 0
(integer) 3
127.0.0.1:6379> bitcount k 0 1
(integer) 6
127.0.0.1:6379> bitcount k 0 3
(integer) 6
127.0.0.1:6379>

END