Redis学习

Redis

Redis学习

因为没有指定配置文件

需配置

redis-server redis.windows.conf

之后自动启动

测试性能

redis-benchmark -p 6379 -c 100 -n 10000

Redis学习

Redis学习

基础概念:

Redis学习

Redis学习

清空当前数据库:flushdb

清空全部数据库:flushall

redis是单线程的

redis的瓶颈是机器的内存和网络的带宽,用单线程既然可以实现,就用单线程了

为什么单线程还这么快呢

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

底层数据结构(参考

简单动态字符串

Redis学习

一般来说,SDS 除了保存数据库中的字符串值以外,SDS 还可以作为缓冲区(buffer):包括 AOF 模块中的AOF缓冲区以及客户端状态中的输入缓冲区。

链表

Redis链表特性:

①、双端:链表具有前置节点和后置节点的引用,获取这两个节点时间复杂度都为O(1)。

②、无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问都是以 NULL 结束。

③、带链表长度计数器:通过 len 属性获取链表长度的时间复杂度为 O(1)。

④、多态:链表节点使用 void* 指针来保存节点值,可以保存各种不同类型的值

字典

Redis 的字典使用哈希表作为底层实现、

key 用来保存键,val 属性用来保存值,值可以是一个指针,也可以是uint64_t整数,也可以是int64_t整数。

注意这里还有一个指向下一个哈希表节点的指针,我们知道哈希表最大的问题是存在哈希冲突,如何解决哈希冲突,有开放地址法和链地址法。这里采用的便是链地址法,通过next这个指针可以将多个哈希值相同的键值对连接在一起,用来解决 哈希冲突

跳表

跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其它节点的指针,从而达到快速访问节点的目的。具有如下性质:

1、由很多层结构组成;

2、每一层都是一个有序的链表,排列顺序为由高层到底层,都至少包含两个链表节点,分别是前面的head节点和后面的nil节点;

3、最底层的链表包含了所有的元素;

4、如果一个元素出现在某一层的链表中,那么在该层之下的链表也全都会出现(上一层的元素是当前层的元素的子集);

5、链表中的每个节点都包含两个指针,一个指向同一层的下一个链表节点,另一个指向下一层的同一个链表节点;

​ ①、搜索:从最高层的链表节点开始,如果比当前节点要大和比当前层的下一个节点要小,那么则往下找,也就是和当前层的下一层的节点的下一个节点进行比较,以此类推,一直找到最底层的最后一个节点,如果找到则返回,反之则返回空。

②、插入:首先确定插入的层数,有一种方法是假设抛一枚硬币,如果是正面就累加,直到遇见反面为止,最后记录正面的次数作为插入的层数。当确定插入的层数k后,则需要将新元素插入到从底层到k层。

③、删除:在各个层中找到包含指定值的节点,然后将节点从链表中删除即可,如果删除以后只剩下头尾两个节点,则删除这一层。

五大数据类型的应用场景

对于string 数据类型,因为string 类型是二进制安全的,可以用来存放图片,视频等内容,另外由于Redis的高性能读写功能,而string类型的value也可以是数字,可以用作计数器(INCR,DECR),比如分布式环境中统计系统的在线人数,秒杀等。

对于 hash 数据类型,value 存放的是键值对,比如可以做单点登录存放用户信息。

对于 list 数据类型,可以实现简单的消息队列,另外可以利用lrange命令,做基于redis的分页功能

对于 set 数据类型,由于底层是字典实现的,查找元素特别快,另外set 数据类型不允许重复,利用这两个特性我们可以进行全局去重,比如在用户注册模块,判断用户名是否注册;另外就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。

对于 zset 数据类型,有序的集合,可以做范围查找,排行榜应用,取 TOP N 操作等

五大数据类型

redis-key

#移除name key
move name 1

Redis学习
#设置过期时间
expire name 10

Redis学习

查看剩余过期时间:ttl name;

#查看键的类型
type name

Redis学习

String

Redis学习

如果append后的键不存在就创建一个,相当于set

Redis学习

获取一部分值

Redis学习

获取全部的值

Redis学习

替换值

Redis学习

setex 设置过期时间
setnx 如果没有这个键就设置值成功,如果已存在这个键就设置不成功(在分布式锁中常应用 )

Redis学习

批量设置键和值,批量获取值

Redis学习

msetnx 具有原子性

设置对象,以json字符串的形式

Redis学习

getset

Redis学习

List

在redis中,list可以被我们玩成栈,队列,阻塞队列

lpush 放进列表数据
lrange 取出指定位置的数据,可以看出下标是倒着来的。

Redis学习

说明rpush把值放在了队列的最后面

Redis学习

从列表中移除值,可以分为移除左边的和右边的

Redis学习

通过下标获取值

Redis学习

获取列表长度

llen

移除指定的值,可指定数量

Redis学习

通过下标截取指定的长度

Redis学习

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

Redis学习

更新指定位置的值

Redis学习

Redis学习

set

Redis学习

Redis学习

Redis学习

Redis学习

Redis学习

hash

Map集合,key-map,那时候这个值是一个map集合,本质和String类型没有太大区别,还是一个简单的key-vlaue

Redis学习

获取hash表的内容长度

Redis学习

获取所有的field和所有的值

Redis学习

hash更适合于对象的存储

Zset(有序集合)

排列

Redis学习

显示工资小于2000的工资排列

Redis学习

移除指定元素

Redis学习

获取集合中的个数

zcard salary

获取指定区间的成员数量

Redis学习

总结:

Redis学习

三种特殊数据类型

Geospatial(地理位置)

geoadd 添加地理位置

geoadd key longitude latitude member [longitude latitude member ...]

geopos获得地理位置详细信息

geopos key member [member ...]

geodist获得两个地点之间的距离,可在后面追加获得结果的单位 km m

geodist key member1 member2 [unit]

georadius获得以某一点经纬度为圆心,一定距离为半径之内的元素

georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC

georadiusbymember获得某一成员为圆心,一定距离为半径之内的元素

geo底层的实现原理是zset,可以使用zset命令来操作geo

hyperloglog

统计基数

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

传统的方式是用set,如果存储量太大的话就比较麻烦

测试

Redis学习

bitmaps

位存储

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

统计一周的打卡情况

Redis学习

查看某一天的打卡情况

Redis学习

查看打卡了几天

127.0.0.1:6379> bitcount si
(integer) 2

事务

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

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

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

  1. 开启事务
  2. 命令入队
  3. 执行事务

正常执行事务

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 k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec#执行事务
1) OK
2) OK
3) "v2"
4) OK
127.0.0.1:6379>

放弃事务

discard

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

127.0.0.1:6379> get k1
(nil)
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> getset k3
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.#所有事务不会被运行
127.0.0.1:6379>

运行时异常(1/0),其他命令正常执行,错误命令抛出异常

127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1#字符串不会加1
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range#属于运行时异常
2) "v1" #正常执行
127.0.0.1:6379>

监控

乐观锁

获取version,比较version

监视:

watch key [key …]

执行之前,另外一个线程如果修改了我们的值,事务就会执行失败,就要放弃监视,然后重新监视

放弃监视

unwatch key

Jedis

配置依赖

<dependencies>
        <dependency>
            <groupid>redis.clients</groupid>
            <artifactid>jedis</artifactid>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupid>com.alibaba</groupid>
            <artifactid>fastjson</artifactid>
            <version>1.2.62</version>
        </dependency>

    </dependencies>

创建连接进行测试

Jedis jedis=new Jedis("127.0.0.1", 6379);
System.out.println(jedis.ping());

springboot整合

底层为lettuce:采用netty,实例可以在多个线程中共享,不存在线程不安全的情况,NIO模式

jeids采用直连,多线程不安全,如想避免不安全,就使用jedis pool连接池,BIO模式

操作各种基本类型

Redis学习

获得链接,操作数据库

Redis学习

序列化

放入对象需序列化

@Configuration
public class RedisConfig {

    //&#x7F16;&#x5199;&#x81EA;&#x5DF1;&#x7684;redisTemplate
    @Bean
    @SuppressWarnings("all")

    public RedisTemplate<string, object> redisTemplate(RedisConnectionFactory redisConnectionFactory)throws UnknownHostException {

        RedisTemplate<string,object> redisTemplate=new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        //Json&#x5E8F;&#x5217;&#x5316;&#x914D;&#x7F6E;
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper=new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        //String&#x7684;&#x5E8F;&#x5217;&#x5316;
        StringRedisSerializer stringRedisSerializer=new StringRedisSerializer();

        //key&#x91C7;&#x7528;String&#x7684;&#x5E8F;&#x5217;&#x5316;&#x65B9;&#x5F0F;
        redisTemplate.setKeySerializer(stringRedisSerializer);
        //Hash&#x7684;&#x5E8F;&#x5217;&#x5316;&#x65B9;&#x5F0F;&#x4E5F;&#x91C7;&#x7528;String&#x7684;&#x65B9;&#x5F0F;
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        //value&#x5E8F;&#x5217;&#x5316;&#x65B9;&#x5F0F;&#x91C7;&#x7528;jackson
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}</string,object></string,>

———————–固定配置模板

Redis.conf详解

Redis学习

对大小写不敏感

包含

Redis学习
可包含多个配置文件

网络

bind 127.0.0.1
protected-mode yes #&#x4FDD;&#x62A4;&#x6A21;&#x5F0F;
port 6379 #&#x9ED8;&#x8BA4;&#x7AEF;&#x53E3;

绑定的IP

通用

NOT SUPPORTED ON WINDOWS daemonize no
#window&#x7AEF;&#x4E0D;&#x652F;&#x6301;&#x6B64;&#x914D;&#x7F6E;&#xFF0C;&#x914D;&#x7F6E;&#x6B64;&#x9879;&#x987B;&#x5728;linux&#x7AEF;
daemonize yes #&#x4EE5;&#x5B88;&#x62A4;&#x8FDB;&#x7A0B;&#x7684;&#x65B9;&#x5F0F;&#x8FD0;&#x884C;&#xFF0C;&#x9ED8;&#x8BA4;&#x662F;no&#xFF0C;&#x6211;&#x4EEC;&#x9700;&#x8981;&#x81EA;&#x5DF1;&#x5F00;&#x542F;&#x4E3A;yes

NOT SUPPORTED ON WINDOWS pidfile /var/run/redis.pid
#&#x5982;&#x679C;&#x6307;&#x5B9A;&#x4E3A;&#x540E;&#x53F0;&#x65B9;&#x5F0F;&#x8FD0;&#x884C;&#xFF0C;&#x5219;&#x9700;&#x6307;&#x5B9A;pid&#x6587;&#x4EF6;
pidfile /var/run/redis.pid

#&#x65E5;&#x5FD7;&#x7EA7;&#x522B;
debug (a lot of information, useful for development/testing)
verbose (many rarely useful info, but not a mess like the debug level)
notice (moderately verbose, what you want in production probably)
warning (only very important / critical messages are logged)
loglevel notice

logfile "" #&#x65E5;&#x5FD7;&#x6587;&#x4EF6;&#x4F4D;&#x7F6E;
databases 16 #&#x9ED8;&#x8BA4;&#x6570;&#x636E;&#x5E93;&#x6570;&#x91CF;

快照

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

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

save 900 1 #&#x5982;&#x679C;900s&#x5185;&#xFF0C;&#x6709;&#x4E00;&#x4E2A;key&#x8FDB;&#x884C;&#x4E86;&#x4FEE;&#x6539;&#xFF0C;&#x6211;&#x4EEC;&#x5C06;&#x8FDB;&#x884C;&#x6301;&#x4E45;&#x5316;&#x64CD;&#x4F5C;&#x3002;&#x4EE5;&#x4E0B;&#x7686;&#x540C;
save 300 10
save 60 10000

stop-writes-on-bgsave-error yes#&#x6301;&#x4E45;&#x5316;&#x51FA;&#x9519;&#xFF0C;redis&#x662F;&#x5426;&#x8FD8;&#x7EE7;&#x7EED;&#x5DE5;&#x4F5C;
rdbcompression yes#&#x662F;&#x5426;&#x538B;&#x7F29;rdb&#x6587;&#x4EF6;
rdbchecksum yes #&#x4FDD;&#x5B58;rdb&#x6587;&#x4EF6;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x8FDB;&#x884C;&#x9519;&#x8BEF;&#x7684;&#x68C0;&#x67E5;&#x6821;&#x9A8C;
dir ./ #rdb&#x6587;&#x4EF6;&#x7684;&#x4FDD;&#x5B58;&#x76EE;&#x5F55;

安全

127.0.0.1:6379> ping
PONG
127.0.0.1:6379> config set requirepass 1234 #&#x8BBE;&#x7F6E;&#x5BC6;&#x7801;
OK
127.0.0.1:6379> config get requirepass
(error) NOAUTH Authentication required.

127.0.0.1:6379> auth 1234 #&#x767B;&#x5F55;
OK
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "1234"
127.0.0.1:6379>

Redis学习

客户端连接相关

maxclients 10000a &#x6700;&#x5927;&#x5BA2;&#x6237;&#x7AEF;&#x6570;&#x91CF;
maxmemory <bytes> &#x6700;&#x5927;&#x5185;&#x5B58;&#x9650;&#x5236;
maxmemory-policy noeviction &#x5185;&#x5B58;&#x5230;&#x8FBE;&#x6781;&#x9650;&#x503C;&#x7684;&#x5904;&#x7406;&#x7B56;&#x7565;</bytes>

maxmemory-policy 六种方式

1、volatile-lru:只对设置了过期时间的key进行LRU(默认值)

2、allkeys-lru : 删除lru算法的key

3、volatile-random:随机删除即将过期key

4、allkeys-random:随机删除

5、volatile-ttl : 删除即将过期的

6、noeviction : 永不过期,返回错误

Redis持久化

RDB:Redis Databases

什么是RDB

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

Redis学习

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

三种触发方式

Redis学习

还有一种就是自动触发

工作原理

在进行 RDB 的时候, redis 的主线程是不会做 io 操作的,主线程会 fork 一个子线程来完成该操作;

  1. Redis 调用forks。同时拥有父进程和子进程。
  2. 子进程将数据集写入到一个临时 RDB 文件中。
  3. 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。

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

Redis学习

触发机制

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

优缺点

优点:

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

缺点:

耗时,耗性能

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

AOF

Append Only File

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

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

三种策略

always:每条命令都刷盘

everysec:每一秒刷一次

no:操作系统决定

什么是AOF

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

如果要使用AOF,需要修改配置文件:

Redis学习

appendonly no yes则表示启用AOF

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

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

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

优点和缺点

123456appendonly yes  # &#x9ED8;&#x8BA4;&#x662F;&#x4E0D;&#x5F00;&#x542F;aof&#x6A21;&#x5F0F;&#x7684;&#xFF0C;&#x9ED8;&#x8BA4;&#x662F;&#x4F7F;&#x7528;rdb&#x65B9;&#x5F0F;&#x6301;&#x4E45;&#x5316;&#x7684;&#xFF0C;&#x5728;&#x5927;&#x90E8;&#x5206;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;rdb&#x5B8C;&#x5168;&#x591F;&#x7528;
appendfilename "appendonly.aof"

appendfsync always # &#x6BCF;&#x6B21;&#x4FEE;&#x6539;&#x90FD;&#x4F1A;sync &#x6D88;&#x8017;&#x6027;&#x80FD;
appendfsync everysec # &#x6BCF;&#x79D2;&#x6267;&#x884C;&#x4E00;&#x6B21; sync &#x53EF;&#x80FD;&#x4F1A;&#x4E22;&#x5931;&#x8FD9;&#x4E00;&#x79D2;&#x7684;&#x6570;&#x636E;
appendfsync no # &#x4E0D;&#x6267;&#x884C; sync ,&#x8FD9;&#x65F6;&#x5019;&#x64CD;&#x4F5C;&#x7CFB;&#x7EDF;&#x81EA;&#x5DF1;&#x540C;&#x6B65;&#x6570;&#x636E;&#xFF0C;&#x901F;&#x5EA6;&#x6700;&#x5FEB;

优点

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

缺点

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

AOF重写

fork出子进程,一个进行重写,一个把重写过程中产生的aof记录写到buffer中,最后添加到AOF新文件中。

RDB和AOP选择

RDB优势与劣势

优势

  • 适合大规模的数据恢复
  • 对数据完整性和一致性要求不高

劣势

  • 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。
  • Fork的时候,内存中的数据被 &#x514B;&#x9686;了一份, &#x5927;&#x81F4;2&#x500D;的膨胀性能需要考虑

AOF优势/劣势

优势

  • 每次修改同步:appendfsync always同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好
  • 每秒同步:appendfsync everysec异步操作,每秒记录,如果一秒内宕机,仅一秒内的数据丢失

劣势

