redis笔记1

1.mysql的发展方式

单机版本的mysql

使用单个数据库存放的条件:

1.数据量不大

2.数据索引较少,一个机器可以存放

3.访问量(读写混合)不大

Memcached(缓存) + Mysql + 垂直拆分(读写分离)

MemCache缓存:大部分时候,网站都在读取数据库的信息,如果每次都要从数据库中查询,数据库的压力就会很大。这个时候就需要在数据库和数据访问层之间加上一个缓存。第一次访问的时候查询数据库,后续访问的时候,首先查看缓存。

 mysql的垂直拆分:就是使用多个mysql数据库,其中一个用于写内容,然后将内容同步到其他数据库,其他的数据库负责查询数据。这就是垂直拆分的读写分离。

分库分表 + 水平拆分 + Mysql集群

 在垂直拆分的基础上进行水平拆分,将mysql集群式建立,在多台机器上建立mysql数据库。同时减轻压力。

2.nosql的概述

现在的大数据时代,数据量过于庞大,普通的关系型数据库无法满足大量数据要求。 

目前的一个基本的互联网项目

 用户访问企业的防火墙,然后通过负载均衡的平横来访问多台服务器。服务器后面连接的数据库又有着各式各样的分担数据量方式。还有各种图片,文件,视频等数据mysql无法满足大量的传递。

 什么是nosql?

关系型数据库:行列形成的表,数据结构有限制。

非关系型数据库:数据存储没有固定的格式,可以横向拓展

 nosql的特点:

  • 方便拓展
  • 大数据高性能
  • 数据类型多样性

 传统的 RDBMS 和 NoSQL

传统的 RDBMS(关系型数据库)

- 结构化组织

- SQL

- 数据和关系都存在单独的表中 row col

- 操作,数据定义语言

- 严格的一致性

- 基础的事务

Nosql - 不仅仅是数据

- 没有固定的查询语言

- 键值对存储,列存储,文档存储,图形数据库(社交关系)

- 最终一致性

- CAP定理和BASE

- 高性能,高可用,高扩展 - ...

了解3v+3高

大数据时代的3V :主要是描述问题

  1. 海量Velume

  2. 多样Variety

  3. 实时Velocity

大数据时代的3高 : 主要是对程序的要求

  1. 高并发

  2. 高可扩

  3. 高性能

真正在公司中的实践:NoSQL + RDBMS 一起使用才是最强的。

3.redis入门

redis是什么

Redis(Remote Dictionary Server ),即远程字典服务。

是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

redis功能:

  • 内存存储,持久化
  • 高效率。用于高速缓冲
  • 发布订阅系统
  • 地图分析器
  • 计时器,计数器(浏览量) 

特性 

  • 多样化的数据类型
  • 持久化
  • 集群
  • 事务 

 windows环境搭建(推荐使用linux)

直接下载安装包解压 

 直接启动服务器即可,然后启动客户端,这里没有可视化。可以运行这个redis的jiar包可视化界面。

linux安装redis

下载安装包(官网),一般放在opt

解压默认安装路径在usr/local/bin

 基本环境安装

 将解压后的配置文件修改一个yes值之后放在安装目录下(启动需要,因为redis默认是前台任务程序,所以需要更改为后台启动)

 然后就可以通过指定的配置文件启动redis了

 启动服务器之后就可以使用客户端指定端口号连接了

 可以使用netstat -an或者ps -ef这两种方式查看redis进程

关闭redis服务shutdown

4.测试redis性能

官方提供了一个测试redis性能的工具**redis-benchmark:**

# 测试:100个并发连接 100000请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000

 基础知识

redis默认有16分数据库,默认使用第0个

 16个数据库为:DB 0~DB 15
默认使用DB 0 ,可以使用select n切换到DB n,dbsize可以查看当前数据库的大小,与key数量相关。

  •  keys * :查看当前数据库中所有的key。
  • flushdb:清空当前数据库中的键值对。
  • flushall:清空所有数据库的键值对。

在6.0之前redis是单线程的,6.0之后增加了多线程。redis是基于内存操作的

对于redis来说,性能的瓶颈不是cpu,而是机器内存和网络带宽

redis的QPS*(每秒访问数量)可以达到10w+

  1. 纯内存操作(最主要条件):内存访问速度快。这里一般指的是操作内存线程。
  2. 合适的线程模型
  3. 优秀的数据结构
  4. 合理的数据编码方式

redis的单线程只有网络请求模块和数据操作模块是单线程的。

多线程出现的原因是为了解决cpu利用率的不足,对于单线程来说,前面的操作访问内存的时候cpu就会空闲,后面需要使用cpu的操作就无法使用cpu,单线程是按照顺序执行的。如果这里使用多线程,这个线程使用完cpu之后执行其他操作的时候,其他线程就会来使用cpu,这样就能提升效率。cpu在切换切换线程的时候会耗费时间。

但是如果现在的线程都是基于内存的redis操作,对于cpu的需求很少。前面占用完cpu之后需要使用内存,后面的也需要使用内存,都是基于内存操作的。两者都会抢占内存资源,这样的话如果使用多线程没有过多的意义,cpu并不是限制。

结论:redis 在 CPU 计算上不存在瓶颈,性能瓶颈只存在于网络 IO 中

那为什么redis 6.0 还是采用了多线程处理网络 IO ?不是说多路复用技术已经大大的提升了网络 IO 利用率了么,为啥还需要多线程?

 redis服务器可以处理8w到10wQPS,大部分使用足够。但是部分时候的并发过于庞大。

这样的话可以使用部署redis集群的方式,但是资源消耗大。

限制redis的原因是:内存操作加上网络io。网络io使用多线程的时候速度能达到单线程的两倍。

单线程下快的原因:多路复用

 多路复用:简单理解就是 单个线程同时检测若干个网络连接(Socket)是否可以执行IO操作的能力,就是将多个进程的网络 IO Socket注册到同一个管道上。 用最少的资源,干最多的事情。

比较传统的方式是使用多线程模型,每来一个客户端连接,就分配一个线程,然后后续的读写都在对应的进程/线程,这种方式处理 100 个客户端没问题,但是当客户端增大到 10000 个时,10000 个进程/线程的调度、上下文切换以及它们占用的内存,都会成为瓶颈。

多路复用实际上就是在一个进程里面处理多个文件的io操作。

多路复用:在网络请求的时候采用了一个通知的模式,应用程序向linux内核请求数据,linux将数据准备好之后通知程序来读,这样也可以减少占用io时间。

5.五大数据类型

​ Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。

redis-key

在redis中无论什么数据模型,在数据库中都是用key-value形式保存。

  • exists key:判断键是否存在
  • del key:删除键值对
  • move key db:将键值对移动到指定数据库
  • expire key second:设置键值对的过期时间
  • type key:查看value的数据类型
  • ttl key:查看key过期时间

 

Redis的key,通过TTL命令返回key的过期时间,一般来说有3种:

当前key没有设置过期时间,所以会返回-1.
当前key有设置过期时间,而且key已经过期,所以会返回-2.
当前key有设置过期时间,且key还没有过期,故会返回key的正常剩余时间.
关于重命名RENAME和RENAMENX

RENAME key newkey修改 key 的名称
RENAMENX key newkey仅当 newkey 不存在时,将 key 改名为 newkey 。(保险,和setnx类似)

String

 计数器:incr/decr或者incrby/decrby。为整数加上一个浮点数。

 

 List列表

 Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)

首先看一下list的特性,有序可重复。所以存储的时候是可以使用相同的key的。

 

 

 

 

 

 

  • list实际上是一个链表,before Node after , left, right 都可以插入值

  • 如果key不存在,则创建新的链表

  • 如果key存在,新增内容

  • 如果移除了所有值,空链表,也代表不存在

  • 在两边插入或者改动值,效率最高!修改中间元素,效率相对较低

 Set(集合)

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

 

 

