Redis知识点总结

什么是关系型数据库

在这里插入图片描述

在这里插入图片描述

NOSQL四大分类

在这里插入图片描述

图关系型数据库

-不是用来存图的,而是用来存图的关系的,也就是数据结构里的图结构

现在比较流行的:Redis,MongoDB,HBase,Neo4J

四种分类的对比

在这里插入图片描述

Redis概述

Redis能干嘛?

  1. 支持发布订阅系统
  2. 地图信息分析
  3. 计时器、计数器(浏览量)

Redis特性

  1. 多样的数据类型
  2. 持久化
  3. 集群
  4. 事务

启动redis

默认安装在/usr/local/bin中
阿里云装在了/usr/bin下

在这里插入图片描述

阿里云上的配置文件在etc下

在这里插入图片描述

需要修改配置文件,将后台启动改为yes

在这里插入图片描述

cd /etc
redis-server redis.conf  //启动redis服务器
ps -ef|grep redis        //查看启动的redis进程

在这里插入图片描述

可以看到,默认使用6379端口

redis-cli   #启动客户端
auth password #输入密码
shutdown  #关闭redis服务器
exit      #推出redis客户端

在这里插入图片描述

再次查看redis进程,发现服务端已经关闭

在这里插入图片描述

在这里插入图片描述

redis benchmark 测试redis性能

cd /usr/bin  //进入redis安装目录
redis-benchmark -h localhost -p 6379 -c 100 -n 100000   //指定使用本机的redis,100并发连接数,10W个请求

在这里插入图片描述

set的测试结果,10W请求在1.31秒内完成;100并发连接数;一个请求发送3字节

基本知识

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

select 3   #选择第四个数据库

DBSIZE  #当前数据库大小
keys *  #查看查看当前库所有key

flushdb #清空当前数据库
FLUSHALL #清空所有数据库

Redis是单线程的,6版本之后也支持多线程,但一般是超大业务才可能用多线程

Redis是基于内存操作,CPU不是redis性能瓶颈

Redis不区分大小写命令

基本类型

EXISTS KEY  #查看此key是否存在

move KEY 1  #移除某键值对,1代表当前库

EXPIRE KEY 10 #设置某key过期时间为10s。分布式锁会set的同时expire,原子性操作
ttl key      #time to live 剩余存货时间,过期了就返回-2

type   #查看当前key类型   

添加字符串时,尽量用双引号包起来

strings

APPEND KEY "hello"  #追加某key的字符串。假若没有此key,则会自动创建
STRLEN KEY  #获得从key字符串的长度

incr KEY     #加一,value必须要为integer
decr KEY     #减一

INCRBY KEY 10 #加10,可以设定步长
DECRBY KEY 10 #减10

GETRANGE KEY 0 3 #截取字符串,和java一样
SETRANGE KEY 1 ABCD #替换部分字符串 

#这两个常在分布式锁中使用
setex KEY seconds value   #set with expire
setnx KEY value   # set if not exist,不存在此key才会创建并设置值,也就是无法覆盖当前key的值

mset k1 v1 k2 v2 k3 v3  #同时set
mget k1 k2 k3           #同时get
msetnx k1 v2 k4 v4      #原子性操作,要么一起成功,要么一起失败

getset KEY value    #先get再set。

两种存储对象的方式

在这里插入图片描述

用途:

  1. 计数器
  2. 统计多单位的数量:粉丝数
  3. 对象缓存存储

List

可以实现栈,队列,双向队列。

它实际是一个链表

#L 左边 
#R 右边  
Lpush list v1  #向左边插入一个值
Lrange list 0 -1 
LPOP list
RPOP list

Lindex list 1 #通过下标获取value
Llen list #获得该list的长度(value的个数)

Lrem list 1 three #移除指定个数的value,精确匹配名字

Ltrim list 1 2  #保留此闭区间的value,其他全都移除。注意这里索引1,2均会保留

rpoplpush source destination #移除source里的元素,并添加到des里

lset list 0 value #将列表中指定下标的值替换为另一个值。假如不存在列表,或者该下标还没有值,则会报错

Linsert list before/after value insert_value #插入某个value中的前面或者后面

用途:

  1. 消息队列

set

set中的值是不能重复的,无序不重复集合

sadd myset "hello" #添加一个值
smembers myset #查看成功
sismember myset hello #查看该value是否为成员
scard myset  #查看该set的value个数

srem myset hello #移除指定元素
spop myset #随机移除元素

SRANDMEMBER myset 2 #随机选取指定个数的value

smove source destination value #移动某元素到指定set

SDIFF set1 set2  #差集
SINTER set1 set2 #交集
SUNION set1 set2 #并集 

在这里插入图片描述

Hash

其实就像hashmap,只是哈希值是key+field一起计算的,无序的

hset myhash field1 li #设置field-value对
hget myhash field1   
hmset nyhash field1 hello field2 hello2
hmget myhash field1 field2
hgetall myhash #获得所有field-value
hdel myhash field1  #删除field,同时value也会被删除

hlen myhash #获取hash的元素数量
hexists myhash field1 

hkeys myhash  #只获得所有field
hvals myhash  #只获得所有value

Hincrby myhash field3 1 #该field对应value自增1
hsetnx myhash field3 hello #和strings的setnx效果一样

用途:

  1. 用于存储一个对象,尤其是用户信息之类的,经常变动的信息,存储对象比strings好

Zset

在这里插入图片描述

zadd myzset score member  
zadd myzset 100 member1 200 member2  #添加多个值

ZRANGE myzset 0 -1
ZREVRANGE myzset 0 -1   #按score倒序,参数为start stop


ZRANGEBYSCORE myzset -inf +inf #按score排序,-inf为负无穷。min~max
ZRANGEBYSCORE myzset -inf +inf withscores #结果同时显示score
ZREVRANGEBYSCORE myzset +inf -inf  #倒序,注意前为最大值,后为最小值

在这里插入图片描述

zrem myzset member1   #移除
zcard myzset  #获得member个数
zcount myzset 100 299  #获取指定范围内元素个数(闭区间)

用途:

  1. 有权重序列。
  2. 排行榜

三种特殊的基本类型

geospatial 地理位置

根据经度纬度可以推算地理位置的信息,两地之间的距离,方圆几里的人。

我们一般会通过java添加

geoadd china:city 121.47 31.23 shanghai #经度,纬度

geopos china:city shanghai #从存储的geo获取经度、纬度

GEODIST china:city beijing shanghai #计算两地之间直线距离,默认单位为米
GEODIST china:city beijing shanghai km #单位为km

GEORADIUS china:city 120 31 1000 km  #以前两个参数为经度、纬度为圆心,查找半径内的所有人
GEORADIUS china:city 120 31 1000 km withdist #同时显示到中心的距离
GEORADIUS china:city 120 31 1000 km withcoord #显示结果的经度纬度
GEORADIUS china:city 120 31 1000 km count 1 #筛选指定数量的结果
GEORADIUSBYMEMBER china:city beijing 10000 km #圆心为该元素,结果包含该元素

GEOHASH china:city beijing shanghai   #将二维的经纬度转换为11位字符串。字符串越接近,那么距离越近

在这里插入图片描述

geo底层原理就是zset

在这里插入图片描述

Hyperloglog

基数:不重复的元素

优点:占用内存小,占用内存是固定的,2^64不同的元素的基数,只需要12kb的内存。Hyperloglog里的元素都是不能重复的

PFADD mykey a b c d  #添加数据
PFADD mykey2 c d e f
PFCOUNT mykey #计算元素数量
PFMERGE mykey3 mykey mykey2 #融合mykey和mykey2 (并集)

用途:

  1. 用于统计页面计数,比set所占内存会小的多,但是会有0.81%的错误率

Bitmap

位存储

用途:

  1. 统计用户信息,活跃、不活跃;登录,未登录;打卡、未打卡!
  2. 两个状态的都可以用BItmap来存

在这里插入图片描述

setbit KEY offset value  #设置某个位的值
getbit KEY offset
bitcount KEY  #统计为1的位的数量

事务

Redis单命令是保证原子性的,但是事务是不保证原子性,没有隔离级别的概念

Redis事务,所有命令逐一进入队列,但没有执行先。只有当命令都进入队列后,才发出执行命令,然后所有入队的命令按照顺序执行。

——————————队列——————————————
   set set get  执行  

事务顺序

  1. 开启事务(multi)
  2. 命令入队
  3. 执行事务(exe)
  4. 取消事务(DISCARD)

在这里插入图片描述

两种异常:

编译型异常:事务中某一条命令语法等有问题,那么事务所有的命令都不会被执行

在这里插入图片描述

运行时错误:事务中某一条命令运行出错,那么事务剩下的所有命令依然正常执行

比如下方对字符串进行加一,出现运行时错误

在这里插入图片描述

Watch乐观锁

