Redis

NoSQL数据库简介

用NoSQL打破了传统的关系型数据库,以业务逻辑为依据处理存储模式,针对不同数据结构的类型改变以性能为最优先的存储方式,目的就是提高性能

技术的分类:
1.解决功能性的问题(实现一个功能用的这些技术):Java、Jsp、RDBMS、Tomcat、HTML、Linux、JDBC、SVN
2.解决扩展性的问题(加入、修改功能需要用到的技术):Struts、Spring、SpringMVC、Hibrenate、Mybatis
3.解决性能的问题(解决用户量竞争访问,解决性能需要用到的技术):NoSQL、Java线程、Hadoop、Nginx、MQ、ElasticSearch

session的共享问题:
第一种方案:存储到客户端中,或是放在cookie中,好处:每次请求都会带有cookie中,里面都会有用户信息,能保证session共享,缺点:存到客户端中,安全问题

第二种方案:session复制,在第一台服务器登录了,产生了session对象,然后把session对象复制了多份到其他台服务器中,能保证session是同步的,缺点:session是复制的,复制的意思表示session对象是一样的,造成空间极大的浪费,每个里面都存储相同的对象

第三种方案:NoSQL数据库,可以吧用户信息存储到NoSQL数据库中,比如第一次登录后存储,第二次访问就看开NoSQL有没有信息,有的话就登陆,没有就不能登录,好处:不需要经过IO操作,数据完全存到内存中,读的速度更快,解决CPU和内存的方案

NoSQL解决IO压力
在这里插入图片描述

NoSQL数据库

NoSQL数据库概述

NoSQL(NoSQL = Not Only SQL),意思是“不仅仅是SQL”,泛指非关系型数据库
NoSQL不依赖业务逻辑方式存储,而以简单的key-value模式存储,因此大大的增加了数据库的扩展能力

  • 不遵循SQL标准
  • 不支持ACID(原子性、可见性、隔离性、有序性)
  • 远超于SQL的性能
NoSQL适用场景
  • 对数据高并发的读写
  • 海量数据的读写
  • 对数据高可扩展性
NoSQL不适用场景
  • 需要事务支持
  • 基于sql的结构化查询存储吗,处理复杂的关系,需要即席查询
    (用不着sql的和用不了sql也不行的情况,请考虑用NoSQL)

在这里插入图片描述
在这里插入图片描述

行式存储数据库

行式数据库

在这里插入图片描述

列式数据库

在这里插入图片描述

Redis概述

在这里插入图片描述

配合关系型数据库做高速缓存
  • 高频次,热门访问的数据,降低数据库IO
  • 分布式架构,做session共享
多样的数据结构存储持久化数据

在这里插入图片描述

Redis安装

1.首先利用Xshell进入linux
2.安装c语言编译环境,gcc版本

yum install gcc

3.查询版本

gcc --version

4.进入opt文件夹(这里我是放在这个文件夹的)

5.解压redis压缩包

tar -zxvf 文件名

6.进入解压后的文件

7.使用make编译安装
注意:如果没有C语言编译环境,make会报错

进入src目录下执行make install

8.安装后进入 usr/local/bin 目录下有这么几个文件:
在这里插入图片描述
分别是:
在这里插入图片描述
前台启动:(不推荐)

redis-server

在这里插入图片描述

后台启动:(推荐)

  1. 回到 解压后 redis的文件夹
  2. 复制redis.conf文件到etc目录下
cp redis.conf /etc/redis.conf
  1. 后台启动设置daemonize no 改成 yes
vim redis.conf

进入文件夹

找到daemonize no改成yes

再次启动redis服务,并指定启动服务配置文件

 redis-server /etc/redis.conf

启动成功!
在这里插入图片描述

比如吧窗口关掉了,redis还在启动,因为是后台启动

  1. redis-cli 通过后端连接redis关闭,使用shutdown命令

Redis相关知识

端口6379从何而来:Alessia Merz(九键6379的对位)
在这里插入图片描述
Redis:单线程+多线IO复用
在这里插入图片描述

常用五大数据类型