Hash(哈希)

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。

Set就是一种简化的Hash,只变动key,而value使用默认值填充。可以将一个Hash表作为一个对象进行存储,表中存放对象的信息

 

 ​ Hash变更的数据user name age,尤其是用户信息之类的,经常变动的信息!Hash更适合于对象的存储,Sring更加适合字符串存储!

Zset(有序集合)

不同的是每个元素都会关联一个double类型的分数(score)。redis正是通过分数来为集合中的成员进行从小到大的排序。

score相同:按字典顺序排序

有序集合的成员是唯一的,但分数(score)却可以重复。

 

 6.三种特殊的数据类型

Geospatial(地理位置)

 

 

 

有效经纬度

有效的经度从-180度到180度。
有效的纬度从-85.05112878度到85.05112878度。
指定单位的参数 unit 必须是以下单位的其中一个:

m 表示单位为米。

km 表示单位为千米。

mi 表示单位为英里。

ft 表示单位为英尺。

关于GEORADIUS的参数

通过georadius就可以完成 附近的人功能

withcoord:带上坐标

withdist:带上距离,单位与半径单位相同

COUNT n : 只显示前n个(按距离递增排序)

Hyperloglog(基数统计:数组中不重复元素的个数)

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

花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。

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

其底层使用string数据类型

应用场景:统计网页的访问量

 

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

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

BitMaps(位图)

使用位存储,信息状态只有 0 和 1

Bitmap是一串连续的2进制数字(0或1),每一位所在的位置为偏移(offset),在bitmap上可执行AND,OR,XOR,NOT以及其它位操作。

 

7.事务

redis的单挑命令是保证原子性的,但是redis事务不能保证原子性

redis事务的本质:一组命令的集合

事务中每条命令都会被序列化,执行过程中按照顺序执行,不容许其他命令干扰

  • 一次性
  • 顺序性
  • 排他性

redis的事务是没有隔离级别的概念

redis单条命令保证是原子性的,但是事务不保证原子性的 

Redis事务操作过程

  • 开启事务(multi
  • 命令入队
  • 执行事务(exec
    127.0.0.1:6379> multi # 开启事务
    OK
    127.0.0.1:6379> set k1 v1 # 命令入队
    QUEUED
    127.0.0.1:6379> set k2 v2 # ..
    QUEUED
    127.0.0.1:6379> get k1
    QUEUED
    127.0.0.1:6379> set k3 v3
    QUEUED
    127.0.0.1:6379> keys *
    QUEUED
    127.0.0.1:6379> exec # 事务执行
    1) OK
    2) OK
    3) "v1"
    4) OK
    5) 1) "k3"
       2) "k2"
       3) "k1"
    

     取消事务discurd:开启事务之后用这个取消,不然无法退出

事务错误 

编译时异常:开启事务之后有一条命令输入异常,执行的时候这条错误的命令前后的命令都不执行。

运行时异常: 例如incrby  name。为一条string类型的数据加上一个数字,运行时就会报错,其他命令会正常执行,所以不保证事务的原子性

监控

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

乐观锁:认为什么时候都不会出问题,只需要在更新数据的时候判断一下数据是否变动

在redis里面使用watch key来监控某个值。

正常执行:在开启事务之前使用watch来监控某个需要更改的值,在执行事务之前就会判断该值是否更改,未更改就会正常执行,更改的话事务不会执行。

例如开启监控某个值,然后开启事务,等待另一个线程更改数据,在执行,就不会有效果。

watch就是redis的乐观锁,每次提交之后就会自动释放该锁。如果需要手动解锁获取最新的值,需要使用unwatch。

8.Jedis

使用java操作redis,Jedis是redis官方推荐的客户端,依赖:

<!--导入jredis的包-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.2.0</version>
</dependency>
<!--fastjson-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.70</version>
</dependency>

 使用java连接数据库的时候,需要更改redis的配置文件(linux连接,windows直接连就可以)

  • redis中有一个bind 127.0.0.1指定了只容许本机连接,注释或者添加
  • 关闭保护模式:protected-mode yes——》no
  • 允许后台运行
  • 开放linux防火墙端口 firewall-cmd --permanent --add-port=6379/tcp
  • 刷新端口 firewall-cmd --query-port=6379/tcp
public class TestTX {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.200.130", 6379);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("hello", "world");
        jsonObject.put("name", "kuangshen");
        // 开启事务
        Transaction multi = jedis.multi();
        String result = jsonObject.toJSONString();
        // jedis.watch(result)
        try {
            multi.set("user1", result);
            multi.set("user2", result);
            // 执行事务
            multi.exec();
        }catch (Exception e){
            // 放弃事务
            multi.discard();
        } finally {
            // 关闭连接
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();
        }
    }
}

9.springboot整合

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

springboot 2.x后 ,原来使用的 Jedis 被 lettuce 替换。

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

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

springboot中redis注入配置文件是RedisAutoConfiguratioimg

 其中只有两个bean可以使用

  • RedisTemplate
  • StringRedisTemplate

 第一个模板redis中什么数据类型都可以使用,但是默认采用jdk的序列化方式,使用中文的话在redis中看起来很不方便,所以只使用string类型的redis时候可以选择第二个。或者使用第一个规定他的序列化方式。

springboot配置文件:如果有密码需要加上

# 配置redis
spring.redis.host=192.168.200.130
spring.redis.port=6379

使用redisTemplate

@SpringBootTest
class Redis02SpringbootApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {

        // redisTemplate 操作不同的数据类型,api和我们的指令是一样的
        // opsForValue 操作字符串 类似String
        // opsForList 操作List 类似List
        // opsForHah

        // 除了基本的操作,我们常用的方法都可以直接通过redisTemplate操作,比如事务和基本的CRUD

        // 获取连接对象
        //RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        //connection.flushDb();
        //connection.flushAll();

        redisTemplate.opsForValue().set("mykey","kuangshen");
        System.out.println(redisTemplate.opsForValue().get("mykey"));
    }
}

此时在redis中显示的全是乱码,因为使用的序列化方式是jdk。可以在springboot中定制自己的序列化方式:

@Configuration
public class RedisConfig {

   @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        // 将template 泛型设置为 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate();
        // 连接工厂,不必修改
        template.setConnectionFactory(redisConnectionFactory);
        /*
         * 序列化设置
         */
        // key、hash的key 采用 String序列化方式
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // value、hash的value 采用 Jackson 序列化方式
        template.setValueSerializer(RedisSerializer.json());
        template.setHashValueSerializer(RedisSerializer.json());
        template.afterPropertiesSet();
        
        return template;
    }
}

每次使用RedisTemplate都需要先调用opsForValue().get("mykey")。这样会很麻烦,所以可以自定义一个redis工具类。

10.解析redis.config文件

容量单位不区分大小写,g和gb有区别

可以使用include引入其他配置 

 

 网络配置:指定可以访问ip,端口号,受保护,日志信息,超时等

 日志输出级别,日志保存名称,数据库数量,总是展示logo

 持久化规则

RDB:

AOF: 在这里插入图片描述

 在这里插入图片描述

 mysql集群持久化配置文件,主从复制

 设置密码

 客户端连接

maxclients 10000  最大客户端数量
maxmemory <bytes> 最大内存限制
maxmemory-policy noeviction # 内存达到限制值的处理策略
 

 11.持久化

RDB

 在指定时间间隔后,将内存中的数据集快照写入数据库 ;在恢复时候,直接读取快照文件,进行数据的恢复 ;

 默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。文件名可以在配置文件中进行自定义。

