Redis笔记

** Redis**

要弄清问题先要知道问题的出现原因

Redis官方网站 http://Redis.io
Redis中文官方网站 http://www.Redis.net.cn

Redis是一个开源的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间价。它支持多种类型的数据类型,如五大常用数据类型:字符串string,集合set,哈希hash,列表list,有序集合sorted sets)和三种特殊数据类型(geospatial地址位置,hyperloglog基数统计,bitmaps位图。redis 也经常用来做分布式锁,支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。

打开一个 cmd 窗口 使用 cd 命令切换目录到 C:\redis 运行:

redis-server.exe redis.windows.conf

如果想方便的话,可以把 redis 的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个 redis.windows.conf 可以省略,如果省略,会启用默认的。输入之后,会显示如下界面:

Redis笔记_第1张图片
这时候另启一个 cmd 窗口,原来的不要关闭,不然就无法访问服务端了。

切换到 redis 目录下运行:

redis-cli.exe -h 127.0.0.1 -p 6379

端口号 6379

默认16个数据库,0-15

切换数据库 select + 数字

数据库大小 dbsize

设置数据库名字 set name + 名字

获取数据库名字 get + 名字

查看当前数据库所有的key keys *

清空当前数据库 flushdb

清楚所有数据库 flushall

Redis的应用场景

1.配合关系型数据库做高速缓存
高频次,热门访问的数据,降低数据库IO
2.由于其拥有持久化能力,利用其多样的数据结构存储特定的数据
最新N个数据→通过List实现按自然事件排序的数据
排行榜,TopN→利用zset(有序集合)
时效性的数据,比如手机验证码→Expire过期
计数器,秒杀→原子性,自增方法INCR、DECR
去除大量数据中的重复数据→利用set集合
构建队列→利用list集合
发布订阅消息系统→pub/sub模式

Redis是单线程 +多路IO复用技术!

很快,基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽
IO NIO
阻塞IO 非阻塞IO即NIO

什么是I/O 多路复用
在单个线程中通过记录跟踪每一个sock(I/O流) 的状态来管理多个I/O流。结合下图可以清晰地理解I/O多路复用。
Redis笔记_第2张图片
select, poll, epoll 都是I/O多路复用的具体的实现。epoll性能比其他几者要好。redis中的I/O多路复用的所有功能通过包装常见的select、epoll、evport和kqueue这些I/O多路复用函数库来实现的。
采用多路I/O复用技术:其一,可以让单个线程高效处理多个连接请求(尽量减少网络IO的时间消耗)。其二,Redis在内存中操作数据的速度非常快(内存里的操作不会成为这里的性能瓶颈)。主要以上两点造就了Redis具有很高的吞吐量。

多线程的本质就是 CPU 模拟出来多个线程的情况,这种模拟出来的情况就有一个代价,就是上下文的切换,对于一个内存的系统来说,它没有上下文的切换就是效率最高的。

Reactor(反应器模式)

IO多路复用模型是建立在内核提供的多路分离函数select基础之上的,使用select函数可以避免同步非阻塞IO模型中轮询等待的问题

为什么Redis是单线程的?

因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。
Redis 核心就是 如果我的数据全都在内存里,我单线程的去操作 就是效率最高的
详细原因
1)不需要各种锁的性能消耗
在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁、释放锁操作,没有因为可能出现死锁而导致的性能消耗。
2)CPU消耗
采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。
但是如果CPU成为Redis瓶颈,或者不想让服务器其他CPU核闲置,那怎么办?
可以考虑多起几个Redis进程,Redis是key-value数据库,不是关系数据库,数据之间没有约束。只要客户端分清哪些key放在哪个Redis

面试:Redis为什么单线程还那么快?

速度:CPU > 内存 > 硬盘

redis是将所有数据全部存放在内存中,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文切换是一种耗时的操作),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下,这个就是最佳的方案!

读速度11w/s,写速度8.1w/s!

五大数据类型

判断当前的key是否存在 exists name //key=name

移除当前的key move name

设置key过期时间 expire name 10

查看key过期剩余时间 ttl name

查看key数据类型 type name

1.String(字符串)

append key1 " "

strlen

incr 和 desr 是原子性操作

getrange key1 0 3 截取字符串

getrange key1 0 -1 查看所有的字符串

setex 设置过期时间

setnx 不存在设置(在分布式锁中会常常使用)

mget 获取key的值

同时设置多个值 mset k1 v1 k2 v2 k3 v3

同时获取多个值 mget k1 k2 k3

getset 如果不存在值则返回null,如果存在值,获取原来的值,并设置新的值

使用场景示例
hash类型应用场景:
淘宝购物车涉及与实现
业务分析:
仅分析购物车的redis存储模型。添加、浏览、更改数量、删除、清空
购物车于数据库间持久化同步(不讨论)
购物车于订单间关系(不讨论)
提交购物车:读取数据生成订单
商家临时价格调整:隶属于订单级别
未登录用户购物车信息存储(不讨论)
cookie存储
解决方案

以客户id作为key,每位客户创建一个hash存储结构存储对应的购物车信息
将商品编号作为field,购买数量作为value进行存储
添加商品:追加全新的field与value
浏览:遍历hash
更改数量:自增/自减,设置value值
删除商品:删除field
清空:删除key
此处仅讨论购物车中的模型设计
购物车与数据库间持久化同步、购物车与订单间关系、未登录用户购物车信息存储不进行讨论
场景2:双11活动日,销售手机充值卡的商家对移动、联通、电信的30元、 50元、 100元商品推出抢购活动,每种商品抢购上限1000张

解决方案
以商家id作为key,3个key
将参与抢购的商品id作为field
将参与抢购的商品数量作为对应的value
抢购时使用降值的方式控制产品数量
实际业务中还有超卖等实际问题,这里不做讨论
扩缩容的条件
正常情况下,当 hash 表中 元素的个数等于第一维数组的长度时,就会开始扩容,扩容的新数组是 原数组大小的 2 倍。不过如果 Redis 正在做 bgsave(持久化命令),为了减少内存也得过多分离,Redis 尽量不去扩容,但是如果 hash 表非常满了,达到了第一维数组长度的 5 倍了,这个时候就会 强制扩容。

当 hash 表因为元素逐渐被删除变得越来越稀疏时,Redis 会对 hash 表进行缩容来减少 hash 表的第一维数组空间占用。所用的条件是 元素个数低于数组长度的 10%,缩容不会考虑 Redis 是否在做 bgsave。

2.List (列表)
业务场景:
微信朋友圈点赞,要求按照点赞顺序显示点赞好友信息
如果取消点赞,移除对应好友信息
场景2:
twitter、新浪微博、腾讯微博中个人用户的关注列表需要按照用户的关注顺序进行展示,粉丝列表需要将最近关注的粉丝列在前面
新闻、资讯类网站如何将最新的新闻或资讯按照发生的时间顺序展示?
企业运营过程中,系统将产生出大量的运营数据,如何保障多台服务器操作日志的统一顺序输出?
解决方案
依赖list的数据具有顺序的特征对信息进行管理
使用队列模型解决多路信息汇总合并的问题
使用栈模型解决最新消息的问题

lpush list one

lpush list two

lpush list three

lrance list 0 -1 查看全部

Lpop list 移除列表最左端元素

Rpop list 移除列表最右端元素

Lpush

Lpop

Llen 查看List长度

ltrim 通过下标截取指定的长度,这个list已经被改变了,截取了只剩下最后的长度

rpoplpush 移除列表的最后一个元素,将他移到新的列表中

应用:

消息排队!消息队列(Lpush Rpop),栈(Lpush Lpop)

3.Set(集合)
缺点: 用户ID数据冗余
第三种方案: 通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题
场景:

