Redis
NoSql特点
1、方便扩展(数据之间没关系)
2、大数据量高性能(单线程,一秒写8万次,读取11万次)
3、数据类型是多样型的(不需要事先设计数据库,随取随用)
4、关系型数据库(RDBMS)和Nosql
关系型数据库
数据和关系都存在在单独的表中
操作,数据定义语言
严格的一致性
Nosql
不仅仅是数据
没有固定的查询语言
键值对存储,列存储(HBASE)、文档存储,图数据库(社交关系)
最终一致性
CAP定理和BASE(异地多活)
高性能,高可用,高可扩展性
阿里云的这群疯子
分布式文件系统FastDFS
搜索引擎Elasticsearch,淘宝Isearch:多隆
NoSQL四大分类
KV 键值对
文档型数据库(bson和JSON一样):MongoDB基于分布式文件存储的数据库,是NOSQL和关系型数据库中间的产品
列存储数据库:HBase、分布式文件系统
图关系数据库:存放的是关系
Redis
远程字典服务,C语言写的,支持网络,可持久化的key-value数据库。
可以干嘛
1、内存存储,持久化(没有持久化,数据断电即失去)
2、效率高,可用于高速缓存
3、地图信息分析
4、计时器、计数器
5、解决Session共享问题
默认端口号:6379
默认16个数据库,默认使用第0个,可以使用select选择数据库,select 3
不区分大小写
安装homebrew:/bin/zsh -c “$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)”
启动Redis服务,redis-server /opt/homebrew/etc/redis.conf
redis-benchmark压力测试 工具
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
redis是单线程的,处理请求是单线程的,持久化的时候,多线程,不是所有的操作都是单线程
Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,可以使用单线程来实现,就使用单线程了
Redis为什么单线程这么快
redis是将所有数据放在内存中的,单线程操作效率是最高的,多线程CPU会上下文切换,耗时,对于内存系统来说,没有上下文切换效率是最高的
可以给Redis设置密码
//在控制台设置密码
config get requirepass // 获取密码
config set requirepass //设置密码
auth pwd //登录时输入密码命令
五大数据类型
Strings(字符串set get)
切换数据库:select 3
设置KV:set key value
获取值:get key
获取所有key:keys *
清空当前数据库:flushdb
清空所有库:flushall
判断是否存在key: exists key
删除key:move key index (index为当前数据库)
设置key过期,过期后自动删除:expire key time (time 是秒 )
查看key剩余时间:ttl key
查看key类型:type key
动态修改value:append key "str" (给之前的key对应的value值追加)
获取当前key对应value的长度:strlen key
value自增:incr key
value自减:decr key
value 增加指定增长量:incrby key 10
value 减少指定增长量:decrby key 20
截取字符串:getrange key start end (例:getrange age 0,2)闭区间
替换: setrange key start xx (从1开始替换)
设置过期时间:setex(set with expire) setex key time value //设置key的值为value,time时间后过期
不存在设置:setnx(set if not exist) setnx key value //不存在的时候新建k-v,存在的时候覆盖不了, //分布式锁中会常用
批量设置k-v: mset k1 v1 k2 v2 k3 v3
批量获取value: mget k1 k2
批量不存在创建:msetnx k1 v1 k4 v4 //会失败,原子性操作,一个失败,就都失败,k1已存在,失败
//对象
set user:1:{name:zhangsan,age:3}设置一个user:1对象
mset user:1:name zhangsan user:1:age 2
mget user:1:name user:1:age
先get再set:getset key value
计数器,统计多单位数量 ,setnx可以做分布式锁
hashes(散列set get hdel)
Key-Map,跟String差不多
hset myhash key value //插入值
hget myhash key //取值
hmset myhash k1 v1 k2 v2 //批量设置key-value
hmget myhash k1 k2 //批量取值
hgetall myhash //获取全部的数据,展示形式:key 和value按顺序单个显示
hdel myhash k1 //删除k1
hlen myhash //取数量
hexists myhash k1 //是否key存在
hkeys myhash //所有的key
hvals myhash //获得所有的value
hincrby myhash k1 count //给k1增加1
hdecrby myhash k1 count //给k1减1
hsetnx myhash k1 value //如果不存在,新建,存在,就没效果
存一些变更的信息,尤其是用户信息,经常变动的信息,更适合对象的存储
lists(列表push pop)
同JAVA,可以设置成栈、队列、阻塞队列(有序可重复)
//设置值
LPush list value // 从左侧放值
LRange list start end //取值,从开始到结束,闭区间,是放进去顺序的倒序
RPUSH list value //从右侧放值
LRange list 0 -1 //插入顺序和显示顺序一致,查看所有值
//弹出值
LPop list //从左边弹出值
RPop list //从右侧弹出值
//取下标
Lindex list index //从左侧取第index个值,从0开始
//取长度
Llen list
//移除指定的值
lrem list count value //移除指定个数的值,lrem list 2 one
//截取指定长度,即list被删除了
Ltrim mylist 1,2 //下标在[1,2]之间以外的都删除,Lrange是只显示,不删除
//先把元素从一个list弹出,再将其移动到新的列表中
rpoppush mylist myotherlist
exists list //是否存在list
lset list index othervalue //如果list的下标为index存在,会覆盖值为othervalue,否则会报错,提示不存在
Linsert list before/after "value" "newValue" //给value的前面/后面加newvalue的值
Sets(集合add、srem)
set中的值不能重复(无序不重复)
sadd myset "hello" //插入值
smembers myset //列出元素
sismember myset value //是否存在元素value
scard myset //获取set中元素个数
srem myset value //移除元素
srandmember myset //随机取元素
spop myset //随机弹出元素
smove myset myset2 "value" //将myset中的value移动到myset2中
//微博、b站共同关注(取交集)
sdiff set1 set2 //set1-set2,取set1不同于set2的元素
sinter set1 set2 //取set1和set2相同的元素,交集
sunion key1 key2 //取并集
共同关注、二度好友、好友推荐
ZSet(有序集合add rem)
在set 基础上增加了一个值,可以进行分组
zadd myset score value //添加,中间的1可以是一类,或者倒序正序排 根据业务来
zadd myset 2 tow 3 three //批量添加
//排序
zRangeByScore myset -inf +inf //按中间值的,从小到大排序,inf是无穷,输出的都是value
zRangeByScore myset -inf +inf withscores //作用如上,同时输出value和score
zRangeByScore myset min max //升序排序,从最小到最大
zRevRangeByScore myset 0 -1 //降序,饭转
zrange myset 0 -1 //输出所有元素
zrem mysey value //删除指定元素
zcard myset //获取有序集合中的个数
zcount myset score1 score2 //获取[score1,score2]中间的值的个数
对set进行排序,存储班级成绩表,工资表排序(注意,可能值一样,就不行了)
加权判断、排行榜、获取TopN
三大特殊类型
geospatial地理位置
朋友的定位,附近的人,打车距离,方圆几里的人,索引半径查询
geoadd key value(经度 纬度 城市) //添加,两级无法添加,一般通过JAVA程序一次性导入
geopos key 城市1 城市2 //取所在城市的经纬度
geodist key 城市1 城市2 m/km/mi/ft //获取两个城市之间的距离,后面的是单位 米/千米/英里/英尺
georadius key 经度 纬度 半径 m/km/mi/ft //获取附近所有人的地址,定位,通过半径来查询
georadius key 经度 纬度 半径 m/km/mi/ft withdist //获取附近的半径人,附带距离
georadius key 经度 纬度 半径 m/km/mi/ft withdist withcoord count 2 //获取附近的半径人,附带距离,经度、纬度 限制两人
geoRadiusByMember key 城市1 半径 m/km/mi/ft //找出指定元素周围的其他元素 根据城市,及半径找出附近的城市
Geo底层原理是ZSet,有序集合,可以使用zset的查看元素,移除元素
Hyperloglog
网页访问数(一个人访问网站多次,但是还算做一个人)
传统方式,set保存ID,占据空间大。目的是计数,用hyperloglog,只占12KB的内存
pfadd key a b c d e f g h i j // 创建
pfadd key2 i j a b c m n
pfcount key //计数
pfmerge mykey3 key key2 //合并key 和key2 作为mykey3,并集 会将key和key2中的合并,并去重,相当于set
//查看mykey3的数量,就可以查看访问量,需要允许容错,不允许容错,用set或其他类型统计
Bitmaps
位存储
统计用户信息,活跃,不活跃;登录,未登录,365天打卡,两个状态的,都可以使用bitmaps,用0和1存储
setbit key 2 0 //例如,周一到周日用0-6表示,后面是打卡状态
getbit key 2 //获取周三是否打卡
bitcount key //统计这周打卡记录
布隆过滤器,利用很长的二进制向量和随机映射函数。
事务
Redis事务本质:一组命令的集合!
一个事务中的所有命令都会被序列化,在事务执行过成功,会按照顺序执行!
具有一次性,排序行,排他性
Redis单条命令是保存原子性的,但是事务不保持原子性
原子性:要么同时成功,要么同时失败
Redis事务没有隔离级别的概念(幻读、脏读、不可重复读)单线程的
所有的命令在事务中,并没有被执行,只有发起执行命令的时候才会执行。
Redis的事务
1、开启事务(multi)
2、命令入队
3、执行事务(exec)
放弃事务discard,事务队列中的命令不会执行
编译型异常(语法错误代码有问题!命令有错),事务中所有命令都不会被执行
运行时异常(1/0),如果事务队列中存在语法性错误,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!监控 ! watch 可以做乐观锁(用于秒杀)
悲观锁:什么时候都会出现问题,无论做什么都会加锁。synchronized
乐观锁:认为什么时候都不会出现问题,所以不会上锁。更新数据的时候判断,获取version ,比较version 在此期间是否有人改过这个数据。
watch key,然后进行事务,不exec,另外一个线程修改了key的值,此时exec执行失败,需要unwatch解锁,再监视
SpringBoot整合
在SpringBoot2.x之后,Jedis换成了lettuce,因为Jedis是直连的,多线程操作不安全,需要使用Jedis pool连接池。
Lettuce:实例可以在多线程中共享,不存在线程不安全的情况,可以减少线程数据
序列化是为了可以通过网络传输对象,JAVA实体类,继承Serializable接口
Redis持久化
有两种模式aof 和rdb,在大部分情况下,rdb完全够用
RDB(Redis DataBase)
redis.conf中有配置
Redis会单独创建一个子进程持久化,在指定的时间内,将内存中的数据写到一个临时文件中(快照SnapShot),持久化过程结束后,将临时文件替换上次持久化后的文件。整个过程中,主进程不进行任何IO操作。进行大规模的数据恢复,RDB比AOF更高效,缺点是RDB在最后一个持久化后数据可能丢失。
save 900 1 ##900s内至少一个key修改了,就进行持久化操作
save 300 10 ##300s内至少10个key修改,持久化
save 60 10000 ##60s内至少10000个key修改,持久化
stop-writes-on-bgsave-error yes ##创建快照需要几秒,中间主进程还在接收客户端数据,在创建快照的过程中,磁盘满了或者宕机出错了,此时停止写入工作
rdbcompression yes ##是否压缩rdb文件,需要消耗一些cpu资源
rdbchecksum yes ##保存rdb文件时,进行错误的检查校验
dir path ##rdb文件保存目录
保存的文件叫dump.rdb
触发机制
1、save规则满足
2、执行flushall
3、退出redis,shutdown
如何恢复rdb文件
将rdb文件放在redis启动目录下就可以
save和bgSave
相当于同步和异步,save的时候,将所有数据快照以rdb文件保存到硬盘上,会阻塞主进程,直到保存完成,主进程不会处理客户端的请求
bgsave的时候,会fork一个子线程,将数据保存到硬盘上,主进程继续接收客户端请求。
优点和缺点
##优点
在大量数据恢复时,性能比AOF好
##缺点
每隔一段时间出发持久化,数据安全性低
AOF(Append Only File)
Append Only Mode将所有命令都记录下来,恢复的时候将这个文件执行一遍。
以日志的形式记录每个写操作(不记录读操作),只追加文件,不改写文件,Redis启动时,会读取该文件重新构建数据
保存的文件叫appendonly.aof
appendonly no ##默认不开启
appendfilename "appendonly.aof" ##保存AOF的文件名称
appendfsync always ##每一次都球盖
appendfsync everysec ##每一秒都修改
appendfsync no ##从不修改
no-appendfsync-on-rewrite no ##重写
auto-aof-rewrite-percentage 100 ##
auto-aof-rewrite-min-size 64mb ##aof文件大于65M,fork一个新的进程将文件重写,不影响主进程处理命令请求
##重写的时候,fork一个子进程,重写好后给父进程发送一个完成信号,父进程接收到后,会调用信号处理函数:
1、将AOF重新缓存中的内容全部写入到新的AOF文件中,新的AOF文件保存的数据库状态和服务器当前数据库状态一致
2、对新的AOF文件进行改名,新的AOF文件覆盖原有的AOF文件,完成新旧两个AOF文件的替换
触发机制
重启的时候
同时开启两种持久化方式,AOF比RDB优先级更高,通常情况下AOF文件保存的数据集比RDB完整性更高
Redis发布订阅
消息发送者 》频道》消息订阅者
subscribe channel ##订阅一个频道,自动监听的
publish channel msg ##发送信息到一个频道
主从复制
将主节点的数据复制到从节点,Master以写为主,Slave以读为主。80%都在 进行读操作,减缓服务器的压力
主从复制作用:
1、数据冗余:实现了数据的热备份,是持久化之外的一种数据冗余方式
2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余
3、负载均衡:在主从复制基础上,配合读写分离,主节点写,从节点读,分担服务器负载,可以大大提高Redis服务器的并发量
4、高可用(集群)基石:主从复制还是哨兵和集群能够实施的基础
单台Redis最大使用内存不应超过20G
每一台Redis服务器都默认自己为主节点,需要配置从机
##命令配置
info replacation ##查看主机丛机配置信息
slaveof host port ##认主机
slaveof no one ##没有主机,如果主机宕机了,可以自己设置为主机
##conf文件配置
replicaof masterHost masterPort ##在从机上配置
主机中的所有信息都会被从机复制 ,Redis自己底层的
主机断掉了,从机依旧只有读,没有写。主机重新连接,还是主机
如果从机断掉了,就读不到主机的数据了,重新设置主机,会读到
复制原理
从机连到主机,master将传送整个数据文件到slave(全量复制),Master继续将新的修改命令依次传给slave(增量复制)
哨兵模式
在主机断了之后,谁为主机,Redis2.8后自动换主机
哨兵模式(sentinel):是一个独立的进程 ,通过发送命令,等待Redis服务器响应,监控运行的多个Redis实例
一个哨兵可能会出现问题,需要多个哨兵进行监控,各个哨兵之间还会进行监控,形成多哨兵模式。
配置哨兵配置文件sentinel.conf
sentinel monitor myredis host port quorum ##被监控的名称 ,1是至少多少个哨兵挂了,才能使主机下线,故障转移failover
启动哨兵
redis-sentinel sentinel.conf
主机断开后,哨兵会投票选一个从机为主机,主机恢复后,会将原来的主机设置为从机
优点
1、哨兵集群,基于主从复制模式,是主从模式的升级,手动到自动,更加健壮
2、主从可以切换,故障可以转移,系统的可用性更好
缺点
1、Redis不好在线扩容,集群容量一旦达到上限,在线扩容十分麻烦
2、实现哨兵模式很麻烦,上述conf配置,只是其中核心的
Redis缓存穿透和雪崩(需细化)
缓存穿透(查不到)
用户查数据,缓存没有,就会向MySQL等数据库查,发现也没数据,查询失败。如果用户很多,缓存没有,就会都请求数据库,数据库有很大的压力,出现了缓存穿透。
解决方案
布隆过滤器
说存在不一定存在,说不存在一定不存在
缓存击穿(值有,但是缓存过期 访问量太大)
一个热点数据,在不停的扛着大并发,大并发集中对着一个点访问,这个缓存过期,持续的大并发就击破缓存,直接请求数据库,并回写缓存,导致数据库瞬间压力过大。例如微博服务器宕机
解决方案
1、设置热点数据永不过期
2、加互斥锁
缓存雪崩
在某一个时间段内,缓存集中过期失效。Redis宕机
解决方案