悲观锁:

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

乐观锁:

·很乐观,行动前获得version,行动的时候再比较一下version,看看是否有其他线程更新了此行。

Redis,一个终端代表一个线程。一个线程中Redis执行是单线程的,而监听端口是多线程的

watch KEY #监视该对象,是否有别的进程更改了,其实就是获得此key的version。假如别的线程更改了此对象,那么该事务所有命令执行失败。也就是可以作为乐观锁。
unwatch KEY #放弃监视,一般用于事务结束,再watch获得新的version。但是exec和discard会自动解锁。

在这里插入图片描述

在exec前,另开另一个终端(线程)修改money,可以看到事务全部执行失败。

在这里插入图片描述

Jedis

连接远程服务器

  1. 关闭防火墙

  2. 改动redis配置文件

    注释掉 bind 127.0.0.1

    设置密码 requirepass password

    阿里云的服务器,需要设置安全组设置,添加安全组规则,将端口6379开放出来

img

public class TestPing {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("远程机的ip",6379);
        jedis.auth("password");
        System.out.println(jedis.ping());
    }
}

Jedis的所有函数名字与用法与redis原生的一模一样

jedis是实现事务

public class TestPing {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("120.24.6.203",6379);
        jedis.auth("123456");

        jedis.flushDB();

        Transaction multi= jedis.multi();

        try {
            multi.set("user1","hello");
            multi.set("user2","hello2");

            multi.exec();
        }catch (Exception e){
            multi.discard();
            e.printStackTrace();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();
        }

    }
}

springboot

springboot 2.x之后,原来使用的jedis被替换为了lettuce,配置文件中,都要配置lettuce而不要再配置jedis.

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

lettuce:采用了netty,NIO模式,线程更安全,性能更高

autoconfiugration里

在这里插入图片描述

RedisTemplate

里面opsForXXX().xxx(),xxx与原生redis中的一一对应

但是我们基本不会使用原生的,而是编写RedisUtil

在这里插入图片描述

基本配置文件:

spring.redis.host=100.110.110.26
spring.redis.port=6379   #默认就是6379
spring.redis.password=password

对象序列化

一般我们都会把对象转换为json,但是我们必须实现对象的jdk序列化,因为有可能在某些情况下会用到。没有实现序列化的JDK在存入Redis中会报错。

在这里插入图片描述

RedisTemplate默认使用JDK序列化,那么key前缀会出现固定的乱码\xac\xed\x00\x05t\x00\x04,同时value变nil(实际上应该不是nil,而是redis根本无法识别)

我们直接在redis里面取,是根本取不到的,但是redisTemplate却是可以get到的

在这里插入图片描述

在这里插入图片描述

因此我们需要自己编写配置文件

@Configuration
public class RedisConfig {
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        //为了开发方便,一般使用<string,object>
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        //json序列化配置
        Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectJackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        //string序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        //key和hash采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);

        //value和hash的value采用jaskson的序列化方式
        template.setValueSerializer(objectJackson2JsonRedisSerializer);
        template.setHashValueSerializer(objectJackson2JsonRedisSerializer);

        template.afterPropertiesSet();
        return template;
    }

}


在redis存储结果如下,可以看到key的存储没有出现乱码,value也是json结构

在这里插入图片描述

通过redistemplate

在这里插入图片描述

Redis.Conf

最基本配置

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

可以Include别的配置文件,同时起作用

在这里插入图片描述

网络配置

bind 127.0.0.1  #绑定的Ip,只有绑定了的IP才能访问本机的Redis。可以注释掉或者改为0.0.0.0,让所有机器都能够访问
port 6379 #使用集群时就需要改动端口了

通用配置

daemonize no #开启守护线程,开启后才能后台运行。默认为0,需要手动改为1

pidfile /var/run/redis_6379.pid #如果以后台方式运行,我们就需要指定一个Pid文件

loglevel notice #日志级别

logfile "" #日志生成的文件位置名

database #默认16个数据库

在这里插入图片描述

快照

持久化,在规定大的时间内,值了多少次操作,则会持久化到文件

save 900 1 #如果900s内,有一个key进了了就修改,我们就进行持久化操作
save 300 10
save 60 10000

stop-writes-on-bgsave-error yes #持久化如果出错,是否还要继续工作

rdbcompression yes #是否压缩rdb文件,开始的话,需要消耗cpu

rdbchecksum yes #保存rdb文件的时候,进行错误的检查校验

dir /var/lib/redis #rdb文件保存的目录