每位用户首次使用今日头条时会设置3项爱好的内容,但是后期为了增加用户的活跃度、兴趣点,必须让用户对其他信息类别逐渐产生兴趣,增加客户留存度,如何实现?

业务分析

系统分析出各个分类的最新或最热点信息条目并组织成set集合
随机挑选其中部分信息
配合用户关注信息分类中的热点信息组织成展示的全信息集合
redis 应用于随机推荐类信息检索,例如热点歌单推荐,热点新闻推荐,热卖旅游线路,应用APP推荐,大V推荐等

场景2:

脉脉为了促进用户间的交流,保障业务成单率的提升,需要让每位用户拥有大量的好友,事实上职场新人不具有更多的职场好友,如何快速为用户积累更多的好友?
新浪微博为了增加用户热度,提高用户留存性,需要微博用户在关注更多的人,以此获得更多的信息或热门话题,如何提高用户关注他人的总量?
QQ新用户入网年龄越来越低,这些用户的朋友圈交际圈非常小,往往集中在一所学校甚至一个班级中,如何帮助用户快速积累好友用户带来更多的活跃度?
微信公众号是微信信息流通的渠道之一,增加用户关注的公众号成为提高用户活跃度的一种方式,如何帮助用户积累更多关注的公众号?
美团外卖为了提升成单量,必须帮助用户挖掘美食需求,如何推荐给用户最适合自己的美食?

Tips 9:
 redis 应用于同类信息的关联搜索,二度关联搜索,深度关联搜索
 显示共同关注(一度)
 显示共同好友(一度)
 由用户A出发,获取到好友用户B的好友信息列表(一度)
 由用户A出发,获取到好友用户B的购物清单列表(二度)
 由用户A出发,获取到好友用户B的游戏充值列表(二度)

set 类型数据操作的注意事项

set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份
set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
场景3:

集团公司共具有12000名员工,内部OA系统中具有700多个角色, 3000多个业务操作, 23000多种数据,每位员工具有一个或多个角色,如何快速进行业务操作的权限校验?

场景4:

公司对旗下新的网站做推广,统计网站的PV(访问量) ,UV(独立访客) ,IP(独立IP)。
PV:网站被访问次数,可通过刷新页面提高访问量
UV:网站被不同用户访问的次数,可通过cookie统计访问量,相同用户切换IP地址, UV不变
IP:网站被不同IP地址访问的总次数,可通过IP地址统计访问量,相同IP不同用户访问, IP不变

解决方案
 利用set集合的数据去重特征,记录各种访问数据
 建立string类型数据,利用incr统计日访问量( PV)
 建立set模型,记录不同cookie数量( UV)
 建立set模型,记录不同IP数量( IP)

tips:redis 应用于同类型数据的快速去重

场景5:

黑名单
资讯类信息类网站追求高访问量,但是由于其信息的价值,往往容易被不法分子利用,通过爬虫技术,快速获取信息,个别特种行业网站信息通过爬虫获取分析后,可以转换成商业机密进行出售。例如第三方火车票、机票、酒店刷票代购软件,电商刷评论、刷好评。
同时爬虫带来的伪流量也会给经营者带来错觉,产生错误的决策,有效避免网站被爬虫反复爬取成为每个网站都要考虑的基本问题。在基于技术层面区分出爬虫用户后,需要将此类用户进行有效的屏蔽,这就是黑名单的典型应用。
ps:不是说爬虫一定做摧毁性的工作,有些小型网站需要爬虫为其带来一些流量。

白名单
对于安全性更高的应用访问,仅仅靠黑名单是不能解决安全问题的,此时需要设定可访问的用户群体,
依赖白名单做更为苛刻的访问验证。

解决方案
 基于经营战略设定问题用户发现、鉴别规则
 周期性更新满足规则的用户黑名单,加入set集合
 用户行为信息达到后与黑名单进行比对,确认行为去向
 黑名单过滤IP地址:应用于开放游客访问权限的信息源
 黑名单过滤设备信息:应用于限定访问设备的信息源
 黑名单过滤用户:应用于基于访问权限的信息源