Redis键(Key)
  1. keys * 查看当前库所有key
  2. exists key 判断某个key是否存在 返回1就表示有 返回0就是没有
  3. type key 查看你的key是什么数据类型
  4. del key 删除指定的key数据
  5. unlink key 根绝value选择非阻塞删除
  6. set key键 value值 增加操作
  7. expire key 10 为指定的key设置过期时间
  8. ttl key 查看还有多少s过期 -1永不过期 -2表示已过期
  9. select 切换库
  10. dbsize 查看当前库里又多少key

常用数据类型 字符串(String)

在这里插入图片描述

常用命令
  • set key value 添加键值对(设置相同的key就把之前的覆盖了)
  • get key 查询对应键值对
  • append key 将给的value值追加到原值的末尾
  • strlen key 获得值的长度
  • setnx key value 只有在key不存在时 设置key的值
  • incr key 将key中存储的数字值增1 只能对数字值操作,如果为空,新增值为1
  • decr key 将key中存储的数字值捡1 只能对数字值操作,如果为空,新增值为-1
  • incrby decrby key 步长 将key中存储的数字值增减 自定义步长 只能对数字值操作(步长:自定义数字)

原子操作
在这里插入图片描述

  • mset key1 key2… 同时设置一个或者多个key-value对
  • mget 同时获取一个或者多个key-value对
  • msetnx 同时设置一个或多个key-value对 仅当所有给定key都不存在
    原子性,有一个失效,都会失效
  • getrange key 起始位置 结束位置;获取值的范围(含头含尾)
  • setrange key 位置 覆盖的值 ;覆写key所存储的字符串值
  • setex key 过期时间 value值
  • getset key value 以新值换旧值
String数据结构

在这里插入图片描述
什么叫动态字符串?
就可以修改字符串的值
在这里插入图片描述

Redis 列表 (List)

在这里插入图片描述

常用命令

在这里插入图片描述

  • lpus/rpush key value1 value2 ;从左边/右边插入一个或多个值
    在这里插入图片描述
    v1本来是在第一个格子,然后v2进来吧v1挤到第二个格子,v2就在第一个格子 以此类推

Redis列表(List)

常用命令

在这里插入图片描述
在这里插入图片描述

数据结构

quickList
List数据结构快速链表 quickList
首先在列表元素较少的情况会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表

它将所有的元素紧挨着一起存储,分配的是一块连续的内存

当数据量比较多的时候才会改成quickList

因为普通的链表需要的附加指针空间太大,会比较浪费空间,比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next

在这里插入图片描述
Redis将链表和ziplist结合起来组成了quicklist,也就是将多个ziplist使用双向指针串起来使用,这样既满足了快速的插入删除性能,又不会出现太大的空间冗余

Redis集合(Set)

Redis Set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的

Redis的set是string类型的无序集合,它底层其实是一个value为null的hash表,所以添加、删除、查找的复杂度是0(1)

一个算法,随着数据的增加,执行时间的长短,如果是0(1),数据增加,查找数据的时间不变

常用命令
  • sadd key value 将一个或者多个member元素加入到集合key中,已经存在的member元素将被忽略
  • smenbers key 取出该集合的所有值
  • sismember key value 判断集合key是否为含有该value值 有1 没有0
  • scard key 返回该集合的元素个数
  • srem key value 删除集合中的某个元素
  • spop key 随机从该集合中吐出一个值
  • srandmember key n 随机从该集合中取出n个值,不会从集合中删除
  • smove source destination value 吧集合中一个值从一个集合移动到另一个集合
  • sinter key1 key2 返回两个集合的交集*(相同的)元素
  • sunion key1 key2 返回两个集合的并集(所有的)元素
set数据结构

Java中HashSet内部实现使用的是HashMap,只不过所有的value都指向同一个对象,Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值

Redis哈希(Hash)

Redis hash是一个键值对集合

Redis hash是一个string类型的field合value的映射表,hash特别适合用于存储对象类似java里面的Map<String,Object>

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构赖存储
主要有以下两种存储方式:
在这里插入图片描述
最好用hash存储方式:
在这里插入图片描述
通过key(用户ID)+field(属性标签)就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题
在这里插入图片描述

