一、Redis简介
1 Redis是什么?
Redis是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
2 Redis的特征
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
3 Redis的应用场景
- 热点数据加快查询(主要查询)如热点商品、热点信息等访问量较高的数据
- 即是信息查询,如公交到站信息、在线人数信息等
- 时效性信息控制,如验证码控制,投票控制等
- 分布式数据共享,如分布式集群架构中的session分离消息队列
4 Redis的优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
5 Redis命令行工具redis-cli
6 Redis基础命令
-
Redis采用单线程机制进行工作的。为什么?
-
Redis默认拥有16个数据库,数据库编号从0开始,默认使用0号数据库。为什么?
-
使用select 数据库编号 可以切换使用的数据库
127.0.0.1:6379> select 3
-
dbsize 命令查看当前数据库key的数量
127.0.0.1:6379[3]> dbsize
-
keys * 命令查看当前数据库所有的key
127.0.0.1:6379[3]> keys *
-
flushdb 命令清空当前数据库
127.0.0.1:6379[3]> flushdb
-
flushall 命令清空所有数据库
127.0.0.1:6379[3]> flushdball
-
Redis中所有数据库使用同一个密码,默认没有密码,Redis认为安全层面应该由Linux来保证
-
Redis中所有索引都是从0开始
-
Redis默认端口是6379
-
查看redis的运行端口
ps -ef|grep redis
7 Redis的数据类型及其查询语句
- key(键)
set name wwj#set key
keys *#查询所有的key
exists name #判断key:name是否存在
move name#移除key:name
expire name 10#设置key的过期时间
ttl name #查看当前key的过期时间
type name#查看当前key的一个类型
Redis有五大数据类型:String 、 List 、Set 、Zset 、Hash。
注意:Redis采用键值对存储数据,key永远都是String类型,五大数据类型指的是value部分
-
String(字符串)
一个key对应一个value;String可以包含任何数据,比如jpg图片等;String是Redis最基本的 数据类型,一个String的value最大可支持512M
String类型的查询语句1.存一个值: set k v 取值: get k 追加(不存在则创建):append k hello 长度:strlen k 2.存取多个值:mset k1 v1 k2 v2 取多个值:mget k1 k1 3.存取并赋值:getset k v 取值:get k 4.删除:del k 5.数值递增:incr num 指定数值递增:incrby num 2 6.数值递减:decr num 指定数值递减:drcrby num 2
-
List(列表)
列表的底层是一个字符串链表;可以从头或尾添加元素。
注意
(1)添加元素时
添加元素时,如果key不存在,创建新的链表
如果key已存在,添加内容
如果key的所有值全部消失,则对应的key也会消失
(2)在链表的头尾操作时的效率较高,但是对中间元素的操作效率较低
List列表的查询语句1.向左边列表增加元素:lpush agelist 1 2 3 查看元素:lrange 0 2 或者lrange 0 -1 2.向右边列表增加元素:rpush agelist 1 2 3 查看元素:lrange 0 2或者lrange 0 -1 3.左移除并返回元素:lpop agelist 3 4.右移除并返回元素:rpop agelist 3 5.特点:有序可重复
-
Set(集合)
Set集合底层是通过Hash Table实现,是String类型的无重复值的无序集合。不重复,无序
Set集合的查询语句1.添加元素:sadd list 1 查看元素:smembers list 2.删除元素:srem list 1 3.查看元素是否在集合中:sismembers list 1 4.集合运算: 差集运算: sadd seta 1 2 3 sadd setb 2 3 4 sdiff seta setb 交集运算: sinter seta setb 并集运算: sunion seta setb 5.特点:集合类型无序 不可重复
-
Zset(有序集合)
类似Set,每个元素都会关联一个double类型的分数(score),redis通过分数自动给集合中的成员进行从小到大的排序,成员不可重复,分数可以重复
mset集合的查询语句1.增加元素:zadd testscore 80 zhangsan 90 lisi 获取元素:zscore testscore lisi 2.删除元素:zrem testscore lisi 3.获取排名列表(默认从小到大):zrange testscore 0 2或者0 -1 在获取排名的同时显示分数:zrange 0 -1 WITHSCORES 4.排名(默认从0开始):zrank testscore li 5.特点:是有序集合 可以排序
-
Hash(哈希)
类似Java中的Map<String,Object>,是一个键值对集合,适合存储对象
Hash散列集合的查询语句1.存一个值:hset user username xiaoming 取值:hget user username 2.存取多个值:hmset user username xiaoming age 12 取多个值:hmget user username age 3.取出所有值:hgetall 4.增值:hincrby user age 12 5.减值:hdecrby user age 4 6.删除字段:hdel user username 7.是否存在字段:hexists user hobby 8.特点:可以存储对象 给对象赋值
-
单指令和多指令的选择
对set与mset两个指令,应该使用哪一个具体的业务场景决定
(1)set指令的执行过程
set指令发送给Redis服务器需要一个网络时间;Redis服务器执行该指令需要一个处理时间; Redis服务器将结果返回需要一个网络时间;故需要2个网络时间 + 1个处理时间
(2)使用set存储n个值
n个网络时间(发送) + n个处理时间(处理) + n个网络时间(返回)
(3)使用mset存储n个值
1个网络时间(发送) + n个处理时间(处理) + 1个网络时间(返回)
注:每个携带的数据增多,网络时间会相应的延长
综上所述,当需要处理的数据较少时,使用单指令;当处理的数据较多时,使用多指令。
8 三大特殊数据类型
8.1 geospatial地理位置
- 应用场景
附近的人,朋友圈的地理位置,打车的距离。这个功能可以推算出地理位置,两地之间的距离,方圆几里的人。 - 相关命令
- GEOADD
- GEODIST
- GEOHASH
- GEOPOS
- GEORADIUS
- GEORADISEBYMEMBER
- GEOADD
将指定的地理位置(纬度,经度,名称)添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBMEMBER命令对数据进行半径查询等操作。
返回值:
添加到sorted set元素的数目,但不包括已更新score的元素。
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
redis> GEODIST Sicily Palermo Catania
redis> GEORADIUS Sicily 15 37 200 km
- GEODIST
返回两个给定位置之间的距离。
如果两个位置之间得到其中一个不存在,那么命令返回空值
指定单位的参数unit必须是下面其中一个
- m:米
- km:千米
- mi:赢利
- ft:英尺
GEODIST 命令在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差。
返回值:
计算出的距离会以双精度浮点数的形式被返回。 如果给定的位置元素不存在, 那么命令返回空值。
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEODIST Sicily Palermo Catania
"166274.15156960039"
redis> GEODIST Sicily Palermo Catania km
"166.27415156960038"
redis> GEODIST Sicily Palermo Catania mi
"103.31822459492736"
redis> GEODIST Sicily Foo Bar
(nil)
redis>
- GEOHASH
返回一个或多个位置元素的Geohash表示
通常使用表示位置的元素使用不同的技术,使用GeoHash位置52点整数编码。
返回值:
一个数组, 数组的每个项都是一个 geohash 。 命令返回的 geohash 的位置与用户给定的位置元素的位置一一对应。
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEOHASH Sicily Palermo Catania
1) "sqc8b49rny0"
2) "sqdtr74hyu0"
redis>
- GEOPOS
从key里返回所有给定位置元素的位置(经度和纬度)。
返回值:
GEOPOS 命令返回一个数组, 数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 而第二个元素则为给定位置元素的纬度。
当给定的位置元素不存在时, 对应的数组项为空值。
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEOPOS Sicily Palermo Catania NonExisting
1) 1) "13.361389338970184"
2) "38.115556395496299"
2) 1) "15.087267458438873"
2) "37.50266842333162"
3) (nil)
redis>
- GEORADIUS
以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
范围可以使用以下其中一个单位:
- m 表示单位为米。
- km 表示单位为千米。
- mi 表示单位为英里。
- ft 表示单位为英尺。
在给定以下可选项时, 命令会返回额外的信息:
- WITHDIST: 在返回位置元素的同时, 将位置元素与中心
- 间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
- WITHCOORD: 将位置元素的经度和维度也一并返回。
- WITHHASH: 以 52 位有符号整数的形式, 返回位置元
- 经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式: - ASC: 根据中心的位置, 按照从近到远的方式返回位置元素。
- DESC: 根据中心的位置, 按照从远到近的方式返回位置元素。
返回值
- 在没有给定任何 WITH 选项的情况下, 命令只会返回一个像 [“New York”,”Milan”,”Paris”] 这样的线性(linear)列表。
- 在指定了 WITHCOORD 、 WITHDIST 、 WITHHASH 等选项的情况下, 命令返回一个二层嵌套数组, 内层的每个子数组就表示一个元素。
在返回嵌套数组时, 子数组的第一个元素总是位置元素的名字。 至于额外的信息, 则会作为子数组的后续元素, 按照以下顺序被返回:-
以浮点数格式返回的中心与位置元素之间的距离, 单位与用户指定范围时的单位一致。
-
geohash 整数。
-
由两个元素组成的坐标,分别为经度和纬度。
举个例子:["Palermo","190.4424",["13.361389338970184","38.115556395496299"]]
-
例子
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEORADIUS Sicily 15 37 200 km WITHDIST
1) 1) "Palermo"
2) "190.4424"
2) 1) "Catania"
2) "56.4413"
redis> GEORADIUS Sicily 15 37 200 km WITHCOORD
1) 1) "Palermo"
2) 1) "13.361389338970184"
2) "38.115556395496299"
2) 1) "Catania"
2) 1) "15.087267458438873"
2) "37.50266842333162"
redis> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD
1) 1) "Palermo"
2) "190.4424"
3) 1) "13.361389338970184"
2) "38.115556395496299"
2) 1) "Catania"
2) "56.4413"
3) 1) "15.087267458438873"
2) "37.50266842333162"
redis>
-
GEORADISEBYMEMBER
这个命令和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS 那样, 使用输入的经度和纬度来决定中心点
指定成员的位置被用作查询的中心。redis> GEOADD Sicily 13.583333 37.316667 "Agrigento" (integer) 1 redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" (integer) 2 redis> GEORADIUSBYMEMBER Sicily Agrigento 100 km 1) "Agrigento" 2) "Palermo" redis>
8.2 hyperloglog
8.3 bitmaps
8 综合案例
- 业务场景
在微信聊天过程中,当接收到信息时,会将最新的消息显示在窗口顶端,当收到不同消息时,会因为是否顶置以及消息到达的先后顺序产生不同的显示顺序。 - 业务分析
假设a这位用户将与b与c两位好友消息顶置,当收到多个好友的消息时,它的微信聊天窗口会产生怎样的显示顺序呢? - 解决思路
(1)将b与c两位用户放入set中(因为不重复),表示置顶好友
(2) 创建两个list列表(因为有顺序),分别表示置顶用户的消息列表与非置顶用户的消息列表
(3) 将上述两个list列表当作栈来使用
(4)当d用户给a发送消息时,检测到d用户并不属于set集合,将其压入普通list栈中
(5)当e用户和b用户给a发送消息时,同理得图
(6)当d用户再次给a发送消息时,判断得到d的消息需要压入普通list栈中,首先将栈 中原来存在的d用户删除,此时e用户到达原来d用户的位置,然后将新的d用 户的消息压入栈中
9 Redis中key的查询语法
10 Jedis的使用
11 持久化知识
11.1 概念
利用磁盘将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化
11.2 持久化流程(保存数据在磁盘)
- 客户端向服务端发送写操作(数据在客户端的内存中)。
- 数据库服务端接收到写请求的数据(数据在服务端的内存中)。
- 服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。
- 操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。
- 磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。
这5个过程是在理想条件下一个正常的保存流程,但是在大多数情况下,我们的机器等等都会有各种各样的故障,这里划分了两种情况:
- Redis数据库发生故障,只要在上面的第三步执行完毕,那么就可以持久化保存,剩下的两步由操作系统替我们完成。
- 操作系统发生故障,必须上面5步都完成才可以。
11.3 实现持久化的两种方式
(1)快照
将某个时间点的工作状态保存下来,恢复时间可直接恢复时间点的工作状态,Redis中称这种方式为RDB(Redis DataBase)
(2)日志
将对数据的所有操作过程记录下来,恢复数据时重新执行这些操作,Redis中称这种方式为AOF(Append Only File)
12 Redis的性能测试redis-benchmark
12.1 介绍
redis-benchmark是一个压力测试工具!官方自带的性能测试工具!
12.2 命令格式
redis-benchmark [参数] [参数的值]
执行redis-benchmark需要到/usr/local/bin这个目录中;
12.3 简单测试
#测试:100个并发连接 100000请求
./redis-benchmark -h localhost -p 6379 -c 100 -n 100000
参考链接:Redis常见的面试题硬核整理