学习笔记系列开头惯例发布一些寻亲消息
链接:https://baobeihuijia.com/bbhj/contents/3/194205.html
跟学链接
跟学视频链接:https://www.bilibili.com/video/BV1S54y1R7SB/?spm_id_from=333.999.0.0
(建议有java基础的同学学习或者一直跟着狂神系列的同学学习)
Nosql
-
发展历史 Structured Query Language
- 单机mysql->读写分离+cache->集群
- MyISAM表锁->行锁 Innodb->分库分表,mysql集群
- mysql关系数据库-> NoSQL非关系型数据库,不需要关注数据的类型
-
3V3高
- 海量多样实时
- 并发可扩性能
-
NoSql的四大类型
- KV键值对:redis 内容缓存查找快
- 文档形式:
- MongoDB
- 基于分布式文件存储
- 处理大量文档
- MongoDB是一个介于关系和非关系数据库的产品
- MongoDB
- 列存储
- HBase,容易进行分布式扩展
- 图关系数据库
- 社交拓扑图
- 存储的是关系(朋友圈社交网络,广告推荐)
- InfoGrid
-
Redis:远程字典服务
- 内存存储、持久化存储(内存中断电即失,但是redis可以做到持久化)
- 效率高、高速缓存
- 发布、订阅系统
- 地图信息分析
- 计时器、计数器、浏览量
Redis 基本语法
-
redis默认有16个数据库
-
redis为什么单线程还这么快?
- cpu>内存>硬盘,所以cpu不是redis的性能瓶颈
- redis是将所有数据全部放入内存中
- 而多线程操作的话cpu会有切换上下文的耗时操作
- 对于内存系统,没有上下文切换操作,效率就是最高的
-
redis是内存中的数据结构存储系统,可以用作数据库,缓存,和消息中间件
-
value数据类型
-
String/还可以是数字,可以增减(计数器/实时粉丝数量)
- select 1
- set name xxx
- APPEND name xxx(补加,如果不存在那就相当于新建)
- get name
- DBSIZE
- keys * :显示全部数据
- flushdb:清除当前数据库
- flushall 清空所有数据库
- EXISTS name
- move name x(x是哪个数据库)
- EXPIRE name 10 (控制name十秒过期)
- ttl name (剩余过期时间)
- type name(查看name即key的类型)
- STRLEN name(求name的长度)
- incr/decr name (浏览量±)
- INCRBY name 5 (一次性增加5)
- GETRANGE name 0 3 (类似substring,全部的话就是 0 -1)
- SETRANGE name 1 “shixh” (从第一个位置开始修改后边数据为shixh)
- setnx (如果不存在就set,存在就算了,分布式锁)
- setex (设置过期时间)
- mset/ mget 一次性设置和get多个值,是原子性操作要么成功要么失败
- set user:1:name zhangsan 作为对象缓存,更多的是用hash存
- getset(先get后set)
-
List (可以作为消息队列、栈)
- LPUSH name one (头插)
- RPUSH name two (尾插 )
- LPOP name
- RPOP name
- Lset name 1 rrr ( 修改name指定位置的值)
- Lindex name 1(通过下表获取name中第一个值)
- Llen name
- Lrem name 3 one (移除从上到下3个one)
- Ltrim name 0 1(只截取这部分保留下来)
- LRANGE name 0 -1 (获取全部)
- RpopLpush name othername(移除name结尾并将该元素加到othername开头)
-
set(无序不能有重复)
- sadd myset ”hello“
- sremove myset ”hello“
- scard myset 求长度
- smembers myset 查看所有值
- sismember myset ”hello“ 判断是否在set中
- srandmember 随机抽取元素
- spop 随机删除元素
- smove myset1 myset2 ”hello“ 将制定的值移动到另外一个set
- (共同关注)
- sdiff key1 key2 差集
- sinter key1 key2 交集 共同好友的实现,微博b站,好友推荐
- sunion key1 key2 并集
-
Hash (key-map集合)用作一个用户多个信息的保存,尤其是经常变动的信息 hset user name 崔志雅 age 23 ismarried no
- hset myhash filed1 aaa
- hget myhash filed1得到结果aaa
- hmset myhash field1 hello field2 world
- hmget
- hgetall myhash 得到结果field1 hello filed2 world
- hdelete myhash filed1
- hlen myhash 获取键值对的数量
- hexist myhash filed1
- hkeys myhash / hvals myhash
- hset myhash filed3 5
- hincrby myhash filed3 -1
- hsetnx myhash filed3 存在就失败
-
zset(有序集合)zset 成绩排序/ 对消息进行带权重执行/ 排行榜 ,热榜
- zadd myset 1 one
- zrange myset 0 1
- zadd salary 2388 hong
- zrem myset hong
- zadd salary 300 zhansgan
- zrangebyscore salary -inf +inf 对salary排序从最小到最大, -inf +inf是score排序区间范围
- zrevrange myset 0 -1 从大到小排序
- zrangebyscore salary -inf +inf withscores 就是排序并且加上score
- zcard myset 获取有序集合中的个数
-
三种特殊的数据类型
-
geospatial 地理位置 算地理位置 两地距离,算方圆几里的人
- 底层实现原理是zset,官方没有给删除,但是可以自己关掉自己的定位信息 用zrange 查看全部,用zrem删掉
- 超过南北极直接判定无法添加 先经度后维度
- geoadd china:city 115.00 39.00 beijing
- geopos china:city beijing 获取北京的经纬度
- geodist china:city beijing shanghai km 求两人定位之间的距离
- georadius china:city 110 30 1000 km 满足半径的:我附近的人 【我附近的人】
- georadius china:city 110 30 1000 km withcoord 返回他人的带经纬度
- georadius china:city 110 30 1000 km withdist count 1 限定返回数量为1
- georadiusbymember china:city shanghai 400 km 以上海为中心的400km以内的 【用于定位】
-
Hyperloglog 占用的内存是固定的 12kb 底层是布隆过滤器, 无法判断即将到来的庞大数据流,且不能查看内存,容忍错误率
- 基数就是不重复的元素
- 统计网页的UV(一个人访问网站多次,但还是算一个人)
- 传统方式是用set来保存id,因为set不允许重复,因此可以用set元素统计数量
- PFadd myket abcdefg
- PFCOUNT mykey (统计不重复元素)
- PFMETGE mykey3 mykey mykey2 (mykey mykey2 的并集)
-
Bitmaps 位图数据结构,位存储 只有两个状态的
-
如何筛选用户是最快的,用0101表示用户(统计大数量的感染人数,用户信息活跃和不活跃的,登录和未登录的,打卡或者没打卡的)
-
setbit sign 0 1
-
getbit sign 6
-
bitcount sign 统计打卡天数
-
-
-
事务:本质就是一组命令的集合,命令直到执行事务才会执行
- 关系数据库的事务 ACID (原子性,一致性,隔离性,持久性) redis的单条命令保证原子性,but redis事务是不保证原子性的
- redis一个事务中所有命令都会序列化,顺序执行,满足一次性、顺序性、排他性,没有隔离级别
- 开启事务:multi
- 给出命令: set k1 v1 ……
- 执行事务:exec
- 取消事务 discard
- 编译时异常整个事务的命令都不执行
- 运行时异常只有运行错误的代码不执行,其余都要执行
-
监控watch,是乐观锁:
-
悲观锁:认为什么时候都出问题
- 无论做什么都加锁
-
乐观锁:认为什么时候都不会出问题
- 不会上锁,更新数据的时候判断一下在此期间是否有人修改过
- 获取version
- 更新的时候对比version
-
redis监控测试:
-
watch money
-
watch会检测到另一个程序是否修改过该值,修改过那么就不能执行事务
-
unwatch 原始事务失败就解锁
-
watch money 重新监视
-
Springboot整合redis——lettuce
-
jedis已经改版为lettuce
-
jedis是直连,采用多个线程操作是不安全的,需要用jedis pool连接池 BIO
-
lettuce采用netty,实例可以在多个线程中共享 NIO
- 三种IO模型即为BIO【同步阻塞IO】、NIO【同步非阻塞IO】、AIO【异步非阻塞IO】。 首先可以先简单地体会一下三种IO模型的情景:假设你需要等待开水的煮开: 1. 同步阻塞:你蹲在开水壶旁边,什么都不做,等着开水的煮开。 2. 同步非阻塞:你跑去看书学习,隔一段时间来看看开水是否煮开。 3. 异步非阻塞:你跑去看书学习,当开水煮开的时候会发出响声,听到响声后你再回来。
-
redis的config配置文件
- 快照
- 在规定时间内,执行了多少次操作则会持久化到文件,生成快照,否则数据会断电即失
- client:如果内存达到上限后,六种处理策略和JUC(并发)一致
- 1.noeviction(默认策略):对于写请求不再提供服务,直接返回错误(DEL请求和部分特殊请求除外)
- 2.allkeys-lru:从所有key中使用LRU算法进行淘汰(LRU算法:即最近最少使用算法)
- 3.volatile-lru:从设置了过期时间的key中使用LRU算法进行淘汰
- 4.allkeys-random:从所有key中随机淘汰数据
- 5.volatile-random:从设置了过期时间的key中随机淘汰
- 6.volatile-ttl:在设置了过期时间的key中,淘汰过期时间剩余最短的
- 快照
Redis持久化(RDB &AOF)
-
RDB & AOF,两种都开启的话,优先AOF的数据载入
-
redis是内存数据库,所以需要持久化操作
-
RDB(redis database):在指定时间间隔内,将内存的中的数据写到磁盘,也就是Snapshot快照,恢复的时候将快照读到内存
-
dump.rdb
-
规则
- 触发生成rdb文件的规则
- save的规则满足的时候 save 60 5(60s进行五次修改操作)
- 执行flushall命令
- 退出redis
- 恢复rdb文件:只需要将rdb文件放在启动目录即可,redis启动会自动检查dump.rdb恢复其中的数据
- 触发生成rdb文件的规则
-
优点
- redis宕机也可以通过dump恢复数据,所以很适合大规模的数据恢复
- 父进程继续处理client,子进程的fork不会影响父进程
-
缺点
- 对数据的完整性要求不高,redis意外宕机,最后一次修改数据就没有了
- fork进程的时候,会占用一定的内存空间
-
-
AOF(append only file):以日志形式记录每个写操作,redis启动时通过命令重建数据库
-
appendonly.aof
-
每秒钟往aof中追加
-
如果这个文件有问题那么redis无法启动,可以通过redis-check-aof --fix xxx.aof
-
优点
- 每一次修改都同步/每秒同步/从不同步 相比于rdb完整性更好
-
缺点
-
aof文件远大于rdb,修复速度比rdb慢
-
运行效率也比rdb漫长
-
-
这样文件是不是会越来越大?
如果上一次文件大于限定的64m,就会fork一个新进程,新进程会把数据转为写指令存入到aof文件
-
Redis的发布订阅
- 是一种消息通信模式,有发送者pub有订阅者sub
-
SUBSCRIBE 订阅频道,监听等待推送的信息
-
PUBLISH 发布者往频道里边发布消息
-
PSUBSCRIBE 退订
-
用途(简单场景,难得场景会使用消息中间件MQ)
- 实时消息系统
- 关注系统
- 微信公众号:博主是发布者,我们可以订阅博主,此时的结构是一个发布者产生一个订阅队列,向队列中发送消息
- 是字典结构
- 频道是key,值是订阅者形成的一个链表
Redis主从复制(集群)
-
从主节点服务器单向复制到从节点服务器,master以读,slave以写为主
-
主从复制的作用
- 是持久化之外另一种数据冗余形式
- 故障恢复
- 读写分离,负载均衡:一般读比写要多,用多个节点可以分担负载,提高服务器的并发承受量
- 高可用(集群)基石:防止一台redis宕机情况
-
info replication 查看当前主从信息
-
配置的时候要每一个服务器拥有一个单独的config
- 修改内部的dumb文件名
- 端口号
- pid进程文件名字
- log日志文件名字
-
给从机配老大: SLAVEOF 127.0.0.1 6379 如果是永久配置的话要在config中写死,否则一旦断开,从机就会认为自己是主机
-
slave启动后会给所属master发一个同步命令,Master收到命令后自动后台存盘进程,将数据文件同步到slave
-
当主机断开连接,不影响从机的响应,从机之间彼此也不会影响,重新加进来的slave会重新执行一次全量复制
- 全量复制:新连接过来的就将全部数据都给它
- 增量复制:将新收集到的修改命令传给slave
-
Resid主从复制方式二——人体蜈蚣模式
哨兵模式——自动选取老大
-
原始方式是手动切换一台从服务器到主服务器,现在就是谋朝篡位的自动版,后台监控主机是否故障,如果故障那么就投票来选择从库作为主库
1、多个哨兵之间也在互相监控,避免某个哨兵自身挂掉
2、当某个哨兵发现master一直不回应,此时为哨兵一的主观下线
3、当别的一定数量哨兵也发现这一现象后,哨兵之间就会进行一次投票,投票由随机某个哨兵发起进行统计
4、根据投票结果选出下一个主节点
5、该哨兵通过发布订阅模式,让各个哨兵更改自己监控的主机,此时为客观下线
6、此时如果原始的主机回来了,那么会自动成为当前新主机的从机
- 优点
- 冗余、持久化
- 主从故障转移切换,系统的可用性更好
- 哨兵模式的自动化,更加健壮
- 缺点
- redis的在线扩容很麻烦,当前服务器满了需要迁移到另一台服务器上时
- 哨兵模式配置
Redis缓存穿透和雪崩(服务器的高可用问题)
-
缓存穿透(查不到):查询的数据在缓存中没有命中,于是向持久层数据库查询,这次查询也没有查询到——如果用户很多缓存都没有命中就会频繁请求持久层数据库,出现缓存穿透(穿透的意思大概就是,此时缓存就像不存在一样)
- 解决方法
- 请求的时候加一个过滤器——布隆过滤器
- 是一种数据结构
- 对所有查询以hash形式存储
- 先校验再给到底层数据库
- 当持久层数据库没有的话,也把这条信息存入到缓存中(但是不知道哪个空请求会被频繁执行)——缓存空对象
- 请求的时候加一个过滤器——布隆过滤器
- 解决方法
-
缓存击穿(查的量太大了,缓存过期):请求全部集中在一个点key,大并发集都对这一个点进行访问,当key失效的瞬间,大并发涌入击穿缓存涌入数据库,就像在屏障上凿出一个洞
- 比如微博热搜,所有人都在高并发访问一个点的数据,但是这个点在缓存中比如60s过期,那么在过期的瞬间,大量请求涌入数据库,直接击穿缓存
- 解决方案
- 热点数据永不过期
- 加分布式锁,这样的话数据请求就会以分布锁的形式控制只有一个线程能进入到持久化数据库,其余线程等待
-
缓存雪崩:在一个时间段,缓存中的数据全失或者集中过期失效
- 所有的数据全部砸在了数据库,此时对数据库产生周期性压力波峰,存储层调用量暴增,由于此时压力不可预知的,可能数据库瞬间压垮
- 双十一:停掉别的服务:比如退款请求(保证主要服务可用)
- 解决方案:
- 集群:异地多活
- 限流降级:(缓存失效后,通过加锁限制数据库的访问量)
- 数据预热:先模拟访问一遍,先加载到缓存中,并且手动设置不同过期时间,使失效时间尽量均匀
-
比如微博热搜,所有人都在高并发访问一个点的数据,但是这个点在缓存中比如60s过期,那么在过期的瞬间,大量请求涌入数据库,直接击穿缓存
- 解决方案
- 热点数据永不过期
- 加分布式锁,这样的话数据请求就会以分布锁的形式控制只有一个线程能进入到持久化数据库,其余线程等待
- 解决方案
-
缓存雪崩:在一个时间段,缓存中的数据全失或者集中过期失效
- 所有的数据全部砸在了数据库,此时对数据库产生周期性压力波峰,存储层调用量暴增,由于此时压力不可预知的,可能数据库瞬间压垮
- 双十一:停掉别的服务:比如退款请求(保证主要服务可用)
- 解决方案:
- 集群:异地多活
- 限流降级:(缓存失效后,通过加锁限制数据库的访问量)
- 数据预热:先模拟访问一遍,先加载到缓存中,并且手动设置不同过期时间,使失效时间尽量均匀