常用命令
  • hset key filed value 给key集合中的field键赋值value值
  • hget key field 从key1集合field取出value
  • hmset key1 field1 value1 field2 value2 批量设置hash的值
  • hexists ke1 field 查看哈希表key中,给定域field是否存在,真返回1 假返回0
  • hkeys key 列出该hash集合所有的field
  • hvals key 列出该hash集合所有的value
  • hincrby key field increment 为哈希表key中的域field的值加上增量1,加值
  • hsetnx key field value 将哈希表中的域field值设置为value 当且仅当域field不存在,field值有就不能加,没有就可以加
数据结构

Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表),当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable

配置文件

单位设置方式:
只支持bytes,不支持bit

在这里插入图片描述
网络相关配置:
在这里插入图片描述
bind
默认情况bind=127.0.0.1只能接受本机的访问请求
不写的情况下,无限制接受任何ip地址的访问

生产环境肯定要写你应用服务器的地址:服务器是需要远程访问的,所以需要将其注释掉

如果开起来protected-mode,那么在没有设定bind ip且没有设密码的情况下,Redis只允许接受本机的响应

开启保护模式:
在这里插入图片描述
改成no就是关闭保护模式,支持远程访问

tcp-backlog
设置tcp的backlog,backlog其实是一个链接队列,backlog队列总和=未完成三次握手队列+已经完成三次握手队列

在高并发环境下你需要意个高backlog值来避免客户端连接问题

监测心跳:
在这里插入图片描述
设置日志的输入路径
在这里插入图片描述
默认的库有多少 个
在这里插入图片描述
LIMITS限制
设置redis同时可以与多少个客户端进行连接
默认情况下为10000个客户端
如果达到了此限制,redis则会拒绝新的连接请求,并且向这些连接请求方发出max number of client reached 已做回应

Redis发布和订阅

什么是发布和订阅
Redis发布订阅(pub/sub)是一种消息通信 模式:发送者(pub)发送消息,订阅者(sub)接收消息

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

发布订阅命令行实现

1.打开一个客户端订阅channe11
SUBSCRIBE channe11
在这里插入图片描述

2.打开另一个客户端,给channe11发布消息hello
publish channe11 hello
在这里插入图片描述

3.打开第一个客户端可以看到发送的消息
在这里插入图片描述

新数据类型-Bitmaps

简介:
在这里插入图片描述
Redis提供了Bitmaps这个“数据类型”可以实现对位的操作:
(1)Bitmaps本身不是一种数据类型,实际上它就是字符串(Key-value),但是它可以对字符串的位进行操作
(2)Bitmaps单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同,可以吧Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在Bitmaps中叫做偏移量

offset:偏移量

格式:
setbit key offset value 设置Bitmaps 中某个偏移量的值(0或1)1设置被访问,0未访问
偏移量从0开始

getbit key offset 获取偏移量是否被访问过

bitcount
统计字符串被设置为1的bit数,一般情况下,给定的整个字符串都会被进行计数,通过指定额外的start或end参数,可以让计数只在特定的位上进行,start和end参数的设置,都可以使用负数值:比如-1 表示最后一个位,而-2表示倒数第二个位,start、end是指bit组的字节的下表述,二者皆包含

bitcount key 统计字符串start字节到end字节的比特值为1(被访问)的数量

bitop and unique:users:and:20201104_03
unique:users:20201103unique:users:20201104

Bitmaps与set对比

用户量大就用Bitmaps:
在这里插入图片描述
用户量小用set集合
在这里插入图片描述

新数据类型-HyperLogLog

统计页面访问量

在工作当中,我们经常会遇到与统计相关的功能需求,比如统计网站PV(PageView页面访问量),可以使用Redis的incr、incrby轻松实现

但像UV(UniqueVisitor,独立访客)、独立ip数、搜索记录数等需要去重和计数的问题如何解决?这种求集合中不重复元素个数的问题称为基数问题