  • 相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
  • Aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同

RDB消耗性能大,如果宕机可能丢失最后一次所做的修改,但是文件小,恢复快

为什么RDB恢复数据集较快

AOF,存放的指令日志,做数据恢复的时候,其实是要回放和执行所有的指令日志,来恢复出来内存中的所有数据的;
RDB,就是一份数据文件,恢复的时候,直接加载到内存中即可

Redis学习

如何选择使用哪种持久化方式?

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

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

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

常见问题

fork

内存越大,fork时间越长,所以设置参数maxmemory参数

降低fork频率,避免不必要的全量复制

Redis学习

AOF追加阻塞

Redis学习

距离上次同步超过两秒,就阻塞主线程,直到同步完成

参考硬盘优化的相关策略

Redis学习

Redis发布订阅

订阅

subscribe hongdou
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "hongdou"
3) (integer) 1

发布

127.0.0.1:6379> publish hongdou hahaha
(integer) 1

结果:

1) "message"
2) "hongdou"
3) "hahaha"

原理

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

Redis学习

客户端订阅,就被链接到对应频道的链表的尾部,退订则就是将客户端节点从链表中移除。

缺点

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

应用

  1. 消息订阅:公众号订阅,微博关注等等(起始更多是使用消息队列来进行实现)
  2. 多人在线聊天室。

稍微复杂的场景,我们就会使用消息中间件MQ处理。

Redis主从复制

概念

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

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

作用

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

为什么使用集群

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

环境配置

我们在讲解配置文件的时候,注意到有一个 replication模块 (见Redis.conf中第8条)

查看当前库的信息: info replication

123456789101112127.0.0.1:6379> info replication
Replication
role:master # &#x89D2;&#x8272;
connected_slaves:0 # &#x4ECE;&#x673A;&#x6570;&#x91CF;
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

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

  • 端口号
  • pid文件名
  • 日志文件名
  • rdb文件名
注意:window配置方法:

开启多个端口服务器
1.配置文件
将redis.windows-service.conf复制一份,改名为相应文件,并更改配置文件中的端口为指定端口,以6380为例

port 6380

2.安装服务
redis-server –service-install –service-name redis_6380 redis.windows-service-6380.conf
3.启动服务
redis-server –service-start –service-name redis_6380
4.停止服务
redis-server –service-stop –service-name redis_6380
5.卸载服务
redis-server –service-uninstall –service-name redis_6380

指定端口启动客户端:
redis.cli -p 端口号

Redis学习

启动单机多服务集群:

Redis学习

一主二从配置

默认情况下,每台Redis服务器都是主节点;一般情况下只用配置从机就好了!

认老大!一主(79)二从(80,81)

使用 SLAVEOF host port就可以为从机配置主机了。

Redis学习

Redis学习

主机截图:

Redis学习

使用命令搭建是暂时的,真实开发中应该在从机的配置文件中进行配置,这样的话是永久的。

Redis学习

规则

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

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

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

复制原理

从机成功连接到主机后会发送一个同步命令

主机启动bgsave,开始生成RDB文件,同时把期间的写命令缓存在内存中,RDB文件生成后发送给slave,slave会先写入磁盘,再从磁盘加载到内存,接着master将缓存中的写命令发送到slave,slave再进行同步

Redis学习

全量复制:主机生成RDB——-》同时缓存写命令———–》发送给从机,从机清空旧数据加载rdb到内存中———》同时基于旧数据版本提供服务

增量复制:每次更新数据同步到从机

过期key处理:主机删掉,模拟一条del指令发给slave

层层链路

主机从机成链路式连接

如果主机断开了连接,我们可以使用 SLAVEOF no one让自己变成主机!其他的节点就可以手动连接到最新的主节点

哨兵模式的全部配置

完整的哨兵模式配置文件 sentinel.conf

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970# Example sentinel.conf

&#x54E8;&#x5175;sentinel&#x5B9E;&#x4F8B;&#x8FD0;&#x884C;&#x7684;&#x7AEF;&#x53E3; &#x9ED8;&#x8BA4;26379
port 26379

&#x54E8;&#x5175;sentinel&#x7684;&#x5DE5;&#x4F5C;&#x76EE;&#x5F55;
dir /tmp

&#x54E8;&#x5175;sentinel&#x76D1;&#x63A7;&#x7684;redis&#x4E3B;&#x8282;&#x70B9;&#x7684; ip port
master-name  &#x53EF;&#x4EE5;&#x81EA;&#x5DF1;&#x547D;&#x540D;&#x7684;&#x4E3B;&#x8282;&#x70B9;&#x540D;&#x5B57; &#x53EA;&#x80FD;&#x7531;&#x5B57;&#x6BCD;A-z&#x3001;&#x6570;&#x5B57;0-9 &#x3001;&#x8FD9;&#x4E09;&#x4E2A;&#x5B57;&#x7B26;".-_"&#x7EC4;&#x6210;&#x3002;
quorum &#x5F53;&#x8FD9;&#x4E9B;quorum&#x4E2A;&#x6570;sentinel&#x54E8;&#x5175;&#x8BA4;&#x4E3A;master&#x4E3B;&#x8282;&#x70B9;&#x5931;&#x8054; &#x90A3;&#x4E48;&#x8FD9;&#x65F6; &#x5BA2;&#x89C2;&#x4E0A;&#x8BA4;&#x4E3A;&#x4E3B;&#x8282;&#x70B9;&#x5931;&#x8054;&#x4E86;
sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 1

&#x5F53;&#x5728;Redis&#x5B9E;&#x4F8B;&#x4E2D;&#x5F00;&#x542F;&#x4E86;requirepass foobared &#x6388;&#x6743;&#x5BC6;&#x7801; &#x8FD9;&#x6837;&#x6240;&#x6709;&#x8FDE;&#x63A5;Redis&#x5B9E;&#x4F8B;&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#x90FD;&#x8981;&#x63D0;&#x4F9B;&#x5BC6;&#x7801;
&#x8BBE;&#x7F6E;&#x54E8;&#x5175;sentinel &#x8FDE;&#x63A5;&#x4E3B;&#x4ECE;&#x7684;&#x5BC6;&#x7801; &#x6CE8;&#x610F;&#x5FC5;&#x987B;&#x4E3A;&#x4E3B;&#x4ECE;&#x8BBE;&#x7F6E;&#x4E00;&#x6837;&#x7684;&#x9A8C;&#x8BC1;&#x5BC6;&#x7801;
sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd

&#x6307;&#x5B9A;&#x591A;&#x5C11;&#x6BEB;&#x79D2;&#x4E4B;&#x540E; &#x4E3B;&#x8282;&#x70B9;&#x6CA1;&#x6709;&#x5E94;&#x7B54;&#x54E8;&#x5175;sentinel &#x6B64;&#x65F6; &#x54E8;&#x5175;&#x4E3B;&#x89C2;&#x4E0A;&#x8BA4;&#x4E3A;&#x4E3B;&#x8282;&#x70B9;&#x4E0B;&#x7EBF; &#x9ED8;&#x8BA4;30&#x79D2;
sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000

&#x8FD9;&#x4E2A;&#x914D;&#x7F6E;&#x9879;&#x6307;&#x5B9A;&#x4E86;&#x5728;&#x53D1;&#x751F;failover&#x4E3B;&#x5907;&#x5207;&#x6362;&#x65F6;&#x6700;&#x591A;&#x53EF;&#x4EE5;&#x6709;&#x591A;&#x5C11;&#x4E2A;slave&#x540C;&#x65F6;&#x5BF9;&#x65B0;&#x7684;master&#x8FDB;&#x884C; &#x540C;&#x6B65;&#xFF0C;
&#x8FD9;&#x4E2A;&#x6570;&#x5B57;&#x8D8A;&#x5C0F;&#xFF0C;&#x5B8C;&#x6210;failover&#x6240;&#x9700;&#x7684;&#x65F6;&#x95F4;&#x5C31;&#x8D8A;&#x957F;&#xFF0C;
&#x4F46;&#x662F;&#x5982;&#x679C;&#x8FD9;&#x4E2A;&#x6570;&#x5B57;&#x8D8A;&#x5927;&#xFF0C;&#x5C31;&#x610F;&#x5473;&#x7740;&#x8D8A; &#x591A;&#x7684;slave&#x56E0;&#x4E3A;replication&#x800C;&#x4E0D;&#x53EF;&#x7528;&#x3002;
&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x5C06;&#x8FD9;&#x4E2A;&#x503C;&#x8BBE;&#x4E3A; 1 &#x6765;&#x4FDD;&#x8BC1;&#x6BCF;&#x6B21;&#x53EA;&#x6709;&#x4E00;&#x4E2A;slave &#x5904;&#x4E8E;&#x4E0D;&#x80FD;&#x5904;&#x7406;&#x547D;&#x4EE4;&#x8BF7;&#x6C42;&#x7684;&#x72B6;&#x6001;&#x3002;
sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1

&#x6545;&#x969C;&#x8F6C;&#x79FB;&#x7684;&#x8D85;&#x65F6;&#x65F6;&#x95F4; failover-timeout &#x53EF;&#x4EE5;&#x7528;&#x5728;&#x4EE5;&#x4E0B;&#x8FD9;&#x4E9B;&#x65B9;&#x9762;&#xFF1A;
#1. &#x540C;&#x4E00;&#x4E2A;sentinel&#x5BF9;&#x540C;&#x4E00;&#x4E2A;master&#x4E24;&#x6B21;failover&#x4E4B;&#x95F4;&#x7684;&#x95F4;&#x9694;&#x65F6;&#x95F4;&#x3002;
#2. &#x5F53;&#x4E00;&#x4E2A;slave&#x4ECE;&#x4E00;&#x4E2A;&#x9519;&#x8BEF;&#x7684;master&#x90A3;&#x91CC;&#x540C;&#x6B65;&#x6570;&#x636E;&#x5F00;&#x59CB;&#x8BA1;&#x7B97;&#x65F6;&#x95F4;&#x3002;&#x76F4;&#x5230;slave&#x88AB;&#x7EA0;&#x6B63;&#x4E3A;&#x5411;&#x6B63;&#x786E;&#x7684;master&#x90A3;&#x91CC;&#x540C;&#x6B65;&#x6570;&#x636E;&#x65F6;&#x3002;
#3.&#x5F53;&#x60F3;&#x8981;&#x53D6;&#x6D88;&#x4E00;&#x4E2A;&#x6B63;&#x5728;&#x8FDB;&#x884C;&#x7684;failover&#x6240;&#x9700;&#x8981;&#x7684;&#x65F6;&#x95F4;&#x3002;
#4.&#x5F53;&#x8FDB;&#x884C;failover&#x65F6;&#xFF0C;&#x914D;&#x7F6E;&#x6240;&#x6709;slaves&#x6307;&#x5411;&#x65B0;&#x7684;master&#x6240;&#x9700;&#x7684;&#x6700;&#x5927;&#x65F6;&#x95F4;&#x3002;&#x4E0D;&#x8FC7;&#xFF0C;&#x5373;&#x4F7F;&#x8FC7;&#x4E86;&#x8FD9;&#x4E2A;&#x8D85;&#x65F6;&#xFF0C;slaves&#x4F9D;&#x7136;&#x4F1A;&#x88AB;&#x6B63;&#x786E;&#x914D;&#x7F6E;&#x4E3A;&#x6307;&#x5411;master&#xFF0C;&#x4F46;&#x662F;&#x5C31;&#x4E0D;&#x6309;parallel-syncs&#x6240;&#x914D;&#x7F6E;&#x7684;&#x89C4;&#x5219;&#x6765;&#x4E86;
&#x9ED8;&#x8BA4;&#x4E09;&#x5206;&#x949F;
sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000

SCRIPTS EXECUTION

#&#x914D;&#x7F6E;&#x5F53;&#x67D0;&#x4E00;&#x4E8B;&#x4EF6;&#x53D1;&#x751F;&#x65F6;&#x6240;&#x9700;&#x8981;&#x6267;&#x884C;&#x7684;&#x811A;&#x672C;&#xFF0C;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x811A;&#x672C;&#x6765;&#x901A;&#x77E5;&#x7BA1;&#x7406;&#x5458;&#xFF0C;&#x4F8B;&#x5982;&#x5F53;&#x7CFB;&#x7EDF;&#x8FD0;&#x884C;&#x4E0D;&#x6B63;&#x5E38;&#x65F6;&#x53D1;&#x90AE;&#x4EF6;&#x901A;&#x77E5;&#x76F8;&#x5173;&#x4EBA;&#x5458;&#x3002;
#&#x5BF9;&#x4E8E;&#x811A;&#x672C;&#x7684;&#x8FD0;&#x884C;&#x7ED3;&#x679C;&#x6709;&#x4EE5;&#x4E0B;&#x89C4;&#x5219;&#xFF1A;
#&#x82E5;&#x811A;&#x672C;&#x6267;&#x884C;&#x540E;&#x8FD4;&#x56DE;1&#xFF0C;&#x90A3;&#x4E48;&#x8BE5;&#x811A;&#x672C;&#x7A0D;&#x540E;&#x5C06;&#x4F1A;&#x88AB;&#x518D;&#x6B21;&#x6267;&#x884C;&#xFF0C;&#x91CD;&#x590D;&#x6B21;&#x6570;&#x76EE;&#x524D;&#x9ED8;&#x8BA4;&#x4E3A;10
#&#x82E5;&#x811A;&#x672C;&#x6267;&#x884C;&#x540E;&#x8FD4;&#x56DE;2&#xFF0C;&#x6216;&#x8005;&#x6BD4;2&#x66F4;&#x9AD8;&#x7684;&#x4E00;&#x4E2A;&#x8FD4;&#x56DE;&#x503C;&#xFF0C;&#x811A;&#x672C;&#x5C06;&#x4E0D;&#x4F1A;&#x91CD;&#x590D;&#x6267;&#x884C;&#x3002;
#&#x5982;&#x679C;&#x811A;&#x672C;&#x5728;&#x6267;&#x884C;&#x8FC7;&#x7A0B;&#x4E2D;&#x7531;&#x4E8E;&#x6536;&#x5230;&#x7CFB;&#x7EDF;&#x4E2D;&#x65AD;&#x4FE1;&#x53F7;&#x88AB;&#x7EC8;&#x6B62;&#x4E86;&#xFF0C;&#x5219;&#x540C;&#x8FD4;&#x56DE;&#x503C;&#x4E3A;1&#x65F6;&#x7684;&#x884C;&#x4E3A;&#x76F8;&#x540C;&#x3002;
#&#x4E00;&#x4E2A;&#x811A;&#x672C;&#x7684;&#x6700;&#x5927;&#x6267;&#x884C;&#x65F6;&#x95F4;&#x4E3A;60s&#xFF0C;&#x5982;&#x679C;&#x8D85;&#x8FC7;&#x8FD9;&#x4E2A;&#x65F6;&#x95F4;&#xFF0C;&#x811A;&#x672C;&#x5C06;&#x4F1A;&#x88AB;&#x4E00;&#x4E2A;SIGKILL&#x4FE1;&#x53F7;&#x7EC8;&#x6B62;&#xFF0C;&#x4E4B;&#x540E;&#x91CD;&#x65B0;&#x6267;&#x884C;&#x3002;

#&#x901A;&#x77E5;&#x578B;&#x811A;&#x672C;:&#x5F53;sentinel&#x6709;&#x4EFB;&#x4F55;&#x8B66;&#x544A;&#x7EA7;&#x522B;&#x7684;&#x4E8B;&#x4EF6;&#x53D1;&#x751F;&#x65F6;&#xFF08;&#x6BD4;&#x5982;&#x8BF4;redis&#x5B9E;&#x4F8B;&#x7684;&#x4E3B;&#x89C2;&#x5931;&#x6548;&#x548C;&#x5BA2;&#x89C2;&#x5931;&#x6548;&#x7B49;&#x7B49;&#xFF09;&#xFF0C;&#x5C06;&#x4F1A;&#x53BB;&#x8C03;&#x7528;&#x8FD9;&#x4E2A;&#x811A;&#x672C;&#xFF0C;
#&#x8FD9;&#x65F6;&#x8FD9;&#x4E2A;&#x811A;&#x672C;&#x5E94;&#x8BE5;&#x901A;&#x8FC7;&#x90AE;&#x4EF6;&#xFF0C;SMS&#x7B49;&#x65B9;&#x5F0F;&#x53BB;&#x901A;&#x77E5;&#x7CFB;&#x7EDF;&#x7BA1;&#x7406;&#x5458;&#x5173;&#x4E8E;&#x7CFB;&#x7EDF;&#x4E0D;&#x6B63;&#x5E38;&#x8FD0;&#x884C;&#x7684;&#x4FE1;&#x606F;&#x3002;&#x8C03;&#x7528;&#x8BE5;&#x811A;&#x672C;&#x65F6;&#xFF0C;&#x5C06;&#x4F20;&#x7ED9;&#x811A;&#x672C;&#x4E24;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;
#&#x4E00;&#x4E2A;&#x662F;&#x4E8B;&#x4EF6;&#x7684;&#x7C7B;&#x578B;&#xFF0C;
#&#x4E00;&#x4E2A;&#x662F;&#x4E8B;&#x4EF6;&#x7684;&#x63CF;&#x8FF0;&#x3002;
#&#x5982;&#x679C;sentinel.conf&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x4E2D;&#x914D;&#x7F6E;&#x4E86;&#x8FD9;&#x4E2A;&#x811A;&#x672C;&#x8DEF;&#x5F84;&#xFF0C;&#x90A3;&#x4E48;&#x5FC5;&#x987B;&#x4FDD;&#x8BC1;&#x8FD9;&#x4E2A;&#x811A;&#x672C;&#x5B58;&#x5728;&#x4E8E;&#x8FD9;&#x4E2A;&#x8DEF;&#x5F84;&#xFF0C;&#x5E76;&#x4E14;&#x662F;&#x53EF;&#x6267;&#x884C;&#x7684;&#xFF0C;&#x5426;&#x5219;sentinel&#x65E0;&#x6CD5;&#x6B63;&#x5E38;&#x542F;&#x52A8;&#x6210;&#x529F;&#x3002;
#&#x901A;&#x77E5;&#x811A;&#x672C;
sentinel notification-script <master-name> <script-path>
  sentinel notification-script mymaster /var/redis/notify.sh

&#x5BA2;&#x6237;&#x7AEF;&#x91CD;&#x65B0;&#x914D;&#x7F6E;&#x4E3B;&#x8282;&#x70B9;&#x53C2;&#x6570;&#x811A;&#x672C;
&#x5F53;&#x4E00;&#x4E2A;master&#x7531;&#x4E8E;failover&#x800C;&#x53D1;&#x751F;&#x6539;&#x53D8;&#x65F6;&#xFF0C;&#x8FD9;&#x4E2A;&#x811A;&#x672C;&#x5C06;&#x4F1A;&#x88AB;&#x8C03;&#x7528;&#xFF0C;&#x901A;&#x77E5;&#x76F8;&#x5173;&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#x5173;&#x4E8E;master&#x5730;&#x5740;&#x5DF2;&#x7ECF;&#x53D1;&#x751F;&#x6539;&#x53D8;&#x7684;&#x4FE1;&#x606F;&#x3002;
&#x4EE5;&#x4E0B;&#x53C2;&#x6570;&#x5C06;&#x4F1A;&#x5728;&#x8C03;&#x7528;&#x811A;&#x672C;&#x65F6;&#x4F20;&#x7ED9;&#x811A;&#x672C;:
<master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
&#x76EE;&#x524D;<state>&#x603B;&#x662F;&#x201C;failover&#x201D;,
<role>&#x662F;&#x201C;leader&#x201D;&#x6216;&#x8005;&#x201C;observer&#x201D;&#x4E2D;&#x7684;&#x4E00;&#x4E2A;&#x3002;
&#x53C2;&#x6570; from-ip, from-port, to-ip, to-port&#x662F;&#x7528;&#x6765;&#x548C;&#x65E7;&#x7684;master&#x548C;&#x65B0;&#x7684;master(&#x5373;&#x65E7;&#x7684;slave)&#x901A;&#x4FE1;&#x7684;
&#x8FD9;&#x4E2A;&#x811A;&#x672C;&#x5E94;&#x8BE5;&#x662F;&#x901A;&#x7528;&#x7684;&#xFF0C;&#x80FD;&#x88AB;&#x591A;&#x6B21;&#x8C03;&#x7528;&#xFF0C;&#x4E0D;&#x662F;&#x9488;&#x5BF9;&#x6027;&#x7684;&#x3002;
sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh</script-path></master-name></role></state></to-port></to-ip></from-port></from-ip></state></role></master-name></script-path></master-name></milliseconds></master-name></numslaves></master-name></milliseconds></master-name></password></master-name></quorum></redis-port></ip></master-name>

缓存穿透与雪崩

缓存穿透(查不到)

概念

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

解决方案

布隆过滤器

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

Redis学习

缓存空对象

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

Redis学习

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

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

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

概念

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

比如热搜排行上,一个热点新闻被同时大量访问就可能导致缓存击穿。

解决方案

  1. 设置热点数据永不过期 这样就不会出现热点数据过期的情况,但是当Redis内存空间满的时候也会清理部分数据,而且此种方案会占用空间,一旦热点数据多了起来,就会占用部分空间。
  2. 加互斥锁(分布式锁) 在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。保证同时刻只有一个线程访问。这样对锁的要求就十分高。

缓存雪崩

概念

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

Redis学习

解决方案

  • redis高可用 这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群
  • 限流降级 这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  • 数据预热 数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

缓存一致性

先更新数据库,在更新缓存,先更新缓存,再更新数据库都会有问题

一般使用 先更新数据库再删除缓存可以解决,因为缓存的写入要快于数据库的写入,但是会影响缓存的命中率,

那么缓存删除失败怎么办?

  1. 先删除缓存,再更新数据库
  2. 此时就引入了延时双删:
&#x5220;&#x9664;&#x7F13;&#x5B58;
&#x66F4;&#x65B0;&#x6570;&#x636E;&#x5E93;
&#x7761;&#x7720; &#x9700;&#x8981;&#x5927;&#x4E8E;&#x7B2C;&#x4E8C;&#x4E2A;&#x7EBF;&#x7A0B;&#x8BFB;&#x53D6;&#x6570;&#x636E;&#x5E76;&#x5199;&#x5165;&#x7F13;&#x5B58;&#x7684;&#x65F6;&#x95F4;
&#x5220;&#x9664;&#x7F13;&#x5B58;

睡眠时间难以估算,所以还是先更新数据库再删除缓存比较好