工作原理:在满足RDB设定的触发条件之后(config中,flushall等),redis会fork一个子线程将数据写到一个临时文件中,等文件写入完成就会替换掉原本的那个。

这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益(因为是使用子进程进行写操作,而父进程依然可以接收来自客户端的请求。)

触发机制:

  1. save的规则满足的情况下,会自动触发rdb原则
  2. 执行flushall命令,也会触发我们的rdb原则
  3. 退出redis,也会自动产生rdb文件

 save命令

使用 save 命令,会立刻对当前内存中的数据进行持久化 ,但是会阻塞,也就是不接受其他操作了;

由于 save 命令是同步命令,会占用Redis的主进程。若Redis数据非常多时,save命令执行速度会非常慢,阻塞所有客户端的请求。

flushall命令

flushall 命令也会触发持久化 ;

bgsave

bgsave 是异步进行,进行持久化的时候,redis 还可以将继续响应客户端请求 ;

优缺点

优点:

  1. 适合大规模的数据恢复
  2. 对数据的完整性要求不高

缺点:

  1. 需要一定的时间间隔进行操作,如果redis意外宕机了,这个最后一次修改的数据就没有了。
  2. fork进程的时候,会占用一定的内容空间。

持久化规则AOF 

Append Only File

将我们所有的命令都记录下来,history,恢复的时候就把这个文件全部再执行一遍

以日志的形式来记录每个写的操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

什么是AOF

​ 快照功能(RDB)并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、以及未保存到快照中的那些数据。 从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化。

如果要使用AOF,需要修改配置文件:在这里插入图片描述

appendonly no yes则表示启用AOF

默认是不开启的,我们需要手动配置,然后重启redis,就可以生效了!

如果这个aof文件有错位,这时候redis是启动不起来的,我需要修改这个aof文件

redis给我们提供了一个工具redis-check-aof --fix

appendonly yes  # 默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分的情况下,rdb完全够用
appendfilename "appendonly.aof"

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

优点

  1. 每一次修改都会同步,文件的完整性会更加好
  2. 没秒同步一次,可能会丢失一秒的数据
  3. 从不同步,效率最高

缺点

  1. 相对于数据文件来说,aof远远大于rdb,修复速度比rdb慢!
  2. Aof运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化

如何选择使用哪种持久化方式?
一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。

如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。

有很多用户都只使用 AOF 持久化, 但并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。


14.redis发布和订阅

redis发布订阅是一种消息通信模式:发布者发送消息,订阅者接收消息。

首先使用PSUBSCRIBE订阅一个频道,然后可以在另一台redis连接上使用PUBLISH 命令发布消息。

 

 每个 Redis 服务器进程都维持着一个表示服务器状态的 redis.h/redisServer 结构, 结构的 pubsub_channels 属性是一个字典, 这个字典就用于保存订阅频道的信息,其中,字典的键为正在被订阅的频道, 而字典的值则是一个链表, 链表中保存了所有订阅这个频道的客户端。

缺点

  1. 如果一个客户端订阅了频道,但自己读取消息的速度却不够快的话,那么不断积压的消息会使redis输出缓冲区的体积变得越来越大,这可能使得redis本身的速度变慢,甚至直接崩溃。
  2. 这和数据传输可靠性有关,如果在订阅方断线,那么他将会丢失所有在短线期间发布者发布的消息。

15.主从复制 

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

作用

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

为什么使用集群

  1. 单台服务器难以负载大量的请求
  2. 单台服务器故障率高,系统崩坏概率大
  3. 单台服务器内存容量有限。

 使用读写分离的形式搭建集群类型的redis

配置方法

首先准备三份配置文件,使用不同的端口,日志、持久化以及pid文件名等。要求

关闭保护模式

在从机中加上masterauth 密码;或者不使用密码 

使用三个不同的配置文件分别启动不同的redis