Replication 主从复制

security 安全

requirepass password  #设置访问redis的密码。登录时,需要auth password

LIMITS

maxclient 100000   #最大连接客户端数量
maxmemory <bytes> #redis最大的内存容量
maxmemory-policy noviction #内存达到上限之后的处理策略

# volatile-lru -> remove the key with an expire set using an LRU algorithm 在设置了过期时间的key中采用LRU策略移除
# allkeys-lru -> remove any key according to the LRU algorithm 对所有key都进行LRU策略移除

# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key

# volatile-ttl -> remove the key with the nearest expire time (minor TTL)  移除离现在最快要过期的key

#volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰
#allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰

# noeviction -> don't expire at all, just return an error on write operations

APEND ONLY MODE aof配置

appendonly no #默认不开始aof持久化
appendfilename "appendonly.aof"  #持久化的文件的名字


appendfsync always    #每次修改就会同步,速度慢
appendfsync everysec  #每秒同步持久化一次
appendfsync no        #不同步,由操作系统选择时刻自己同步

内存淘汰策略

volatile-lru -> remove the key with an expire set using an LRU algorithm 在设置了过期时间的key中采用LRU策略移除

allkeys-lru -> remove any key according to the LRU algorithm 对所有key都进行LRU策略移除

volatile-random -> remove a random key with an expire set

allkeys-random -> remove a random key, any key

volatile-ttl -> remove the key with the nearest expire time (minor TTL) 移除离现在最快要过期的key

volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰
allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰

noeviction -> don’t expire at all, just return an error on write operations

Redis过期策略以及内存淘汰机制

Redis持久化

RDB

在这里插入图片描述

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的snapshot快照

在这里插入图片描述

fork一个子进程持久化;恢复数据时更加高效

RDB保存的文件时dump .rdb

在这里插入图片描述

  1. save规则满足的情况下,会自动触发RDB规则
  2. flushall 默认产生dump.rdb
  3. 退出redis,也会产生RDB文件

需只要将dump.rdb文件放在redis.conf配置的dir目录下,也就是存放rdb文件的目录下,redis会自动扫描并加持rdb文件。

优点:

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

2.对数据的完整性要求不高

缺点:

1.需要一定的时间间隔进行进程操作!也就是Redis意外宕机了,丢失的数据会比aof更多

2.fork进程的时候,会占用一定的内存空间,虽然可共享的数据内容不需要复制,但会复制之前进程空间的内存页表。由于 fork 操作运用写时复制技术,子进程只能共享 fork 操作时的内存数据。

fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。

AOF (Append only File)

写流程

img

>> [插图]

以日志的形式来记录每个写操作,将redis执行过所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据。数据很多的时候就会很慢。

  1. append -> 调用propagate方法将当前命令的内容append到redisServer对象的aof_buf变量中。主循环在下一个迭代进入多路复用的select方法前,Redis会通过flushAppendOnlyFile方法将aof_buf的内容write到OS buffer。但write操作只是将数据写到缓存中,什么时候从缓存真正落地到磁盘上,取决于操作系统。只有显式调用fsync()方法才能强制地让操作系统落地数据到磁盘。

  2. sync ->Redis通过flushAppendOnlyFile方法将aof_buf的内容write到AOF对应的文件中,同时根据同步策略判断是否调用fsync将数据写到磁盘。

    ❑ always:主循环的每个迭代的flushAppendOnlyFile函数中直接同步触发fsync方法,强制数据落地磁盘。该策略会降低Redis吞吐量,使得磁盘的写入成为Redis对外写服务的瓶颈,但由于每个命令都在写入磁盘后才返回,这种模式拥有最高的容错能力。
    ❑ every second:每秒异步地触发一次fsync方法。fsync方法的执行者是bio线程池中的某个线程flushAppendOnlyFile函数只是作为生产者将fsync任务放入队列,由bio线程消费并执行。
    ❑ no:不显式调用fsync,由操作系统决定什么时候落地磁盘。这种模式下,Redis无法决定增量的落地时间,因此容错能力不可控。

    1,2便是定时写流程,也就是AOF。rewrite严格来说并不属于持久化。

  3. rewrite,Redis通过rewrite机制合并历史AOF记录,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文本大于64MB时触发。

rewrite

AOF随着Redis持续的运行,会不断地产生新的数据append到AOF文件中,后者会日积月累越来越大,它占用了大量的磁盘空间,同时会降低Redis启动时的回放加载效率。Redis通过rewrite机制合并历史AOF记录,如图所示。

>> [插图]

这份快照仍然用cmd的形式来承载,只是将快照的所有key-value值用插入命令来表示。这样一来,rewrite出来的快照文件和普通的AOF文件格式一致,可复用相同的加载逻辑统一处理Redis启动时的数据恢复。rewrite通过bgrewrite方法实现,如图所示。
>> [插图]

  1. 主循环运行到定时任务处理时,一旦Redis发现Rewrite条件满足,则通过rewriteAppendOnlyFileBackground函数fork出一个子进程,开销等于同于bgsave过程。
  2. 由于 fork 操作运用写时复制技术,子进程只能共享 fork 操作时的内存数据子进程利用此内存快照进行rewirte,按照命令合并规则写入到新的 AOF 文件,每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync,默认为 32MB,防止单次刷盘数据过多造成硬盘阻塞。
  3. 子进程运行期间,Redis主进程继续对外提供服务,新的增量写入redisServer对象的aof_rewrite_buf_blocks中。
  4. 待子进程完成后,父进程将aof_rewrite_buf_blocks的内容将append到新AOF文件末尾,此处父进程需要进行IO
  5. 父进程将新AOF文件改名替换旧AOF文件。

aof保存的是appendonly.aof

AOF默认不开启的

假如aof文件有错误,那么redis是会启动失败。那么这时候需要使用redis-check-aof --fix。这个工具其实就是将恶意修改的记录删除了而已。

优点:

  1. 假如设置每一次修改都同步,文件完整性好,但是效率很低。
  2. 每秒同步一次,流失的数据量还可以接受。
  3. 由操作系统选择同步的时刻,效率最高。
  4. AOF同步的频率是高于RDB。假如宕机,那么丢失的数据也相对少一点。
  5. Redis 重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

缺点:

  1. 保存的文件大小,aof要远远大于rdb,恢复的速度也比rdb慢的多。
  2. Aof的运行效率要低于RDB,因为AOF的rewrite父进程有IO,因此AOF带来了持续的IO。运行效率不等于运行所需时间,RDB所需的完成时间会大于aof,因此频率更低,一般15分钟保存一次快照。
  3. AOF rewrite最后将rewrite过程中产生的新数据会写入到新文件中。因为这段时间同步了不止一次,新数据比较多,因此写入新数据会比较慢。因此需要减少rewrite的频率。

在这里插入图片描述

Redis主从持久化

redis主从持久化讨论

一张图搞定redis持久化

Redis持久化:RDB和AOF、SAVE和BGSAVE、数据恢复、AOF刷盘策略、AOF的bgrewrite优化-《深入分布式缓存:从原理到实践》读书笔记

订阅发布

在这里插入图片描述

命令描述
PSUBSCRIBE pattern [pattern..]订阅一个或多个符合给定模式的频道。
PUNSUBSCRIBE pattern [pattern..]退订一个或多个符合给定模式的频道。
PUBSUB subcommand [argument[argument]]查看订阅与发布系统状态。
PUBLISH channel message向指定频道发布消息
SUBSCRIBE channel [channel..]订阅给定的一个或多个频道。
SUBSCRIBE channel [channel..]退订一个或多个频道

在这里插入图片描述

用途:

  1. 实时消息系统
  2. 实习聊天
  3. 订阅,关注系统

缺点

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

Redis主从复制

概念

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

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

作用

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余的方式。
  2. 故障恢复:当主节点故障时,从节点可以暂时替代主节点提供服务,是一种服务冗余的方式
  3. 负载均衡:在主从复制的基础上,配合读写分离,由主节点进行写操作,从节点进行读操作,分担服务器的负载;尤其是在多读少写的场景下,通过多个从节点分担负载,提高并发量。百分之80的操作都是读操作
  4. 高可用(集群)基石:主从复制还是哨兵和集群能够实施的基础,因此说主从复制还是Redis的基础。至少一主二从配置,因为一从无法选举

配置

只需配置从节点(默认为主节点)

info replication  #查看当前节点信息

既然需要启动多个服务,就需要多个配置文件。每个配置文件对应修改以下信息:

  • 端口号

  • pid文件名

  • 日志文件名

  • rdb文件名

    修改完以上信息后,还没有配置谁是从节点

在这里插入图片描述

SLAVEOF host port	#配置是谁的从节点

使用此命令搭建,是暂时的;从机的配置文件中进行配置,这样的话是永久的

配置完从机后的信息

配置完从机后的信息

