概念
Redis 是一个开源的,内存中的数据结构存储系统,单线程、它可以用作数据库、缓存和消息中间件。
默认有16个数据库
Redis为什么单线程还快?
误区:1有人会认为高性能的服务器一定是多线的?
高性能的服务器不一定是多线程的
2多线程(使用多线程会去用cpu调度上下文的切换)一定比单线程效率高
cpu>内存>硬盘
核心:Redis是将所有的数据放在内存中的,所以说使用单线程操作效率就是最高的。为什么呢?因为多线程会产生cpu的上下文切换这是一个耗时的操作,对于内存系统来说,根本就没有上下文切换,所以效率就是最高的!多次读写都是在一个cpu上,所以说在内存情况下,所以这个就是最佳方案
速度快:
tomcat: 150-220/秒
nginx: 3-5万/秒
redis: 写 8.6万/秒 读 11.2万/秒 ~ 平均10万次/秒
特性
- 多样的数据类型
- 持久化
- 集群
- 事务
- 主从复制
Redis数据类型有哪些?
Redis五大基本数据类型
String(字符串)
list(列表)
set(集合)
zSet(有序列表)
hash(散列表)
三大特殊类型:
geo
hyperloglog
bitmap
Redis中的常用命令哪些?
incr 让当前键值以1的数量递增,并返回递增后的值
incrby 可以指定参数一次增加的数值,并返回递增后的值
incrby 可以指定参数一次增加的数值,并返回递增后的值
decrby 可以指定参数一次递减的数值,并返回递减后的值
incrbyfloat 可以递增一个双精度浮点数
append 作用是向键值的末尾追加value。如果键不存在则将该键的值设置为value。返回值是追加后字符串的总长度。
mget/mset 作用与get/set相似,不过mget/mset可以同时获得/设置多个键的键值
del 根据key来删除value
flushdb 清除当前库的所有数据
hset 存储一个哈希键值对的集合
hget获取一个哈希键的值
hmset 存储一个或多个哈希是键值对的集合
hmget 获取多个指定的键的值
hexists 判断哈希表中的字段名是否存在 如果存在返回1 否则返回0
hdel 删除一个或多个字段
hgetall 获取一个哈希是键值对的集合
hvals 只返回字段值
hkeys 只返回字段名
hlen 返回key的hash的元素个数
lpush key value向链表左侧添加
rpush key value向链表右侧添加
lpop key 从左边移出一个元素
rpop key 从右边移出一个元素
llen key 返回链表中元素的个数 相当于关系型数据库中 select count()
lrange key start end lrange命令将返回索引从start到stop之间的所有元素。Redis的列表起始索引为0。
lrange也支持负索引 lrange nn -2 -1 如 -1表示最右边第一个元素 -2表示最右边第二个元素,依次类推。
lindex key indexnumber 如果要将列表类型当做数组来用,lindex命令是必不可少的。lindex命令用来返回指定索引的元素,索引从0开始
如果是负数表示从右边开始计算的索引,最右边元素的索引是-1。
Lset key indexnumber value 是另一个通过索引操作列表的命令,它会将索引为index的元素赋值为value。
sadd key value 添加一个string元素到,key对应的set集合中,成功返回1,如果元素已经在集合中返回0
scard key 返回set的元素个数,如果set是空或者key不存在返回0
smembers key 返回key对应set的所有元素,结果是无序的
sismember key value 判断value 是否在set中,存在返回1,0表示不存在或者key不存在
srem key value 从key对应set中移除给定元素,成功返回1,如果value 在集合中不存在或者key不存在返回0
zadd key score value 将一个或多个value及其socre加入到set中
zrange key start end 0和-1表示从索引为0的元素到最后一个元素(同LRANGE命令相似)
zrange key 0 -1 withscores 也可以连同score一块输出,使用WITHSCORES参数
zremrangebyscore key start end 可用于范围删除操作
ping 测试redis是否链接 如果已链接返回 PONG
echo value测试redis是否链接 如果已链接返回 echo命令后给定的值
keys * 返回所有的key 可以加通配
exists key判断string类型一个key是否存在 如果存在返回1 否则返回0
expire key time(s) 设置一个key的过期时间 单位秒。时间到达后会删除key及value
ttl key 查询已设置过期时间的key的剩余时间 如果返回-2表示该键值对已经被删除
persist 移除给定key的过期时间
select dbindex 选择数据库(0-15)
move key dbIndex 将当前数据库中的key转移到其他数据库中
dbsize 返回当前数据库中的key的数目
info 获取服务器的信息和统计
flushdb 删除当前选择的数据库中的key
flushall 删除所有数据库中的所有key
quit 退出连接
Redis实现乐观锁
在redis中使用watch(监视器) 监控
–面试常问:redis可以实现乐观锁?redis-watch可以实现乐观锁
悲观锁:顾名思义!很悲观 什么时候都会出现问题,所以说无论什么时候都会加锁(但是影响性能)
乐观锁:很乐观 认为什么时候都不会出现问题,所以说就不一定会加锁!会在更新数据的时候去判断一下,在此期间是否有人修改过这个数据
mysql中使用version字段
获取version在更新的时候比较version
Redis监视测试
set money 100 set out 0 watch money 监视money对象 multi 事务正常结束,数据期间没有发生变动,这个时候就正常执行成功! decrby money 20 incrby out 20 exec
测试多线程修改值,使用watch可以当做Redis乐观锁操作
exec和discard自动解锁了
watch money 监视money multi decrby money 10 incrby money 10 exec 执行之前,另外一个线程修改了值,那这个时候就会导致事务执行失败 nil 线程进来操作了一下 get money set money 1000 unwatch 如果执行事务失败我们就先解锁 watch money 获取到最新的值,进行再次监视 mutli decrby money 1 incrby money 1 exec 比对监视的值是否发生了变化,如果没有变化,那么可以执行成功,如果变化了,那么就执行失败了
事务
Redis事务本质:一组命令的集合!(一块执行)一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行(谁先放进队列谁执行)
**特性:**一次性、顺序性、排他性(事务在执行中不允许被干扰的) 执行一系列的命令
Redis单条命令是保持原子性的,但是Redis事务不保持原子性的!
Redis事务没有隔离级别的概念(不会出现幻读、脏读、不可重复读)
所有的命令在事务中,并没有直接执行!只有它发起执行命令的时候才会执行 Exec执行命令
Redis的事务分为三个阶段:
- 开启事务(Multi)
- 命令入队(正常的那些命令比如get set命令。。。。)
- 执行事务(exec)
正常执行事务!
Multi 开启事务 set k1 v1 命令入队 get k1 exec 执行事务 在这里就执行完一组事务了,在用事务,得重新开启事务
放弃事务!
multi 开启事务 set k2 v2 命令入队 set k4 v4 discard 放弃事务 放弃之后所有事务全都不会执行了 get k4 nil
编译型异常(代码有问题|在Redis中命令有问题) 事务所有命令都不会被执行
multi set k1 v1 set k2 v2 getset k2 错误命令 set k4 v4 exec 执行事务报错 get k1 所的命令都不会被执行
运行时异常(1/0 ) 如果事务队列中存在语法性错误,那么执行命令的时候,其他命令时可以正常执行的,错误命令会抛出异常
比如1/0错误了 不会管他继续往下执行 所以说Redis事务没有原子性
set k1 "hello" multi incr k1 执行失败!因为incr不能对字符串进行操作,其他事务还执行 set k2 v2 get k2 exec
知道哨兵机制吗,怎么实现的,实现了什么功能
功能:实现redis高可用
机制:心跳检测
1.21哨兵和分片的优缺点
优点:
1.分片可以使redis动态内存扩容.
2.分片可以将数据均匀的分配到不同的节点中,使数据分散保存.
3.哨兵可以实现redis高可用.
缺点:
1.分片如果有一个节点出现宕机则整个分片都不能正常使用.
2.哨兵如果发生宕机现象,则影响整个redis服务.
升级:
1.使用多台redis实现内存空间的动态扩容.
2.实现在redis内存实现高可用(不再使用哨兵机制)使用组件(ruby)
搭建集群,实现分片和高可用的全部功能.