tips:redis 应用于基于黑名单与白名单设定的服务控制

sadd 添加

scard 获取

spop 随机移除

smembers 查看全部

数学集合类

sdiff key1 key2 差集

sinter key1 key2 交集

sunion key1 key2 并集

zrange key 0 10 withscores 显示全部

4.Hash (哈希)

Map集合,key-map ! 时候这个值是一个map集合!

hget hgetall

hmset

hlen

hexists

hash变更的数据user name age,尤其是用户信息之类的,经常变动的信息!hash 更适合于对象的存储

5.Zset(有序集合)
主要应用:排行榜
思考: 如何利用zset实现一个文章访问量的排行榜?
场景1:
票选广东十大杰出青年,各类综艺选秀海选投票
各类资源网站TOP10(电影,歌曲,文档,电商,游戏等)
聊天室活跃度统计
游戏好友亲密度
业务分析
 为所有参与排名的资源建立排序依据
 redis 应用于计数器组合排序功能对应的排名

注意事项:

score保存的数据存储空间是64位,如果是整数范围是-9007199254740992~9007199254740992
 score保存的数据也可以是一个双精度的double值,基于双精度浮点数的特征,可能会丢失精度,使用时候要慎重
 sorted_set 底层存储还是基于set结构的,因此数据不能重复,如果重复添加相同的数据, score值将被反复覆盖,保留最后一次修改的结果

场景2:

基础服务+增值服务类网站会设定各位会员的试用,让用户充分体验会员优势。例如观影试用VIP、游戏VIP体验、云盘下载体验VIP、数据查看体验VIP。当VIP体验到期后,如果有效管理此类信息。即便对于正式VIP用户也存在对应的管理方式。
网站会定期开启投票、讨论,限时进行,逾期作废。如何有效管理此类过期信息。

解决方案:

对于基于时间线限定的任务处理,将处理时间记录为score值,利用排序功能区分处理的先后顺序
 记录下一个要处理的时间,当到期后处理对应任务,移除redis中的记录,并记录下一个要处理的时间
 当新任务加入时,判定并更新当前下一个要处理的任务时间
 为提升sorted_set的性能,通常将任务根据特征存储成若干个sorted_set。例如1小时内, 1天内,周内,月内,季内,年度等,操作时逐级提升,将即将操作的若干个任务纳入到1小时内处理的队列中
time # 获取当前系统时间
1
tips: redis 应用于定时任务执行顺序管理或任务过期管理

场景3:
任务/消息权重设定应用
当任务或者消息待处理,形成了任务队列或消息队列时,对于高优先级的任务要保障对其优先处理,如何实现任务权重管理。

解决方案:
对于带有权重的任务,优先处理权重高的任务,采用score记录权重即可多条件任务权重设定
如果权重条件过多时,需要对排序score值进行处理,保障score值能够兼容2条件或者多条件,例如外贸订单优先于国内订单,总裁订单优先于员工订单,经理订单优先于员工订单
 因score长度受限,需要对数据进行截断处理,尤其是时间设置为小时或分钟级即可(折算后)
 先设定订单类别,后设定订单发起角色类别,整体score长度必须是统一的,不足位补0。第一排序规则首位不得是0
 例如外贸101,国内102,经理004,员工008。
 员工下的外贸单score值为101008(优先)
 经理下的国内单score值为102004

zadd

zcount key 1 3

zrangescore key -inf +inf 排序 -inf 负无穷 +inf 正无穷

zcard key 获取有序集合中的个数

案例思路:set 排序,存储班级成绩表,工资表排序!

普通消息,1,重要消息2,带权重进行判断!

排行榜应用实现,取Top N测试

三种特殊数据类型

1.geospatial (地理位置)

朋友的定位,附近的人,打车距离计算

只有6个命令

geoadd 添加地理位置的坐标

geodist 计算两个位置之间的距离

geohash 返回一个或多个位置对象的 geohash 值