分别登录自己的客户端,然后使用info replication命令可以查看redis服务器的数据

127.0.0.1:6379> info replication
# Replication
role:master # 角色
connected_slaves:0 # 从机数量
master_replid:3b54deef5b7b7b7f7dd8acefa23be48879b4fcff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

刚登录的时候都是主节点,可以使用SLAVEOF host port认老大(把自己变为从节点)

 在这里插入图片描述

 主机上看到的状态是

在这里插入图片描述

 我们这里是使用命令搭建,是暂时的,==真实开发中应该在从机的配置文件中进行配置,==这样的话是永久的。在这里插入图片描述

 使用规则

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

 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,这样执行以后从机会独立出来成为一个主机
使用哨兵模式(自动选举)


16.哨兵模式

一种自动选举老大的模式,安排一个哨兵去监控主节点,如果挂掉了就会重新选举。

哨兵的作用:

  • 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
  • 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

多哨兵模式 

哨兵也就是一个进程,也可能挂掉,所以可以建议多个哨兵共同监控主节点,投票选举

创建一个哨兵配置文件:

哨兵配置:sentinel monitor mymaster 127.0.0.1 6379 1

使用redis-sentinel sentinel.config启动哨兵监控

 在这里插入图片描述

 断开主机之后在这里插入图片描述

 哨兵模式的优缺点

优点:

  • 哨兵集群,基于主从复制模式,所有主从复制的优点,它都有
  • 主从可以切换,故障可以转移,系统的可用性更好
  • 哨兵模式是主从模式的升级,手动到自动,更加健壮

缺点:

  • Redis不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦
  • 实现哨兵模式的配置其实是很麻烦的,里面有很多配置项

哨兵模式的完整配置 

# Example sentinel.conf
 
# 哨兵sentinel实例运行的端口 默认26379
port 26379
 
# 哨兵sentinel的工作目录
dir /tmp
 
# 哨兵sentinel监控的redis主节点的 ip port 
# master-name  可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。
# quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 1
 
# 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码
# 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
 
 
# 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000
 
# 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步,
这个数字越小,完成failover所需的时间就越长,
但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。
可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1
 
 
 
# 故障转移的超时时间 failover-timeout 可以用在以下这些方面: 
#1. 同一个sentinel对同一个master两次failover之间的间隔时间。
#2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。  
#4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
# 默认三分钟
# sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000
 
# SCRIPTS EXECUTION
 
#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
#一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
 
#通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,
#这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,
#一个是事件的类型,
#一个是事件的描述。
#如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
#通知脚本
# sentinel notification-script <master-name> <script-path>
  sentinel notification-script mymaster /var/redis/notify.sh
 
# 客户端重新配置主节点参数脚本
# 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
# 以下参数将会在调用脚本时传给脚本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>总是“failover”,
# <role>是“leader”或者“observer”中的一个。 
# 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的
# 这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

17.缓存穿透与雪崩

缓存穿透

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

解决方式:布隆过滤器

布隆过滤器

 在这里插入图片描述

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

缓存空对象

在这里插入图片描述

 

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

​ 这样做有一个缺陷:存储空对象也需要空间,大量的空对象会耗费一定的空间,存储效率并不高。解决这个缺陷的方式就是设置较短过期时间

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

缓存击穿(缓存过期)

 相较于缓存穿透,缓存击穿的目的性更强,一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。这就是缓存被击穿,只是针对其中某个key的缓存不可用而导致击穿,但是其他的key依然可以使用缓存响应。​ 比如热搜排行上,一个热点新闻被同时大量访问就可能导致缓存击穿。

解决方式

 

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

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

2.加互斥锁(分布式锁)

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

缓存雪崩

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

 解决方式

redis高可用

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

限流降级

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

数据预热

数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
————————————————
版权声明:本文为CSDN博主「每天进步一點點」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/DDDDeng_/article/details/108118544

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值