解决基数问题有很多种方案:
(1)数据存储在MySQL表中,使用distinct count计算不重复个数
(2)使用Redis提供的hash、set、bitmaps等数据结构来处理
以上的方案结果精确,但随着数据不断增加,导致占用空间越来越大,对于非常大的数据集是不切实际的

是否能降低一定的精度来平衡存储空间?Redis推出了HyperLogLog

Redis HyperLogLog是用来做基数统计的算法,HyperLogLog的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的

在Redis里面,每个HyperLogLog键只需要花费12kb内存,就可以计算接近2^64个不同元素的基数,这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比

但是因为HyperLogLog只会根据输入元素来计算基数,而不会储存输入元素本身,所以HyperLogLog不能像集合那样,返回输入的各个元素

什么是基数

比如数据集{1,3,5,7,5,7,8,},那么这个数据集的基数集为{1,3,5,7,8}基数(不重复元素)为5,基数估计就是在误差可接受的范围内,快速计算基数

命令
pfadd key “elemnt” 添加指定元素到HeyperLogLog中, 成功1,失败0

pfcount key 统计基数

pfmerge destkey sourcekey 将一个或多个HLL合并后的结果存储在另一个HLL中,比如每月活跃用户可以使用每天的活跃用户合并计算可得

新数据类型-Geospatial

简介
Redis 3.2中增加了对GEO类型的支持,GEO,Geographic,地理信息的缩写,该类型,就是元素的2维坐标,在地图上就是经纬度,redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度hash等常见操作

有效的经度从-180 到 180度 纬度从-85.05112878到85.05112878

当坐标位置超出指定范围,该命令会返回一个错误,已经添加的数据,是无法再往里面添加的

命令
geoadd key longitude latitude member 添加地理位置
在这里插入图片描述
geopos key longitude 获取地理位置
在这里插入图片描述

geodist key member1 member2 获取两个位置之间的直线距离
在这里插入图片描述
单位: m 米 km 千米 mi 英里 ft 英尺

Redis客户端工具:Jedis操作-测试

Jedis所需要的jar包

		<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>

在Linux中防火墙:

systemctl status firewalld

在这里插入图片描述
关闭:

systemctl stop firewalld

操作key,得到redis里面所有的数据

@Test
    public void demo1() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        Set<String> keys = jedis.keys("*");
        for (String s : keys) {
            System.out.println(s);
        }
    }

添加key

//添加
    @Test
    public void demo2() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        //添加
        jedis.set("name", "lucy");
        //获取
        String name = jedis.get("name");
        System.out.println(name);
        
        Set<String> keys = jedis.keys("*");
        for (String s : keys) {
            System.out.println(s);
        }
    }

Jedis-API:String

//设置多个key-value
        jedis.mset("k1", "v1", "k2", "v2");
        List<String> mget = jedis.mget("k1", "k2");
        System.out.println(mget);

Jedis-API:List

//操作list
    @Test
    public void demo3() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        jedis.lpush("key1", "lucy", "mary", "jack");
        List<String> key1 = jedis.lrange("key1", 0, -1);
        System.out.println(key1);
    }

Jedis-API:Set

//操作set
    @Test
    public void demo4() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        jedis.sadd("names", "lucy");
        jedis.sadd("names", "mary");
        Set<String> name = jedis.smembers("names");
        System.out.println(name);
    }

Jedis-API:Hash

//操作hash
    @Test
    public void demo5() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        jedis.hset("users", "age", "20");
        String hget = jedis.hget("users", "age");
        System.out.println(hget);
    }

事务和锁机制-基本操作

Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序的执行,事务在执行的过程中,不会被其他客户端发送来的命令请求所打断

Redis事务的主要作用就是串联多个命令防止别的命令插队

Multi、Exec、discard

从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行
组队的过程中可以通过discard来放弃组队
在这里插入图片描述

事务的基本操作

表示已经开启了事务
在这里插入图片描述
新建队列
在这里插入图片描述
执行
在这里插入图片描述
放弃
在这里插入图片描述

事务的错误处理

在这里插入图片描述
如果执行某个阶段命令报了错误,则只有报错的命令不会被执行,其他的命令都会执行,不会回滚

在这里插入图片描述
在这里插入图片描述

组队不会报错,执行会报错,因为incr是自增+1,组队就放进去了,但是v1不是数字就不能加1,所以执行的时候会报错

在这里插入图片描述

事务和锁机制-事务冲突(悲观锁和乐观锁)

为什么要做成事务

想想一个场景:有很多人有你的账户,同时去参加双十一抢购

事务冲突的问题

在这里插入图片描述

悲观锁

在这里插入图片描述
悲观锁(Pessimistic Lock),顾名思义,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁,传统的关系型数据库里面就用到了很多这样的锁机制,比如行锁、表锁等,读锁、写锁等,都是在操作之前先上锁
在这里插入图片描述

乐观锁

通过版本号进行操作
在这里插入图片描述
乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制,乐观锁适用于多读的应用类型,这样可以提高吞吐量,Redis就是利用这种check-and-set机制实现事务的

演示乐观锁和事务特性

WATCH key[key…]
在执行multi之前,先执行waych key1[key2],可以监视一个(或多个)key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断

第一个:
在这里插入图片描述
第二个:
在这里插入图片描述
UNWATCH
取消WATCH命令对所有key的监视
如果在执行WATCH命令之后,EXEC命令或DISCARD命令先被执行了的话,那么就不需要在执行UNWATCH了

Redis事务三特性

  • 单独的隔离操作
    • 事务中的所有命令都会序列化、按顺序执行,事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
  • 没有隔离级别的概念
    • 队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行
  • 不保证原子性
    • 事务中如果有一条命令执行失败,其后的命令仍然会被执行,不会回滚

Redis主从复制

主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

在这里插入图片描述

Redis主从复制-搭建一主多从

先在根目录下创建一个文件夹并进入:
在这里插入图片描述
复制redis.conf配置文件到文件夹中
在这里插入图片描述
配置一主两从的,创建三个配置文件
命名为:redis6379.conf、edis6380.conf、edis6381.conf

从之前conf文件中把appendonly yes改为no

在myredis下创建文件vi redis.conf

在配置文件中写入内容
在这里插入图片描述
用同样的方式创建6380、6381
在这里插入图片描述
启动三台redis服务器
在这里插入图片描述
查看进程的方式

ps -ef | grep redis

在这里插入图片描述
三台服务器连接6379 80 81
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

查看三台主机运行情况

info replication

在这里插入图片描述
配从不配主

slaveof ip port

在6380 6381上执行:slaveof 127.0.0.1 6379
加上后就能作为当前6379里面的从机操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意:从机里面不能做写操作,只能做读操作
在这里插入图片描述

复制原理的一主二从

主机挂掉了,从机也只认这一个主机
主机重新启动还是主服务器
在这里插入图片描述

在这里插入图片描述

主从复制-薪火相传和反客为主

薪火相传

上一个slave可以是下一个slave的master,slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个master可以有效减轻master的写压力,去中心化降低风险

用slaveof ip port
中途变更转向:会清除之前的数据,重新建立拷贝最新的
风险是一旦某个slave宕机,后面的slave都没法备份
主机挂了,从机还是从机,无法写数据了
在这里插入图片描述
在这里插入图片描述
从机之间连接
在这里插入图片描述

反客为主

用slaveof on one 将从机变成主机

哨兵模式

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库(相当于一个谍报人员,从库加一个哨兵到主机,如果主机挂掉了,这个从库立马变为主机)
在这里插入图片描述
还原一主二从的搭建
在这里插入图片描述
自定义在/myredis 目录下新建sentinel.conf文件 名字绝不能错

sentinel monitor mymaster 127.0.0.1 6379 1

在这里插入图片描述
启动配置文件

redis-sentinel sentinel.conf 

在这里插入图片描述
当主机挂掉,从机选举中产生新的主机
先挂掉主机
在这里插入图片描述
然后哨兵这边自动显示
在这里插入图片描述

故障恢复

在这里插入图片描述
偏移量最大的替代被挂掉的主机,偏移量就是主机挂掉之前和某一个从机同步量最高的

集群

Redis集群

容量不够,redis如何进行扩容?

并发写操作吗,redis如何分摊?

另外主从模式,薪火相传模式,主机宕机,导致ip地址发生变化,应用程序中配置需要修改对应的主机地址、端口等信息

之前通过代理主机来解决,但是redis3.0中提供了解决方案,就是无中心化集群配置
在这里插入图片描述
任何一台服务器都可以作为集群的入口,比如通过订单进入集群,正好访问的不是用户数据,那么订单该怎么做?订单吧请求转移给用户去操作,比如现在有个操作也不是用户做的,那么用户就转移给商品,商品转移给订单,可以互相进行访问,这就是无中心化集群

什么是集群
Redis集群实现了对Redis的水平扩容,既启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N

Redis集群通过分区(Partition)来提供一定程度的可用性;即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求

搭建Redis集群

删除带有dump63的文件

rm -rf dump63*

在这里插入图片描述
更改redis6379的配置文件
在这里插入图片描述

复制出同样的几份分别为6380 6381 6389 6390 6391,并在文件里面做响应的修改

启动6379 6380 6381 6389 6390 6391配置文件
在这里插入图片描述

查询进程

ps -ef | grep redis

在这里插入图片描述
将六个节点合成一个集群
组合之前确保所有redis启动,nodex-xxxx.conf文件都生成正常

在这里插入图片描述
进入 /opt/redis/src目录下查找一个集成文件
在这里插入图片描述
在src目录下使用命令

redis-cli --cluster create --cluster-replicas 1 192.168.255.100:6379 192.168.255.100:6380 192.168.255.100:6381 192.168.255.100:6389 192.168.255.100:6390 192.168.255.100:6391 

此处不要用127.0.0.1 请用真实ip地址
–replicas 1 采用最简单的方式配置集群,一个主机,一个从机,正好三组

默认分配三组各组的主机
在这里插入图片描述
回答yes
在这里插入图片描述

-c采用集群策略连接 设置数据会自动切换到相应的写主机
任何一个节点可以作为中心的入口,他们之间可以互相访问
在这里插入图片描述

cluster nodes查看节点信息
在这里插入图片描述

集群操作和故障恢复

redis cluster如何分配六个节点
一个集群至少要有三个主节点

选项 --cluster-replicas 1 表示我们希望为集群中的每个主节点创建一个从节点

分配原则尽量保证每个主数据库运行在不同的ip地址,每个从库和 主库不在一个ip地址上
在这里插入图片描述
什么是slots
一个Redis集群包含16384个插槽(hash slots),数据库中的每个键都属于这16384个插槽的其中一个

集群使用公式CRC16(key)%16384来计算键key属于那个槽,其中CRC16(key)语句用于计算键key的CRC16检验和

如刚刚集群搭建成功给了个插槽:16384 slots covered.

比如刚刚创建的集群就有提示,三个主机每个主机都给了提示的插槽范围
在这里插入图片描述
比如set了一个键值
在这里插入图片描述

其实插槽就是吧每个值分配到每个插槽里面分摊,让他平均分摊压力

例如随机进入一个主机,新增一个值:
在这里插入图片描述
set k1 v1那么她计算后有个提示,【12706】,但是不属于6379插槽范围内,所以他自动切换到6381中,然后往里面添加数据由他来完成

不能一次性添加多个值,他会无法添加
在这里插入图片描述

如果想添加多个值,就分成组的形式
在这里插入图片描述
查询集群中的值

cluster keyslot k1

在这里插入图片描述
查询插槽中有几个键

cluster countkeysinslot 4847

用值返回count个slot槽中的键

getkeysinslot 449 1
故障恢复

主机挂机后,从机替换主机成为主机
先挂掉主机
在这里插入图片描述
随意进一台其他的主机
在这里插入图片描述
查看状态(6379挂掉了替代的是6381)
在这里插入图片描述
重新打开一个服务器重启6379(可以看到取而代之的主机是6381,6379变为了从机)
在这里插入图片描述

Redis缓存穿透和雪崩

Redis缓存使用,极大提升了应用程序的性能和效率,特别是数据查询方面,但同时,它也带来了一些问题,其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解,如果对数据的一致性要求很高,那么就不能使用缓存

另外的一些典型问题就是,缓存穿透、缓存雪崩和缓存击穿,目前,业界都有比较流行的解决方案

缓存穿透

概念
缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有,于是本次查询失败,当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库,这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透

在这里插入图片描述

解决方案
(1)布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力
在这里插入图片描述

(2)缓存空对象
当存储层不命中后,即使返回的空对象也将其缓存起来,同时还会设置一个过期时间,之后在访问这个数据将会从缓存中获取,保护了后端数据源
在这里插入图片描述

但是这两个方法也会存在两个问题:
1.如果空值能够被缓存起来,这就意味着需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键

2.即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口不一致,这对于需要保持一致性的业务会有影响

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

这里需要注意和缓存击穿的区别,缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏幕上凿开了一个洞

当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导致数据库瞬间压力过大

解决方案
设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题

加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可,这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大

缓存雪崩

概念
缓存雪崩,是指在某一个时间段,缓存集中过期失效,Redis宕机

产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品比较集中的放入了缓存,假设缓存一个小时,那么到了凌晨一点钟的时候,这批商品的缓存就都过期了,而对这批商品的查询访问,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰,于是所有的请求都会达到存储层,存储层的调用量就会暴增,造成存储层也会挂掉的情况

在这里插入图片描述
其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网,因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的,无非就是对数据库产生周期性的压力而已,而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮

解决方案
Redis高可用
这个思想的含义是,既然Redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群

限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量,比如对某个key只允许一个线程查询和写缓存,其他线程等待

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

Redis消息队列

为什么要用消息队列

消息队列的本质:
消息队列一种“先进先出”的数据结构
常见的应用场景:解耦、异步、削峰

解耦

系统的耦合性越高,容错性就越抵,以电商应用为例,用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障或者因为升级等原因暂时不可用,都会造成下单操作异常,影响用户使用体验
在这里插入图片描述
如何处理
使用MQ进行解耦,系统的耦合性就会提高了,比如物流系统发生故障,需要几分钟修复,这段时间内,物流系统要处理的数据被缓存到消息队列中,用户的下单操作正常完成,当物流系统回复后,补充处理存在消息队列中的订单消息即可,终端系统感知不到物流系统发生过几分钟故障

在这里插入图片描述

异步

A系统接收一个请求,需要在自己本地写库,还需要在B、C、D三个系统写库,自己本地写库要3ms,B、C、D三个系统分别写库要300ms、400ms、200ms,最终请求总延时是3+300+400+200=903ms,接近1s,用户非常不好,一般互联网类的企业,对于用户直接的操作,一般要求是每个请求都必须在200ms以内完成,对用户几乎是无感知的,如果用户通过浏览器发起请求,等待个1s,这几乎是不可接受的
在这里插入图片描述
如何处理
如果使用MQ,那么A系统连续发送3条消息到MQ队列中,假如耗时5ms,A系统从接受一个请求到返回响应给用户,总时长是3+5=8ms,对于用户而言,响应速度大大提升了,改善了用户的体验

流量削峰

秒杀,应用系统如果遇到系统请求流量瞬间猛增,有可能会将系统压垮,有了消息队列可以将大量请求缓存起来,分散到很长一段时间处理,这样可以大大提高系统的稳定性和用户体验
在这里插入图片描述

如何处理
一般情况,为了保证系统的稳定性,如果系统负载超过阈值,就会阻止用户请求,这会影响用户体验,而如果使用消息队列将请求缓存起来,等待系统处理完毕后通知用户下单完毕,这样总不能下单体验要好

redis中的订阅与发布

Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息,redis客户端可以订阅任意数量的频道

1.pub/sub模式的消息通知,发布/订阅模式:
通过两个命令来实现pub/sub模式的消息通知

1.publish 主题名称 消息内容 (向指定主题中发送一条消息)
2.subscribe 主题名称 (订阅某一个主题)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值