主机的信息

在这里插入图片描述

在配置文件中设置

在这里插入图片描述

使用规则

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

  2. 当主机断电宕机后,默认情况下从机的角色不会发生变化 ,集群中只是失去了写操作,依然能够读到主机已经写入的数据(主从复制),当主机恢复以后,又会连接上从机恢复原状。

  3. 当从机断电宕机后,若不是使用配置文件配置的从机,再次启动后成为master,所以是无法获取主机的数据的。若此时重新配置称为从机,又可以获取到主机的所有数据。这里涉及复制原理。

    复制原理

    slave启动成功连接到master后,会发送sync同步命令,master接到命令,会启动后台的存盘进程,后台进程执行完毕之后,将整个数据文件传送给slave,并完成一次同步,也就是全量复制

    • 全量复制:slave接到数据库文件后,将其存盘并加载到内存中

    • 增量复制:master继续将新的收集到的修改命令依次传送给slave。

    完成同步只要连接到主机,一次全量复制将被执行。

  4. 主机故障后,有两种方式可以产生新的主机:

    • 某台从机手动执行命令slaveof no one,变为master,然后其他从机再配置slaveof host port成为他的从机
    • 使用哨兵模式(自动选举)

蜈蚣模式

针对上面我们的主从模式是这样的

在这里插入图片描述

蜈蚣模式是这样的

在这里插入图片描述

蜈蚣模式下,120.25.6.203才是主机模式,假如120.25.6.203宕机了,那么120.25.6.205依然没有办法进行写操作,依然是slave,依然需要手动配置才能选出主节点

哨兵模式

哨兵的作用:

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

在这里插入图片描述

如果主服务器宕机,哨兵1先检测到这个结果,系统不会马上进行投票(主观下线),当其他哨兵也检查到并数量达到一定后,哨兵就会发起投票,进行故障转移,切换成功之后,就会通过发布订阅模式,实现票数最多的从机切换主机客观下线)。

sentinel monitor mymaster 127.0.0.1 6379 1   #数字1表示,当投票大>=1时,认为其客观下线

redis-sentinel sentinel.conf  #启动哨兵,单哨兵模式

在这里插入图片描述

现在6379宕机,自动选取6381作为master(里面再有一个投票算法)。

在这里插入图片描述

如果6379重新连接回来,那么只能当从机,主机依然是新选出来的。

优点:

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

缺点:

  1. Redis不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦
  2. 实现哨兵模式的配置其实是很麻烦的,里面有很多配置项
# 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无法正常启动成功。
#通知脚本
#shell编程
# 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


缓存穿透与雪崩

缓存穿透(查不到)

在默认情况下,用户请求数据时,会先在缓存(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,设置不同的过期时间,让缓存失效的时间点尽量均匀。

Cache和Buffer

cache 是为了弥补高速设备和低速设备的鸿沟而引入的中间层,最终起到加快访问速度的作用。
而 buffer 的主要目的进行流量整形,把突发的大数量较小规模的 I/O 整理成平稳的小数量较大规模的 I/O,以减少响应次数(比如从网上下电影,你不能下一点点数据就写一下硬盘,而是积攒一定量的数据以后一整块一起写,不然硬盘都要被你玩坏了)。

1、Buffer(缓冲区)是系统两端处理速度平衡(从长时间尺度上看)时使用的。它的引入是为了减小短期内突发I/O的影响,起到流量整形的作用。比如生产者——消费者问题,他们产生和消耗资源的速度大体接近,加一个buffer可以抵消掉资源刚产生/消耗时的突然变化。
2、Cache(缓存)则是系统两端处理速度不匹配时的一种折衷策略。因为CPU和memory之间的速度差异越来越大,所以人们充分利用数据的局部性(locality)特征,通过使用存储系统分级(memory hierarchy)的策略来减小这种差异带来的影响。
3、假定以后存储器访问变得跟CPU做计算一样快,cache就可以消失,但是buffer依然存在。比如从网络上下载东西,瞬时速率可能会有较大变化,但从长期来看却是稳定的,这样就能通过引入一个buffer使得OS接收数据的速率更稳定,进一步减少对磁盘的伤害。
4、TLB(Translation Lookaside Buffer,翻译后备缓冲器)名字起错了,其实它是一个cache.

管道技术

管道技术的优势

管道技术最显著的优势是提高了 redis 服务的性能。将多次数据打包成一个包发送,减少持续性的网路IO。

速度不够,管道来凑——Redis管道技术

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值