基础知识
Redis是一个开源( BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件MQ,它支持多种类型的数据结构,如字符串(strings) ,散列(hashes) ,列表(lists) ,集合(sets) ,有序集合(sorted sets)与范围查询,bitmaps,hyperloglogs和地理空间( geospatial )索引半径查询。Redis内置了复制(replication),LUA脚本(Luascripting),LRU驱动事件( LRU eviction ),事务(transactions )和不同级别的磁盘持久化( persistence ),并通过Redis哨兵(Sentinel )和自动分区( Cluster )提供高可用性( high availability ) 。
redis用C语言写的,默认有16个数据库,默认使用第0个数据库。
切换数据库命令:select 第几个数据库;
清除当前数据库数据:flashdb
清除所有数据库数据:flashall
注:redis命令不区分大小写
五大数据类型
-
Redis-Key
keys *:查看所有的key
exists name:判断key是否存在 1:存在;0:不存在
move name 1:移除当前key
expire name 5:设置过期时间,秒
ttl name:查看当前key的剩余时间
type name:查看当前key的类型 -
String
append name “zhangsan”:追加字符串;若key不存在,相当于set key
strlen name:获取字符串的长度
incr age:自增1
decr age:自减1
incrby age 10:步长为10的自增
decrby age 10:步长为10的自减
getrange name 2 3:若有name为zhangsan,则输出an;若区间为0到-1,输出整个字符串
setrange name 1 xx:若有name为zhangsan,则输出zxxngsan
setex name 5 “zhangsan”:设置字符串的值并设置过期时间
setnx name “zhangsan”:不存在该key再设置key
mset name “张三” sex “男”:同时设置多个值
mget name age:同时获取多个值
msetnx name “张三” sex “男”:原子性,一起成功或一起失败
getset name “zhangsan”:若没name,输出null;若有name,先获取后赋新值使用场景:计数器:文章阅读量,incr
-
List
lpush namelist “zhangsan”:把值插入列表头部
rpush namelist “zhangsan”:把值插入列表尾部
lrange namelist 0 -1:获取列表所有的值
lpop namelist:移除列表第一个值
rpop namelist:移除列表最后一个值
lindex namelist 0:获取列表该索引处的值
len namelist:获取列表长度
lrem namelist 1 zhangsan:移除列表指定个数的value,精确匹配
ltrim namelist 1 2:若有namelist值为a、b、c、d;输出b、c
rpoplpush list1 list2:若list1值为a、b、c、d;执行rpoplpush list1 list2后,list1值为a、b、c;list2值为d
lset namelist 0 lisi:把列表的第一个值替换成lisi,更新操作
linsert namelist before/after a b:把b插入a的前面或后面list其实是一个双向列表,总两边插入或更新效率最高
使用场景:消息队列,lpush rpop 左进右出 -
Set
set是无序不重复集合sadd nameset zhangsan:集合添加元素
smembers nameset:查看该集合的元素
sissmembers nameset zhangsan :判断zhangsan是否在集合中
scard nameset:查看集合的元素的个数
srem nameset zhangsan:移除集合中指定元素
srandmember nameset 2:随机抽取集合中指定个数的元素,不写数量默认为1
spop nameset 2:随机删除集合中指定个数的元素。数字参数在 3.2+ 版本可用。
smove set1 set2 a:若set1元素为a、b,set2元素为c;执行命令后,set1元素为b,set2元素为a、c
sdiff set1 set2:差集
sinsert set1 set2:交集
sunion set1 set2:并集使用场景:共同好友、共同关注、共同爱好、推荐好友 sinsert
-
Hash
hset namehash filed1 zhangsan:set一个key-value
hget namehash filed1:获取该哈希filed1对应的值
hset namehash filed1 a filed2 b:set多个key-value
hget namehash filed1 filed2:获取多个值
hgetall namehash:获取全部值
hdel namehash filed1:删除hash指定键值
hlen namehash:获取哈希表的长度
hexists namehash filed1:判断该哈希是否含该键
hkeys namehash:获取所有的key
hvals namehash:获取所有的value
hincrby、hsetnx:用法和String一样 -
ZSet
有序集合zdd nameset 1 a:添加值
zdd nameset 1 a 2 b:添加多个值
zrange nameset 0 -1:获取值排序:若zdd nameset 1 a 2 b 3 c:
zrangebyscore nameset -inf +inf:显示所有元素,升序
zrangebyscore nameset -1 0:显示所有元素,升序
zrerange nameset +inf -inf:显示所有元素,降序
zrerange nameset 0 -1:显示所有元素,降序
zrangebyscore nameset -inf +inf withscores:显示所有元素,升序,带分数zrem nameset zhangsan:移除集合中指定的元素
zcard nameset:获取集合个数
zcount nameset 1 5:获取指定分数区间内的元素使用场景:
- 成绩表、工资表等排序
- 权重:1为重要消息,2为次要消息,3为普通消息
- 排行榜
geospatial地理位置
- 添加城市经纬度:GEOADD key longitude latitude member
geoadd china:city 116.40 39.90 beijing # 单条添加城市经纬度 geoadd china:city 127.47 31.23 shanghai 120.16 30.24 hangzhou # 多条添加城市经纬度
- 获取城市经纬度:GEOPOS key member
geopos china:city beijing # 获取一个城市经纬度 geopos china:city shanghai hangzhou # 获取多个城市经纬度
- 查看两个城市间的距离:GEODIST key member1 member2 [m|km|ft|mi]
m :米,默认单位。
km :千米。
mi :英里。
ft :英尺。geodist china:city beijing shanghai km# 获取北京到上海直线剧离多少千米
- 以给定的经纬度为中心,找出某一半径内的元素:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
m :米,默认单位。
km :千米。
mi :英里。
ft :英尺。
WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
WITHCOORD: 将位置元素的经度和维度也一并返回。
COUNT 限定返回的记录数。
ASC: 查找结果根据距离从近到远排序。
DESC: 查找结果根据从远到近排序。georadius china:city 116 39 100 km # 以116 39为中心,查询方圆100km内的城市 georadius china:city 116 39 100 km withdist # 返回距离 georadius china:city 116 39 100 km withcoord # 将位置元素的经度和维度也一并返回 georadius china:city 116 39 100 km count 1 # 只查一个
- 找出指定元素周围的其他元素:GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
注:用法和georadius一样georadiusbymember china:city beiijing 100 km # 以北京为中心,查询方圆100km内的城市
注:geo底层是zset,可以用zset命令操作geo
应用场景:好友定位、附近的人、打车距离
HyperLogLog基数统计
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。若用普通的set,消耗的资源将是巨大的。
注:HyperLogLog 不会保存实际的值,只是计数,错误率仅约为0.81%(可以忽略)
- 什么是基数:
数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。
pfadd mykey a b c d e f # 创建
pfcount mykey # 查看基数数量
pfadd mykey2 e f g h #
pfmerge mykey3 mykey mykey2 # 合并基数
应用场景:网页记录浏览量
Bitmaps位存储
存储一次占一个bit,一字节=8bit,统计只有0或1两种状态的适合用Bitmaps,节省空间
setbit login 1 0 # 设置第一天未登录
setbit login 2 0 # 设置第二天未登录
setbit login 3 1 # 设置第三天已登录
getbit login 3 # 输出 1
bitcount login # 统计登陆的天数,输出1
应用场景:统计用户打卡未打卡,登陆未登陆,活跃不活跃;0和1两个状态的
事务
一个事务中的所有命令都会被序列化。
Redis单条命令保证原子性,但事务不能保证原子性!
Redis事务没有隔离级别的概念。
所有命令在事务中实际没有执行,当发起执行命令时才执行:exec
一个事务从开始到执行会经历以下三个阶段:
- 开始事务(multi)
- 命令入队
- 执行事务(exec)
>multi # 开启事务
ok
>set k1 v1
QUEUED
>get k1
QUEUED
>set k2 v2
QUEUED
>exec # 执行事务
1)ok
2)v1
3)ok
discard:取消事务(事务中的命令都不会被执行)
异常:
- 编译型异常:命令有问题,事务中所有命令都不会被执行
- 运行时异常:若事务中存在语法性,执行命令时,其他命令正常执行,错误命令抛异常,因此redis的事务不能保证原子性
watch监控:
watch可以当作redis的乐观锁操作
>set money 100
ok
>set out 0
ok
>watch money # 监视money对象
ok
>multi
ok
>decrby money 10
QUEUED
>incrby out 10
QUEUED
>exec
1)80
2)20
若事务执行完之前,money被修改了,watch会监视到修改,事务执行失效
配置文件
INCLUDES、MODULES
NETWORK网络
GENERAL通用
SNAPSHOTTING快照
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件.rdb. aof
redis是内存数据库,若没有持久化,断电即失
REPLICATION主从复制
SECURITY
CLIENTS客户端
MEMORY MANAGEMENT内存管理
volatile-lru -> 对设置了过期时间的keys适用LRU淘汰策略
allkeys-lru -> 对所有keys适用LRU淘汰策略
volatile-lfu -> 对设置了过期时间的keys适用LFU淘汰策略
allkeys-lfu -> 对所有keys适用LFU淘汰策略
volatile-random -> 对设置了过期时间的keys适用随机淘汰策略
allkeys-random -> 对所有keys适用随机淘汰策略
volatile-ttl -> 淘汰离过期时间最近的keys
noeviction -> 不淘汰任何key,仅对写入操作返回一个错误
APPEND ONLY MODE aof模式
线程
-
6.0之前:
官方表示,redis是基于内存操作,所以CPU不是redis的瓶颈,redis的瓶颈是机器的内存和网络的带宽,所以能用单线程就用单线程了。注:多线程可能会导致 上下文切换(耗时),效率不一定比单线程高
redis将数据放到内存中,所以说单线程效率是最高的,对于内存来说,没有上下文切换效率就是最高的
-
6.0之后:
redis6.0引入了多线程。原因:在更大的QPS(每秒请求数)下,多线程任务可以分摊 Redis 同步 IO 读写负荷。
Redis6.0的多线程默认是禁用的,只使用主线程。
需开启需要修改redis.conf配置文件的io-threads-do-reads改为yes。
开启多线程后,还需要设置线程数,否则是不生效的,修改redis.conf配置文件的io-threads,官方的建议:4核的机器建议设置为2或3个线程,8核的建议设置为6个线程,线程数一定要小于机器核数。
主从复制
哨兵模式
集群
压力测试
redis-benchmark:redis自带的性能测试工具
压测命令:redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 10000
接下来测试一下50万并发: