Redis.conf详解

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 1) The server is not binding explicitly to a set of addresses using the
#    "bind" directive.
# 2) No password is configured.
#
# The server only accepts connections from clients connecting from the
# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain
# sockets.
#
# By default protected mode is enabled. You should disable it only if
# you are sure you want clients from other hosts to connect to Redis
# even if no authentication is configured, nor a specific set of interfaces
# are explicitly listed using the "bind" directive.
# protected-mode yes
protected-mode no
# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 配置文件中, 一些配置项说明

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

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

# 日志
# Specify the server verbosity level.
# This can be one of:
# 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 /var/log/redis/redis-server.log  # 日志文件位置名

# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
always-show-logo yes  # 是否总是显示logo

快照

持久化, 在规定的时间内,执行了多少次的操作,则会持久化到文件.rdb, .aof, redis是内存数据库, 如果没有持久化,那么数据是断电即失的;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 如果900s内, 如果至少有一个1 key进行了修改, 我们即进行持久化操作;
save 900 1
# 如果300s内, 如果至少有一个10 key进行了修改, 我们即进行持久化操作;
save 300 10
# 如果60s内, 如果至少有一个10000 key进行了修改, 我们即进行持久化操作;
save 60 10000

# 之后持久化,可以自己定义;
stop-writes-on-bgsave-error yes  # 如果持久化出错,是否还需要继续工作

rdbcompression yes # 是否压缩rdb文件,需要消耗一些cpu资源
rdbchecksum yes  # 保存rdb文件的时候,进行错误的检查校验
dir ./  # rdb 文件保存的目录

Replication 复制

Security

1
2
3
4
5
config set reqiurepass

config get reqiurepass

auth 123456

限制Clients

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

# 移除一些过期的key
# 报错

​ 当实际内存超出 maxmemory 时,Redis 提供了几种可选策略 (maxmemory-policy) 来让用户自己决定该如何腾出新的空间以继续提供读写服务。

  • noeviction 不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。

  • volatile-lru 尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。

  • volatile-ttl 跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。

  • volatile-random 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。

  • allkeys-lru 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。

  • allkeys-random 跟上面一样,不过淘汰的策略是随机的 key

Append Only模式 aof配置

1
2
3
4
5
6
appendonly no  # 默认是不开启aof模式, 默认是使用rdb方式持久化的,在大部分的情况下,rdb够用
appendfilename "appendonly.aof" # 持久化的文件的名字   .rdb

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

Redis持久化

面试和工作, 持久化是重点;

Redis是内存数据库, 如果不将内存中的数据库状态保存到磁盘, 那么一旦服务器进程退出, 服务器中的数据库状态也会消失,所以redis提供了持久化的功能。

指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话Snapshot。它恢复时是将快照文件直接读到内存中。

Redis会单独创建一个fork子进程来进行持久化,先将数据写入一个临时文件,持久化结束后,用这个临时文件替代上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。

如果需要进行大规模的数据恢复,且对于数据恢复的完整性不是特别敏感,那么RDB方式比AOF更加高效。RDB的缺点就是最后一次持久化的数据可能会丢失。

默认的就是RDB, 一般情况下不需要修改这个配置;

有时候在生产环境,会将rdb文件备份;

==rdb保存的文件默认是 dump.rdb== 是在配置文件里面配置的;

在主从复制中,rdb就是备用的,放在从机上面.

RDB触发持久化保存机制:

  1. save命令规则。可以在redis.conf中设置save规则,满足时会自动触发RDB。
  2. 执行flushall命令。
  3. 退出redis。

RDB恢复:只要把dump.rdb文件放在redis启动目录(/usr/local/bin)即可,redis启动时会自动检查dump.rdb中的数据。(启动就会自动恢复其中的数据)

  • 优点:

    适合大规模。因为fork了一个子进程,效率很高。 对数据完整性不高。因为最后一次持久化数据可能会丢失

  • 缺点:

    占用内存(fork进程的时候,会占用一定的内存空间)。子进程需要占用额外内存。 需要时间间隔进行操作,数据会丢失(如果redis意外宕机了,这个最后一次修改的数据就没有了)。

AOF : Append Only File

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

工作原理:把所有命令全部记录在文件中,恢复时把所有命令再执行一遍。 工作过程:fork子进程以日志形式记录所有写操作(读操作不记录),只允许在之前的基础上追加文件,也是 append only file 的由来。 默认不开启,需要手动修改配置文件开启(将appendonly改为 yes),两个都开启的方式下,优先使用AOF。 AOF保存的持久化文件是appendonly.aof,如果这个文件被破坏修改,是启动不起来的,可以使用redis-check-aof –fix appendonly.aof进行修复。 AOF是文件的无限追加,所以有一个重写机制来保证aof文件不会过大,默认64m时进行重写。

优点:可以每次修改都进行同步,安全性更高,但实际使用是每秒同步一次。

缺点:恢复速度慢,aof文件所占内存会很大。

AOF保存的文件是appendonly.aof文件

redis-check-aof –fix aof文件:用来修复这个aof文件

Redis发布订阅

通信 队列 发送者 接收者

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

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

完成发布订阅需要消息发布者、频道、消息接受者; 频道一般用消息队列来实现。

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

订阅者

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
127.0.0.1:6379> subscribe kuangshenshuo 
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "kuangshenshuo"
3) (integer) 1
1) "message"
2) "kuangshenshuo"
3) "hello,kuangshen"
1) "message"
2) "kuangshenshuo"
3) "hello,redis"

发送端

1
2
3
4
5
6
7
8
bomir@morn:~$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> publish kuangshenshuo "hello,kuangshen"
(integer) 1
127.0.0.1:6379> publish kuangshenshuo "hello,redis"
(integer) 1
127.0.0.1:6379> 

Redis是使用C实现的,通过分析Redis源码里面的pubsub.c文件,即可了解发布和订阅机制的底层实现。

Redis是通过PUBLISH、SUBSCRIBE、PSUBCRIBE等命令实现发布和订阅功能

通过SUBSCRTIBE命令订阅某个频道后,redis-server里维护了一个字典,字典的键就是频道,而字典的值就是一个链表,这个链表保存了所有订阅这个频道的客户端。SUBCRIBE命令的关键,就是将客户端添加到给定频道的订阅链表中。

用过PUBLISH命令向订阅者发布消息,redis-server会使用给定的频道作为键,在它所维护的频道子弟班中查找订阅了这个频道的所有客户端链表,遍历这个链表,将消息发布给所有订阅者。

使用场景

  • 实时消息系统
  • 实时聊天(频道当做聊天室,将信息回显给所有人即可)
  • 订阅、关注系统

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

Redis主从复制

主从复制,就是指一台redis服务器上的数据复制到其他的redis服务器上。前者称为主节点(master/leader),后者称为从节点(slave/follower)。数据的复制是单向的,只能由主节点到从节点。主节点写从节点读

主从复制, 读写分离;80%情况下都是在进行读操作,减缓服务器的压力,架构中经常使用, 一主二从;

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

主从复制的作用:

数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式; 故障恢复:主节点出现问题后,可以由从节点提供服务,实现快速的故障恢复。实际上是一种服务冗余; 负载均衡:主从复制中,配合读写分离,可以由主节点提供写服务,从节点提供读服务,分担服务器负载,可以大大提高redis服务器的并发量; 高可用(集群)基石:主从复制还是哨兵和集群能够实施的基础;

一般来说,将Redis运用于工程项目,只使用一台redis是万万不能的(会宕机),原因如下:

从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大; 从容量上,单个redis服务器容量有限,一般来说,单台redis的最大使用内存不应该超过20G;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# info

