Nosql 四大分类
1 kv键值对
redis
2文档型数据库(格式和json一样)
MongoDB
3列存储数据库
HBASE
分布式文件系统
4图关系数据库
Neo4j
redis是单线程
redis是基于内存操作的,cpu不是redis的性能瓶颈,redis的瓶颈是根据机器的内存和网络带宽。
redis为什么单线程会快?
可能的误区
1高性能的服务器一定是多线程
2多线程(CPU上下文切换)一定比单线程效率高
核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(cpu会上下文切换,这是一个耗时的操作)对内存系统来说,如果没有上下文切换效率就是最高的。多次读写都是在一个cpu上,在内存情况下,这就是最快的。
String类型
setex(set with expire) 设置过期时间
setnx(set if not exist) 不存在设置(在分布式锁中用到)
mset 批量设置 mget批量获取
List类型
所有list命令都是以l开头
lset将列表中指定的值替换为另外一个值,更新操作(如果不存在列表更新就会报错,如果存在就会更新)
linsert将某个具体的值插入到列表的某个元素的前面或者后面
Set集合
命令以s开头
set中的值不能重复,且是无序的
sadd key val 设置值
smembers key 查看指定key中的元素
sismember key val 查看指定key中是否存在元素val
scard key 获取指定key中元素的个数
srem key val 移除指定元素
srandmember key 随机抽取一个元素
srandmember key num 随机抽取指定个数元素(num可设置需要抽取的个数)
spop key 随机删除指定集合中的一个元素
smove key1 key2 val 将集合key1中的val值移动到集合key2中
sdiff key1 key2 获取key1 key2的差集
sinter key1 key2 获取key1 key2的交集(共同好友)
sunion key1 key2 获取key1 key2的并集
set集合可实现共同关注,共同爱好,二度好友,推荐好友(六度分割理论)
Hash(哈希)
命令以h开头
map集合,key-map 值是map集合,本质和string类型没有太大的区别,还是一个简单的key-val
hset key field1 val1 field2 val2 field3 val3 设置值(可设置单个 也可以设置多个)
hget key field 获取field的值
hmset key field1 val1 field2 val2 field3 val3 批量设置值
hmget key field1 field2 field3 批量获取值
hgetall key 获取全部值(展示形式 key-val)
hdel key field 删除指定值
hlen key 获取长度
hexists key field 判断某个字段是否存在
hkeys key 获取指定hash中的全部key
hvals key 获取指定hash中的全部val
hash变更的数据尤其是用户信息,经常变动的信息,hash更适合对象的存储,string更加适合字符串的存储
Zset(有序集合)在set基础上增加了一个值
zadd myset 1 one 增加一个值
zadd myset 1 one 2 two 增加多个值
zrange myset 0 -1 获取全部值
如何排序
zadd salary 2500 zhangsan
zadd salary 5000 lisi
zadd salary 500 wangwu
zrangebyscore key min max [withscores] 排序按最小到最大
zrevrange key 0 -1 从大到小排序
zrem key val 移除值
zcard key 获取个数
zcount myset 区间1 区间2 获取区间1到区间2之间的数量
可用于排行榜,带权重进行判断
三个特殊的类型
geospatial(地理位置) 规则 两级无法直接添加
goadd key 经度 纬度 val 添加一个地址位置
geopos key val 获取指定的经度纬度(一定是坐标值)
geodist key val1 val2 获取两个地方的距离 (后面可跟单位)
georadius key 经度 纬度 半径 单位 以给定的经度纬度为中心,找出某一半径内的元素
georadiusbymember key val 半径 单位 找出指定val半径的其他元素
geo底层实现原理就是Zset 可以使用Zset命令来操作geo
hyperloglog
Redis Hyperloglog 基数统计的算法
优点:占用的内存是固定的 2^64不同的元素的技术,只需要废12KB的内存
缺点:0.81%的错误率
pfadd mykey field1 field2 field3 添加
pfcount mykey 统计mykey中的基数数量
pfmerge 目标key 需合并的key1 需合并的key2 合并 key1 key2 到key
Bitmap
位存储
bitmap位图,数据结构 都是操作二进制位来进行记录 就只有0和1两个状态
setbit mykey key val 设置 key的值为val (val只能为0或者1)
setbit mykey key 获取指定key的值
bitcount mykey 统计总数 (统计为1的总数)
事务
Redis事务本质 : 一组命令的集合。一个事务中的所有命令都会被序列化,在事务执行的过程中,会按照顺序执行
特点:一次性,顺序性,排他性 执行一系列命令
Redis事务没有隔离级别的概念
所有的命令在事务中,并没有直接被执行,只有发起执行命令的时候才会执行exec
Redis的单条命令是保存原子性的,但是事务不保证原子性
redis的事务
开启事务(multi)
命令入队
执行事务(exec)
放弃事务
开启事务(multi)
命令入队
discard放弃事务(事务队列中的命令都不会被执行)
当命令有错误时,事务中的所有命令都不会被执行
如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常
监控 watch(面试常问)
悲观锁 无论做什么都会加锁
乐观锁 不会上锁 更新数据时去判断一下,在此期间是否有人修改过这个数据,获取version 更新的时候比较version
测试多线程修改值,使用watch可以当做redis的乐观锁操作
watch key 监视key
unwatch key 放弃监视key(事务执行失败就先解锁)
插入 spring中的知识点
在springbooot2.x之后,原来使用的jedis被替换为了lettuce
Jedis 采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全,使用jedis连接池,更像BIO模式
Lettuce 采用netty,实例可以再多个线程中进行共享,不存在线程不安全的问题,可以减少线程数据,更像NIO模式
redis.conf详解
配置文件unit单位对大小写不敏感
bind 127.0.0.1 #绑定ip
protected-mode yes #保护模式
port 6379 端口
GENERAL 通用
daemonize yes #以守护进程的方式运行,默认为no
pidfile /var/run/redis_6379.pid #如果以后台的方式运行,我们就需要指定一个pid文件
loglevel notice
logfile “” #日志的文件位置名
database 16 #数据库的数量,默认是16
always-show-logo yes #是否总是显示logo
SNAPSHOTTING 快照
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件 .rdb .aof
redis是内存数据库,如果没有持久化,那么数据断电及失
如果900s内,如果至少有1个key进行了修改,我们及进行持久化操作
save 900 1
如果300s内,如果至少有10个key进行了修改,我们及进行持久化操作
save 300 10
如果60s内,如果至少有10000个key进行了修改,我们及进行持久化操作
save 60 10000
stop-writes-on-bgsave-error yes #持久化如果出错,是否还需要继续工作
rdbcompression yes #是否压缩rdb文件,需要消耗CPU资源
rdbchecksum yes #保存rdb文件的时候,进行错误的检查效验
dir /usr/local/var/db/redis/ # rdb保存的目录
SECURITY 安全
可以在这里设置redis密码,默认没有密码
config get requirepass #获取redis的密码
config set requirepass #设置redis的密码
auth 密码 登陆
CLIENTS 限制
maxclients 10000 #设置能连接上redis的最大客户端数量
maxmemory <bytes> redis配置最大的内存容量
maxmemory-policy noeviction #内存到达上限之后的处理策略
volatile-lru:只对设置了过期时间的key进行LRU(默认值)
allkeys-lru : 删除lru算法的key
volatile-random:随机删除即将过期key
allkeys-random:随机删除
volatile-ttl : 删除即将过期的
noeviction : 永不过期,返回错误
APPEND ONLY模式 aof配置
appendonly no #默认不开启aof模式的,默认是使用rdb方式持久化的。在大部分情况下,rdb完全够用
appendfilename "appendonly.aof" #持久化文件的名字
# appendfsync always # 每次修改都会sync 消耗性能
appendfsync everysec # 每秒执行一次sync 可能会丢失这1s的数据
# appendfsync no # 不执行sync,这个适合操作系统自己同步数据,速度最快
redis持久化
Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所以redis提供了持久化的功能
RDB(Redis DataBase)
在指定的时间间隔内将内存中的数据集快照写入磁盘,它恢复时是将快照文件直接读到内存里
Redis会单独创建一个子进程进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效RDB的缺点是最后一次持久化的数据可能丢失
Rdb保存的文件是 dump.rdb
触发规则
1 save的规则满足的情况下,会自动触发rdb规则
2执行flushall命令,也会触发rdb规则
3 退出redis,也会产生rdb文件
如何恢复rdb文件
1只需要将rdb文件放在我们redis启动目录就可以,redis启动的时候会自动检查dump.rdb恢复其中的数据
2查看需要存在的位置
config get dir #如果在这个目录下存在dump.rdb文件,启动就会自动恢复其中的数据
优点:
1适合大规模的数据恢复
2对数据的完整性要不高
缺点:
1需要一定的时间间隔进行操作
2 fork进程的时候,会占用一定的内容空间
有时候在生成环境会将这个文件进行备份
AOF(Append Only File)
将我们的所有命令都记录下来,history,恢复的时候就把这个文件全部执行一次。
以日志的形式来记录每个写操作,将redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
AOF保存的是appendoly.aof文件
如果aof文件有错误,redis是启动不起来的,我们需要修复这个aof文件
Redis提供的工具 redis-check-aof —fix aof文件
优点:
1每次修改都同步,文件的完整性会更好
2每秒同步一次,可能会丢失一秒的数据
3从不同步,效率最高
缺点:
1相对于数据文件来说,aof远大于rdb,修复速度比rdb慢
2aof运行效率比rdb慢,所以我们redis默认的配置就是rdb持久化
redis发布订阅
Redis发布订阅(pub/sub)是一种消息通信模式:发送者发送消息,订阅者接收消息
subscribe channel 订阅一个频道
publish channel 往频道发送消息
Redis主从复制
数据的复制是单向的,只能由主节点到从节点。Master以写为主,slave以读为主
默认情况下,每台redis服务器都是主节点,且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点
主从复制的作用:
1 数据冗余:主从复制实现数据的热备份,是持久化之外的一种数据冗余方式
2故障恢复:主节点出问题时,可以由从节点提供服务,实现快速的故障恢复,实际上是一种服务的冗余
3负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器负载,尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高redis服务器的并发量
4高可用(集群)基石:除了上述作用外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是redis高可用的基础
单台redis最大使用内存不应该超过20G
环境配置
只配置从库,不用配置主库
info replication 查看当前库的信息
修改配置文件中的信息以下信息
1端口
2pid名字
3log文件名字
4dump.rdb名字
在从机中配置: slaveof host 端口 (找主节点)
真实的主从配置应该在配置文件中,命令行中的只是暂时的
测试:主机断开连接,从机依旧连接到主机,但是没有写操作,这个时候如果主机回来了,从机依旧可以直接获取到主机写的东西
如果是使用命令行来配置的主从,如果重启了,从机就会变回主机,只要变为从机,立马就会从主机中获取值
复制原理
Slave启动成功连接到master后会发送一个sync同步命令
Master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中
增量复制:master继续将新的所有收集到的修改命令依次传给slave,完成同步
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行,在从机中一定会看到数据
如果主机断开了连接,我们可以使用slaveof no one让自己变为主机
哨兵模式
哨兵模式是一种特殊的模式,redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待redis服务器响应,从而监控运行的多个redis实例
作用:
1通过发送命令,让redis服务器返回监控其运行状态,包括主服务器和从服务器
2当哨兵检测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它切换主机
配置:
1配置哨兵配置文件sentinel.conf
sentinel monitor 被监视的名称 host port 1 (1代表票数)
2启动哨兵
redis-sentinel sentinel.conf
优点:
1哨兵集群,基于主从复制,所有的主从配置的优点它都有
2主从可以切换,故障可以转移,系统的可用性更好
3哨兵模式就是主从模式的升级,手动到自动,更加健壮
缺点:
1redis不好在线扩容,集群容量一旦到达上限,在线扩容十分麻烦
2实现哨兵模式的配置很麻烦
缓存穿透(查不到)
用户查询数据,缓存中没有命中,频繁去查询数据库
解决方案:
1布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行效验,不符合规则丢弃,从而避免了对底层存储系统的查询压力
2缓存空对象 当存储层不命中后,即时返回的空对象也将其缓存起来,同时会设置一个过期的时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源
缓存空对象的缺点:1如果空值能够缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键
2即时对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,对于需要保持一致性的业务会有影响
缓存击穿(量太大,缓存过期) 一个热门的key失效瞬间,大并发穿破缓存
解决方案
1设置热点数据永不过期
2加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需等待即可,这种方式将高并发的压力转移到了分布式锁
缓存雪崩 指在某一个时间段,缓存集中过期失效 或者redis宕机
解决方案:
1 redis高可用 多增加几台redis
2 限流降级 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量,比如对某个key只允许一个线程查询数据和写缓存,其他线程等待
3数据热备 在正式部署之前,先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中,在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