geopos 获取地理位置的坐标

georadius 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合

georadiusbymember 根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合

georadiusbymember china:city beijing 1000km

我附近的人?(获得所有附近的人的地址,定位!)通过半径来查询!

获得指定数量的人,200

所有数据应该都录入:china:city,才会让结果更加请求!

GEO底层的实现原理就是 Zset!我们可以使用Zset命令来操作geo!

zrange china:city 0 -1 查看地图中全部的元素

zrem china:city beijing 移除指定元素

2.hyperloglog (基数统计)

优点:占用的内存是固定的,2^64不同的元素的技术,只需费12KB内存!如果要从内存角度来比较的话 hyperloglog是首选!

网页的 UV(一个人访问一个网站多次,但是还是算作一个人)

传统的方式,set保存用户的id,然后就可以统计 set中的元素数量作为标准判断!

这个方式如果保存了大量的用户id,就会比较麻烦!我们的目的是为了计数,而不是保存用户id;

0.81%错误率!统计UV任务,可以忽略不计的!

pfadd

pfcount

pfmerge 合并集合元素

如果允许容错,那么一定可以使用 hyperloglog

如果不允许容错,就使用 set 或者自己的数据类型即可

3.bitmaps (位图)

位存储

统计用户信息,活跃,不活跃!登录、未登录!打卡,365打卡!两个状态的都可以使用 Bitmaps !

Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!

setbit

getbit

bitcount

事务

Redis 事务本质:一组命令的集合!一个事务中所有的命令都会被序列化,在事务执行过程中,会被按照顺序执行!

一次性、顺序性、排他性!执行一系列的命令!

队列 set set set 执行

Redis事务没有隔离级别的概念!

所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会被执行!Exex

Redis单条命令保证原子性,但是事务不保证原子性!

redis的事务:

  • 开启事务() multi

  • 命令入对()

  • 执行事务() exec

Redis笔记_第3张图片

放弃事务 discard

Redis笔记_第4张图片

编译型异常(代码有问题!命令有错!),事务中的所有命令都不会被执行!

Redis笔记_第5张图片

代码逻辑错误(运行时异常 ),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!

Redis笔记_第6张图片
业务场景
天猫双11热卖过程中,对已经售罄的货物追加补货, 4个业务员都有权限进行补货。补货的操作可能是一系列的操作,牵扯到多个连续操作,如何保障不会重复操作?

业务分析:
 多个客户端有可能同时操作同一组数据,并且该数据一旦被操作修改后,将不适用于继续操作
 在操作之前锁定要操作的数据,一旦发生变化,终止当前操作

监控 Watch(面试常问!)

悲观锁

很悲观,认为什么时候都会出问题,无论做什么都会加锁!

乐观锁

很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据

获取version

更新的时候比较 version

Redis 测监视测试

加锁 watch

解锁 unwatch

Redis笔记_第7张图片

Jedis

java连接开发工具!使用 Java 操作 Redis 中间件!

导入 jedis 和 fastjson 的包

连接数据库,测试,断开连接

常用API Stirng List Set Hash Zset

Springboot 整合

Springboot 操作数据:spring-data jpa jdbc redis

  1. 导入依赖
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-redisartifactId>
dependency>

jedis:采用的直连,多个线程操作的话,是不安全的。如果要避免不安全,使用jedis pool连接池!更像BIO模式

lettuce:采用netty,实例可以在多个线程中共享,不存在线程不安全的情况!可以减少线程数据了,更像NIO模式

序列化

实现 Serializable 接口

自定义系列化模版

存储在redis中数据乱码,会有转义字符。比如默认jdkSerializeable序列化后cli示:"\xac\xed\x00\x05t\x00\bcustomer",此刻在cli中get customer 为nil,为避免这种情况的出现,可自行修改序列化方式。只需自定义序列化类redisTemplate,使用时正常调用RedisTemplate类即可。

Redis.conf详解

启动的时候通过配置文件