那么为什么不是更新缓存而是删除缓存呢,就是一个 lazy 计算的思想,不要每次都重新做复杂的计算,不管它会不会用到,而是让它到需要被使用的时候再重新计算

Redis 过期策略

定期删除+惰性删除

如果还有大量的过期数据既没有被用到过,又没有被定期删除扫描到那怎么办,就引入 淘汰策略

淘汰策略

  • noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。
  • allkeys-lru:当内存不足以容纳新写入数据时,在 键空间中,移除最近最少使用的 key(这个是 最常用的)。
  • allkeys-random:当内存不足以容纳新写入数据时,在 键空间中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。
  • volatile-lru:当内存不足以容纳新写入数据时,在 设置了过期时间的键空间中,移除最近最少使用的 key(这个一般不太合适)。
  • volatile-random:当内存不足以容纳新写入数据时,在 设置了过期时间的键空间中, 随机移除某个 key。
  • volatile-ttl:当内存不足以容纳新写入数据时,在 设置了过期时间的键空间中,有 更早过期时间的 key 优先移除。

Original: https://www.cnblogs.com/zz01/p/16489834.html
Author: 山野村夫01
Title: Redis学习

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/621426/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 【黄啊码】MySQL入门—2、使用数据定义语言(DDL)操作数据库

    大家好!我是黄啊码,上一节的知识点你了解多少了,掌握了多少了,别偷懒哦,今天我们就来掌握一下数据定义语言,说得高级点就是Data Definition Language,简称DDL…

    数据库 2023年6月16日
    087
  • likeshop搭建商城系统,一步到位

    什么是商城系统?商城系统又称在线商城系统,是一个功能完善的在线购物系统,主要为在线销售和在线购物服务。 一般的商城系统运营模式有B2C单商户商城系统,B2B2C多商户商城系统以及S…

    数据库 2023年6月14日
    0138
  • java 网络考试 在线教育系统 模块设计方案

    组建试卷:创建试卷,题目、类型、总分、及格分数、时长、出成绩方式、重复考试、公布答案、考试对象等 试卷题型:试卷明细,给试卷添加题型,分值,随机或者手动从题库选择试题,预览试题,自…

    数据库 2023年6月6日
    088
  • mysql杂记漫谈

    Hello,大家好,这几天消失了一下,主要是线上系统出了点小bug和sql性能问题,在努力搬砖,就把之前的设计模式系列放了一下下,正好趁这个复习巩固了一下sql执行计划和sql优化…

    数据库 2023年6月14日
    067
  • Vue3新特性API

    一、vue3介绍 vue3.0是在2.0的基础上重大优化调整后的升级版本,其响应式原理已经在vue2框架基础中介绍过,此文章重点介绍Vue 3 中一些新功能API及其使用,文章内容…

    数据库 2023年6月14日
    081
  • MyBatis详解

    😀搭建 MyBatis mysql mysql-connector-java 8.0.29 org.mybatis mybatis 3.5.7 junit junit 4.12 t…

    数据库 2023年6月14日
    067
  • springboot使用Redis,监听Redis键过期的事件设置与使用代码

    我使用的是Windows下的Redis服务,所以一下Redis设置都是在Windows平台进行。 1、修改Redis配置文件 1.1:Windows下的Redis存在两个配置文件 …

    数据库 2023年6月16日
    074
  • AQS源码探究之竞争锁资源

    AQS源码探究—竞争锁资源 我们进入ReentrantLock源码中查看其内部类 Sync 对AQS进行扩展公共方法并定义抽象方法的抽象类 FaireSync 实现公平…

    数据库 2023年6月11日
    074
  • SQL的多表查询

    显示内连接: select 字段列表 from 表1 [inner] join 表2 on 连接条件; (PS:方括号(“[]”)内的为可选项;) (注意:…

    数据库 2023年6月16日
    097
  • MySQL 中如何定位 DDL 被阻塞的问题

    经常碰到开发、测试童鞋会问,线下开发、测试环境,执行了一个DDL,发现很久都没有执行完,是不是被阻塞了?要怎么解决? 包括在群里,也经常会碰到类似问题:DDL 被阻塞了,如何找到阻…

    数据库 2023年5月24日
    052
  • MySQL Operator 02 | 脚手架选型 & 工程创建

    高日耀 资深数据库内核研发毕业于华中科技大学,喜欢研究主流数据库架构和源码,并长期从事分布式数据库内核研发。曾参与分布式 MPP 数据库 CirroData 内核开发(东方国信),…

    数据库 2023年5月24日
    094
  • Java并发编程之CAS

    在Java并发编程的世界里,synchronized 和 Lock 是控制多线程并发环境下对共享资源同步访问的两大手段。其中 Lock 是 JDK 层面的锁机制,是轻量级锁,底层使…

    数据库 2023年6月11日
    066
  • 西数数码-安装hmx_linux下的环境记录

    [nginx]name=nginx repobaseurl=http://nginx.org/packages/centos/6/x86_64/gpgcheck=0enabled=…

    数据库 2023年6月14日
    045
  • 0812Java核心技术卷(1)随笔

    自增运算符与自减运算符 这些运算符改变了变量的值,所以它的操作数不能是数值。例如4++就是一条非法语句不建议在其他表达式内部使用++,因为这样会降低代码可读性,产生bug Orig…

    数据库 2023年6月14日
    089
  • 695.岛屿的最大面积

    695.岛屿的最大面积 给你一个大小为 m x n 的二进制矩阵 grid 。 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直…

    数据库 2023年6月16日
    067
  • MySQL 批量修改库、表、列的排序规则

    1.表字段修复 SELECT TABLE_SCHEMA ‘数据库’, TABLE_NAME ‘表’, COLUMN_NAME ‘字段’, CHARACTER_SET_NAME ‘原…

    数据库 2023年6月14日
    088
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球