# Replication
role:master
connected_slaves:0
master_replid:9514b713962669e9679d1de62c2ef2fd56d1d19b
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
  • 配置配置文件

    先拷贝三份,

    cp redis.conf redis79.conf

    cp redis.conf redis80.conf

    cp redis.conf redis81.conf

  • 修改配置文件(三个配置文件都要改(79、80、81)

    1:修改端口

    2:开启守护线程模式

    3:修改pidfile

    4:修改logfile

    5:修改dbfilename

  • 修改完毕之后,启动三个redis服务器,可以通过进程信息进行查看

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

  • 从机认证主机

    一主二从

    SLAVEOF host port #配置从机

    然后主机上也能看到从机的状态:

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

使用规则

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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    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"
    
  2. 当主机断电宕机后,默认情况下从机的角色不会发生变化 ,集群中只是失去了写操作,当主机恢复以后,又会连接上从机恢复原状。

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

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

    • 从机手动执行命令slaveof no one,这样执行以后从机会独立出来成为一个主机
    • 使用哨兵模式(自动选举)

复制原理

Slave启动成功连接到master后会发送一个sync同步命令

Master接收到命令后,启动后台的存盘进程,同时手机所有接收到的用于修改数据集命令,后台进程执行完毕之后,==master将传送整个数据文件到slave,并完成一次完全同步==

==全量复制==:slave获取到master的所有数据

==增量复制==:master新增的修改命令传给slave

只要是重新连接master,一次完全同步(全量复制)将被自动执行, 我们的数据一定可以在从机上看到;

如果没有老大了,这个时候能不能选择出来一个老大呢?手动!

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

哨兵模式

自动选取老大

==面试工作重点==

概述:

主从切换技术的方法是:当主服务器宕机后,需要手动把一台服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis从2.8开始正式提供Sentinel(哨兵)架构来解决这个问题。

能够监控主机是否故障,如果故障了==根据投票数自动将从库转化为主库==;

哨兵模式是一种特殊的模式,首先redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。原理是:哨兵通过发送命令,等待redis服务器响应,从而监控多个redis示例。

​ 多哨兵

​ 一个哨兵可以对多台服务器进行监控,并且可以有多个哨兵,每个哨兵会定时发送PING命令给服务器,并且还要在一定时间内得到服务器的响应,得到响应之后哨兵模式才会判定你现在状态正常。如果在规定的时间内它发送的请求主机没有得到响应,那么哨兵便会初步判断,当前主机是==主观下线==,其余的哨兵发现这台主机没有在规定时间内响应数据,那么便会以每秒一次的频率对主机进行判断,它确实是主观下线了,那么主机就会被标记为==客观下线==,主机挂掉之后,哨兵便会通过投票的方式在挂掉的主机下的从机中选出一个作为新主机。

哨兵的核心配置

sentinel monitor mymaster 127.0.0.1 6379 1

数字1表示 :当一个哨兵主观认为主机断开,就可以客观认为主机故障,然后开始选举新的主机。

成功启动哨兵模式

此时哨兵监视着我们的主机6379,当我们断开主机后:

就算此时原来的Master回来了,在6380面前也只能作为从机;

  • 优点:

    1、哨兵集群是基于主从复制来实现的,主从复制的优点全部具备;

    2、主从可以切换,故障可以转移,提升系统可用性;

    3、哨兵模式就是主从模式的升级,谋权篡位的手动到自动,更加健壮;

  • 缺点:

    1、在线扩容比较麻烦,集群的数量达到上限,就会变得十分繁琐;

    2、实现哨兵模式的配置较为麻烦,如果出现故障,还会涉及到一些shell脚本的运行,这些都是非常麻烦的操作;

关于哨兵模式的全部配置,可以看看这篇博客:

https://blog.csdn.net/u012441222/article/details/80751390

Redis缓存穿透和雪崩

==面试高频, 工作中常用;==

对于Redis缓存来说,使用Redis的缓存,它提升了应用程序的性能和效率,并且缓存在高并发场景中起到了非常重要的作用,如果针对数据的一致性来说,Redis的缓存就是一个非常致命的问题,这种问题有三个。

缓存穿透

查不到

在大多数场景中,数据库里的id字段一般来说都是自增。如果说,用户发送了一个请求,会首先进入缓存,查不到,就进入数据库,进了数据库,也查不到,查不到的话,如果说访问量较少,那还好,直接返回不存在嘛,因为这种少量的缓存穿透实际上是不可避免的,但是,一旦有一些不怀好意的坏蛋,在发送请求查询数据库的时候,主键的id字段故意给你来一个负数或者是一些远大于数据库最大id的数,而且进行巨大量的并发访问,这时候缓存中肯定是没有的,那这些请求就直接压给数据库了,数据库扛不住这么大的东西呀,那咋办,不解决数据库就只能挂掉呀。对此,有三种解决方案

1、在进行项目的整合时需要使用到API接口层,在接口层中定义自己的规则,对于不合法的参数可以直接返回,对于调用此接口的API的对象进行严查,任何可能发生的情况都要考虑到

2、在缓存中设置一个空对象,使用空对象完成后续请求;

3.使用一个东西,叫做布隆过滤器(Bloom Filter),布隆过滤器使用的是一个bit数组和一个hash算法实现的数据结构,并且内存的使用率极低。使用布隆过滤器可以快速判断当前key是否存在,和Java的Optional类有点相似,布隆过滤器告诉你这个key不存在,那么它就一定不存在;

布隆过滤器

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

缓存空对象

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

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

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

缓存击穿

量太大,缓存过期

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

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

解决方案

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

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

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

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

缓存雪崩

缓存雪崩指的是,在同一个时间内,一大批的缓存,集体失效,就好像没有被缓存过一样,这个时候假设说有双十一双十二的这种秒杀活动,恰好在这个时刻缓存是成批成批的失效,那么缓存失效,这些请求也还是直接压上数据库的,如果服务器在没有加锁的情况下,这种流量几乎是瞬间达到一个峰值的,对于一个服务器来说,也是会出现宕机的情况;

其实缓存集中过期不是非常致命,而是缓存服务器某个节点宕机或者断网才是致命的,很有可能瞬间就把数据库压垮;

解决方案

1、搭建Redis集群,在高可用的情况下,配置多台服务器,在服务器中保存同样的数据,这样即使是集群中的一台甚至是多台挂掉的情况下,也依旧能够正常工作;

2、如果不搭建集群,也可以这么做:项目启动时,将数据库和Redis进行数据同步,将数据库中部分的数据信息首先加载进入Redis缓存,并且在加载进入缓存时,可以将这些缓存数据的存活时间设置为随机,并且在数据库和Redis缓存需要在一定的时间之内进行同步更新;

总结起来就是:

  • redis高可用

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

  • 限流降级

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

  • 数据预热

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

参考博客

https://blog.csdn.net/DDDDeng_/article/details/108118544

https://www.cnblogs.com/yitudake/p/6747995.html

https://www.cnblogs.com/ysocean/p/9114268.html