单位 (Unit)

配置文件 unit单位 对大小写不敏感

包含 (INCLUDES)

网络 ( NETWORK )

bind 127.0.0.1			#绑定的ip
protected-mode yes		#保护模式
port 6379				#端口设置

通用 (GENERAL)

daemonize yes			#以守护进程的方式运行,默认是no,我们需要开启为yes
piffile /var/run/redis_6379.pid		#如果以后台的方式运行,我们就需要指定一个pid文件

loglevel notice			#日志级别
logfile ""				#日志的文件位置名
database 16				#数据库的数量,默认是16个数据库
always-show-logo yes	#是否总是显示logo

快照 ( SNAPSHOT )

持久化,在规定的时间内执行了多少次凑在哦,则会持久化到文件.rdb .aof

redis是内存数据库,如果没有持久化,那么数据断电即失

save 900 1 #如果900秒内,至少有一个key进行了修改,那么久进行持久化操作
stop-writes-on-bgsave-error yes	#持久化如果出错,是否继续工作
rdbcompression yes				#是否压缩rdb文件,需要消耗一些CPU资源
rdbchecksum yes					#保存rdb文件时,进行错误的检查校验
dir ./							#rdb文件保存的目录

赋值 (REPLICATION)

安全 (SECURITY)

设置密码

Redis笔记_第8张图片

限制 (CLIENTS )

maxclients 10000		#设置能连接redis的最大客户数量
maxmemory <bytes>		#redis配置最大的内存数量
maxmemory-policy noeviction		#内存达到上限之后的处理策略

APPEND ONLY 模式 aof配置

appendonly no			#默认不开启aof模式,默认开启rdb方式持久化
appendfilename "appendonly.aof"		#持久化的文件名字

#appendfsync always		#每次修改都会sync 消耗性能
appendfsync everysec	#每秒执行一次 可能会丢失这一秒的数据
#appendfsync no			#不执行sync 这个时候操作系统自己同步数据 速度最快

Redis持久化

RDB(Redis DataBase) rdb保存的文件 dump.rdb

触发机制

1.save的规则满足情况下,如save 60 5 (60s改变5次)

2.执行flushall命令

3.退出redis,也会产生redis

备份就自动生成一个 dump.rdb

如何恢复 rdb 文件!

1.只需要将 rdb文件放在我们redis启动目录就可以,redis启动时会自动检查 dump.rdb恢复其中的数据!

2.查看需要存在的位置 config get dir

优点

1.适合大规模的数据恢复

2.对数据的完整性不高!

缺点

1.需要一定的时间间隔进程操作!如果redis意外宕机,这个最后一次修改数据就没有的了!

2.fork进程的时候,会占用一定的内存空间!

AOF(Append only file )

Aof保存的是 appendonly.aof

默认不开启的,需要手动配置!只需要将 appendonly.aof 改为 yes 就开启了 aof !

重写规则说明

如果 aof 文件大于 64m,太大了!fork 一个新的进程来将我们的文件进行重写!

优点和缺点

优点

1.每一秒修改都同步,文件的完整会更加好!

2.每秒同步一次,可能会丢失一秒的数据

3.从不同步,效率最高

缺点

1.相对于数据文件来说,aof远远大于 rdb,恢复的速度也比 rdb 慢!

2.Aof 运行效率也要比 rdb 慢所以我们 redis 默认的配置就是 rdb持久化!

Redis发布订阅

发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接受消息。微信、微博、关注系统!

Redis客户端可以订阅任意数量的频道

订阅端 subscribe channel

发送端 publish channel message

使用场景:

1.实时消息系统!

2.实时聊天!(频道当作聊天室,将消息回显给所有人)

3.订阅、关注系统都是可以的!

稍微复杂的场景就会使用 消息中间件 MQ()

Redis主从复制

概念
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower), 数据的复制是单向的!只能由主节点复制到从节点(主节点以写为主、从节点以读为主)。

默认情况下,每台Redis服务器都是主节点,一个主节点可以有0个或者多个从节点,但每个从节点只能由一个主节点。

作用
数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余的方式。
故障恢复:当主节点故障时,从节点可以暂时替代主节点提供服务,是一种服务冗余的方式
负载均衡:在主从复制的基础上,配合读写分离,由主节点进行写操作,从节点进行读操作,分担服务器的负载;尤其是在多读少写的场景下,通过多个从节点分担负载,提高并发量。
高可用基石:主从复制还是哨兵和集群能够实施的基础。
为什么使用集群
单台服务器难以负载大量的请求
单台服务器故障率高,系统崩坏概率大
单台服务器内存容量有限。

一主多从

环境配置

复制3个配置文件然后修改对应的信息

1.端口

2.pid名字

3.log文件名字

4.dump.rdb名字

从机只能读,不能写,主机可读可写但是多用于写。

127.0.0.1:6381> set name sakura # 从机6381写入失败
(error) READONLY You can’t write against a read only replica.

127.0.0.1:6380> set name sakura # 从机6380写入失败
(error) READONLY You can’t write against a read only replica.

127.0.0.1:6379> set name sakura
OK
127.0.0.1:6379> get name
“sakura”

当主机断电宕机后,默认情况下从机的角色不会发生变化 ,集群中只是失去了写操作,当主机恢复以后,又会连接上从机恢复原状。

当从机断电宕机后,若不是使用配置文件配置的从机,再次启动后作为主机是无法获取之前主机的数据的,若此时重新配置称为从机,又可以获取到主机的所有数据。这里就要提到一个同步原理。

第二条中提到,默认情况下,主机故障后,不会出现新的主机,有两种方式可以产生新的主机:

从机手动执行命令slaveof no one,这样执行以后从机会独立出来成为一个主机
使用哨兵模式(自动选举)
如果没有老大了,这个时候能不能选择出来一个老大呢?手动!

如果主机断开了连接,我们可以使用SLAVEOF no one让自己变成主机!其他的节点就可以手动连接到最新的主节点(手动)!如果这个时候老大修复了,那么久重新连接!

一主二从

默认下,每台redis服务器都是主节点

认定老大

slaveof 主机ip 端口

自己当老大

slaveof no one

细节

主机可以写,从机不能写只能读!主机中的所有信息和数据,都保存于从机中

info replication

哨兵模式(自动选举老大的模式)

原理:哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例

然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

测试 ( 一主二从 )

1,配置哨兵配置文件 sentienel.conf

2.启动哨兵

redis-sentinel

优点:

1.哨兵集群,基于主从复制模式,所有的主从配置优点,它全有

2.主从可以切换,故障可以转移,系统的可用性就会更好

3.哨兵模式就是主从模式的升级,手动到自动,更加健壮

缺点:

1.Redis 不好在线扩容的,集群一旦到达上限,在线扩容就十分麻烦!

2.实现哨兵模式的配置其实还是很麻烦的,里面有很多选择!

哨兵模式的全部配置!

Redis缓存穿透和雪崩(面试高频,工作常用)

服务器的高可用

缓存穿透(查不到)

在默认情况下,用户请求数据时,会先在缓存(Redis)中查找,若没找到即缓存未命中,再在数据库中进行查找,数量少可能问题不大,可是一旦大量的请求数据(例如秒杀场景)缓存都没有命中的话,就会全部转移到数据库上,造成数据库极大的压力,就有可能导致数据库崩溃。网络安全中也有人恶意使用这种手段进行攻击被称为洪水攻击。

解决方案

1.布隆过滤器

对所有可能查询的参数以Hash的形式存储,以便快速确定是否存在这个值,在控制层先进行拦截校验,校验不通过直接打回,减轻了存储系统的压力。

2.缓存空对象

一次请求若在缓存和数据库中都没找到,就在缓存中方一个空对象用于处理后续这个请求。

缓存击穿(量太大,缓存过期!)

一次请求若在缓存和数据库中都没找到,就在缓存中方一个空对象用于处理后续这个请求。

解决方案

1.设置热点数据永不过期

这样就不会出现热点数据过期的情况,但是当Redis内存空间满的时候也会清理部分数据,而且此种方案会占用空间,一旦热点数据多了起来,就会占用部分空间。

2.加互斥锁

在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。保证同时刻只有一个线程访问。这样对锁的要求就十分高。

缓存雪崩

大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。

双十一:停掉一些服务,(保证主要的服务可用!)

解决方案:

1.redis高可用

既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群

2.限流降级

在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

3.数据预热

攻击。

解决方案

1.布隆过滤器

对所有可能查询的参数以Hash的形式存储,以便快速确定是否存在这个值,在控制层先进行拦截校验,校验不通过直接打回,减轻了存储系统的压力。

2.缓存空对象

一次请求若在缓存和数据库中都没找到,就在缓存中方一个空对象用于处理后续这个请求。

缓存击穿(量太大,缓存过期!)

一次请求若在缓存和数据库中都没找到,就在缓存中方一个空对象用于处理后续这个请求。

解决方案

1.设置热点数据永不过期

这样就不会出现热点数据过期的情况,但是当Redis内存空间满的时候也会清理部分数据,而且此种方案会占用空间,一旦热点数据多了起来,就会占用部分空间。

2.加互斥锁

在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。保证同时刻只有一个线程访问。这样对锁的要求就十分高。

缓存雪崩

大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。

双十一:停掉一些服务,(保证主要的服务可用!)

解决方案:

1.redis高可用

既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群

2.限流降级

在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

3.数据预热

在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

分布式数据库中CAP原理

  • C:Consistency(强一致性)
  • A:Availability(可用性)
  • P:Partition tolerance(分区容错性)
    CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。
    注意:分布式架构的时候必须做出取舍。一致性和可用性之间取一个平衡。多余大多数web应用,其实并不需要强一致性。
    因此牺牲C换取P,这是目前分布式数据库产品的方向

BASE

BASE就是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。
BASE其实是下面三个术语的缩写:
基本可用(Basically Available)
软状态(Soft state)
最终一致(Eventually consistent)
它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观。为什么这么说呢,缘由就在于大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些指标,我们必须采用另外一种方式来完成,这里BASE就是解决这个问题的办法

技术的分类
1.解决功能性的问题
java、Servlet、Jsp、Tomcat、RDBMS、JDBC、Linux、Svn 等
2.解决扩展性的问题
Spring、 SpringMVC、SpringBoot、Hibernate、MyBatis等
3.解决性能的问题
NoSQL、java多线程、Nginx、MQ、ElasticSearch、Hadoop等

思考: Session共享问题如何解决?
方案一、存在Cookie中
此种方案需要将Session数据以Cookie的形式存在客户端,不安全,网络负担效率低
方案二、存在文件服务器或者是数据库里
此种方案会导致大量的IO操作,效率低.
方案三、Session复制
此种方案会导致每个服务器之间必须将Session广播到集群内的每个节点,Session数据会冗余,节点越多浪费越大,存在广播风暴问题.
方案四、存在Redis中
目前来看,此种方案是最好的。将Session数据存在内存中,每台服务器都从内存中读取数据,速度快,结构还相对简单.

解决IO压力
Redis笔记_第9张图片

将活跃的数据缓存到Redis中,客户端的请求先打到缓存中来获取对应的数据,如果能获取到,直接返回,不需要从MySQL中读取。如果缓存中没有,再从MySQL数据库中读取数据,将读取的数据返回并存一份到Redis中,方便下次读取.
扩展: 对于持久化的数据库来说,单个库单个表存在性能瓶颈,因此会通过水平切分、垂直切分、读取分离等技术提升性能,此种解决方案会破坏一定的业务逻辑,但是可以换取更高的性能.

你可能感兴趣的:(数据库,redis,缓存,数据库)