目录
1、主从复制(读写分离)
1.1、什么是主从复制
1.2、主从复制的作用
1.3、环境搭建
1.4、一主二仆
1.5、注意事项
1.6、反客为主
1.7、哨兵模式(sentinel)
2、Redis集群
2.1、什么是集群
2.2、什么是redis集群
2.3、Redis集群中的哈希槽
2.4、Redis集群中节点的通信
2.5、如何判断某个节点挂掉
3、缓存穿透
3.1、缓存穿透概述
3.2、解决方案
4、缓存击穿
4.1、缓存击穿概述
4.2、解决方案
5、缓存雪崩
5.1、缓存雪崩概述
5.2、解决方案
主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库;主数据库一般是实时的业务数据库,从数据库的作用和使用场合一般有几个:一是作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作;二是可在从数据库作备份、数据统计等工作,这样不影响主数据库的性能。
做数据的热备,作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。
主服务器: 一般用作写操作。
从服务器: 一般用于读操作。
首先在把redis下的redis.conf配置文件copy一份到一个新的文件夹,这里我创建一个myredis文件夹
[root@localhost myredis]# cp /usr/local/redis/redis-6.2.6/redis.conf myredis/redis.conf
复制端口6379
[root@localhost myredis]# vim redis6379.conf
将下面代码编辑到该配置文件
include usr/local/redis/myredis/redis.conf
pidfile /var/run/redis_6379.conf
port 6379
dbfilename dump6379.rdb
复制端口6380
[root@localhost myredis]# vim redis6380.conf
将下面代码编辑到该配置文件
include usr/local/redis/myredis/redis.conf
pidfile /var/run/redis_6380.conf
port 6380
dbfilename dump6380.rdb
复制端口6381
[root@localhost myredis]# vim redis6381.conf
将下面代码编辑到该配置文件
include usr/local/redis/myredis/redis.conf
pidfile /var/run/redis_6381.conf
port 6381
dbfilename dump6381.rdb
启动各个端口的redis
[root@localhost myredis]# redis-server redis6379.conf
[root@localhost myredis]# redis-server redis6380.conf
[root@localhost myredis]# redis-server redis6381.conf
查看redis进程
[root@localhost myredis]# ps -ef | grep redis
root 5209 1 0 06:10 ? 00:00:01 redis-server 127.0.0.1:6380
root 5243 1 0 06:10 ? 00:00:01 redis-server 127.0.0.1:6381
root 5611 1 0 06:24 ? 00:00:00 redis-server 127.0.0.1:6379
root 5620 3992 0 06:24 pts/0 00:00:00 grep --color=auto redis
分别打开三个窗口连接三个服务器
redis-cli -p 6379
redis-cli -p 6380
redis-cli -p 6381
这里把6379当作主服务器,把6380、6381当作为从服务器,那么6380、6381就要通过命令去绑定主服务器,在6380、6381服务器分别输入以下命令,将6379服务器当作主服务器。
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK127.0.0.1:6381> slaveof 127.0.0.1 6379
OK
-- 测试主服务器 写 操作
127.0.0.1:6379> set a 1
OK
-- 从服务器 读 操作
127.0.0.1:6380> get a
"1"
127.0.0.1:6381> get a
"1"
1、当其中的一个从服务器 shutdown 挂掉了,从服务器再次启动还会不会重新连接到主服务器中?
不会,会自动变成主服务器。
2、如果把挂掉的从服务器重新连到主服务器后,主服务器的数据还会不会复制过来?
会。
3、当主服务器挂掉后,从服务器不会做任何事情,查看从服务器 info replication服务器情况,还认主服务器只是状态挂掉了,再次重启主服务器,又回到主服务位置。
将主服务器挂掉
-- 主服务器挂掉 --
127.0.0.1:6379> shutdown
把从服务器上位为主服务器
-- 把从服务器上位为主服务器 --
127.0.0.1:6380> slaveof no one
OK
-- 6381从服务器挂上6380服务器 --
127.0.0.1:6381> slaveof 127.0.0.1 6380
OK
是一种容灾方案。以上主服务器挂了,虽然从服务器变成了主服务器,但是有一个问题,是手动变成服务器
哨兵:实则是一个在特殊模式下的Redis服务器,里面存储的是自己本身的信息,主服务器的信息,从服务器的信息。
用一个或者多个哨兵来监视主服务器(也就是进行写操作的服务器)是否在正常执行任务,一旦哨兵发现主服务器不可用时,就找到一个合适的从服务器成为主服务器。
恢复到6379位主服务器,6380、6381位从服务器的状态
在当前myredis目录下创建 sentinel.conf 文件,名字不要写错,配置如下
sentinel monitor mymaster 127.0.0.1 6379 1
mymaster为监控对象起的服务器名字 ,1 只要有一个哨兵认为master宕机就可以切换,同时会选举1个哨兵进行迁移的数据
启动哨兵模式
[root@localhost myredis]# redis-sentinel sentinel.conf
把主服务器6379服务器 shutdown , 查看哨并是否会自动把从服务器变成主服务器
-- 主服务器 shutdown 宕机 --
127.0.0.1:6379> SHUTDOWN-- 只剩下6380和6381--
[root@localhost myredis]# ps -ef|grep redis
root 5209 1 0 06:10 ? 00:00:10 redis-server 127.0.0.1:6380
root 5243 1 0 06:10 ? 00:00:10 redis-server 127.0.0.1:6381
yanqi 6597 5400 0 07:36 pts/2 00:00:00 redis-cli -p 6380
yanqi 6598 5327 0 07:36 pts/1 00:00:00 redis-cli -p 6381
root 7279 7080 0 08:07 pts/3 00:00:00 redis-sentinel *:26379 [sentinel]
root 7333 3992 0 08:10 pts/0 00:00:00 grep --color=auto redis
此时哨兵会检测到主服务器宕机,会再选择一个从服务器上位主服务器
如果说主从复制是各司其职的话,那么集群就是一群同样的个体做着同样的事情。在Redis中,数据的写入操作次数很大的情况下,只使用单独一个服务器来进行写入操作的话,效率不高,那么如果使用集群方案,利用多个Redis服务器来进行写操作,大量的数据,你写一点,我写一点,大家都分担一点,那么效率会高很多。就像工地上搬砖,一个人搬肯定效率非常慢,但是叫来十几个人一起搬,用不了多少时间就会被搬空,人越多效率越高,也就是说我们数据容量大大提升了!
集群模式的思想可以在多处使用。总之就是,一个个体完成不了或者说效率很低的场景下,都可以使用这种思想。
Redis-Cluster的概念 Redis-Cluster采用无中心结构,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。
数据分散存储 Redis 集群并没有使用传统的一致性哈希来分配数据,而是采用另外一种叫做 哈希槽(hash slot) 的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。
Redis 是在内存中保存数据的,而我们的电脑一般内存都不大, 这也就意味着 Redis 不适合存储大数据,适合存储大数据的是 Hadoop 生态系统的 Hbase 或 者是 MogoDB。Redis 更适合处理高并发,一台设备的存储能力是很有限的,但是多台设备 协同合作,就可以让内存增大很多倍,这就需要用到集群。
Redis 集群搭建的方式有多种,例如使用客户端分片、Twitter开发的Twemproxy、豌豆荚开发的Codis 等,但从 redis 3.0 之后版本支持 redis-cluster 集群,它是 Redis 官方提出的解决方案, Redis-Cluster 采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所 有节点连接。
Redis集群中引入了哈希槽的概念,Redis集群有16384个哈希槽,进行set操作时,每个key会通过CRC16校验后再对16384取模来决定放置在哪个槽,搭建Redis集群时会先给集群中每个master节点分配一部分哈希槽。 比如当前集群有3个master节点,
master1节点包含0~5500号哈希槽, master2节点包含5501~11000号哈希槽, master3节点包含11001~16384号哈希槽,
当我们执行“set key value”时,假如 CRC16(key) % 16384 = 777,那么这个key就会被分配到master1节点上,如下图
既然Redis集群中的数据是通过哈希槽的方式分开存储的,那么集群中每个节点都需要知道其他所有节点的状态信息,包括当前集群状态、集群中各节点负责的哈希槽、集群中各节点的master-slave状态、集群中各节点的存活状态等。Redis集群中,节点之间通过建立TCP连接,使用gossip协议来传播集群的信息。如下图:
首先要说的是,每一个节点都存有这个集群所有主节点以及从节点的信息。它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点。
缓存穿透是指缓存和数据库中都没有的数据,这样每次请求都会去查库,不会查缓存,如果同一时间有大量(高并发)请求进来的话,就会给数据库造成巨大的查询压力,甚至击垮数据库。
1、对空值缓存:如果一个查询返回的数据为空,不管数据是否存在,我们仍然把这个空值作缓存,设置空值的过期时间很短。
2、设置访问的白名单:使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps偏移的量,每次访问和bitmaps有id进行对比,如果不存在就拦截,不允许访问
3、布隆过滤器:布隆过滤器底层使用bit数组存储数据,该数组中的元素默认值是0。布隆过滤器第一次初始化的时候,会把数据库中所有已存在的key,经过一些列的hash算法(比如:三次hash算法)计算,每个key都会计算出多个位置,然后把这些位置上的元素值设置成1。 之后,有用户key请求过来的时候,再用相同的hash算法计算位置。
如果多个位置中的元素值都是1,则说明该key在数据库中已存在。这时允许继续往后面操作。
如果有1个以上的位置上的元素值是0,则说明该key在数据库中不存在。这时可以拒绝该请求,而直接返回。
其实,布隆过滤器最致命的问题是:如果数据库中的数据更新了,需要同步更新布隆过滤器。但它跟数据库是两个数据源,就可能存在数据不一致的情况。
比如:数据库中新增了一个用户,该用户数据需要实时同步到布隆过滤。但由于网络异常,同步失败了。
这时刚好该用户请求过来了,由于布隆过滤器没有该key的数据,所以直接拒绝了该请求。但这个是正常的用户,也被拦截了。
很显然,如果出现了这种正常用户被拦截了情况,有些业务是无法容忍的。所以,布隆过滤器要看实际业务场景再决定是否使用,它帮我们解决了缓存穿透问题,但同时了带来了新的问题。
有时候,我们在访问热点数据时。比如:我们在某个商城购买某个热门商品。 为了保证访问速度,通常情况下,商城系统会把商品信息放到缓存中。但如果某个时刻,该商品到了过期时间失效了。 此时,如果有大量的用户请求同一个商品,但该商品在缓存中失效了,一下子这些用户请求都直接到了数据库,可能会造成瞬间数据库压力过大,而直接挂掉。
1、设置热点数据永不过期。(也是一种解决方式,但是实际过程中不推荐)
2、加锁的方式:锁的对象就是key,这样,当大量查询同一个key的请求并发进来时,只能有一个请求获取到锁,然后获取到锁的线程查询数据库,然后将结果放入到缓存中,然后释放锁,此时,其他处于锁等待的请求即可继续执行,由于此时缓存中已经有了数据,所以直接从缓存中获取到数据返回,并不会查询数据库。也就是加锁让一个人去查询数据并把数据存储到缓存中,其他人再查询的时候就直接从缓存中获取了。
缓存雪崩是指当缓存中有大量的key在同一时刻过期,或者Redis直接宕机了,导致大量的查询请求全部到达数据库,造成数据库查询压力骤增,甚至直接挂掉。
给不同的key的TTL添加随机值,避免大量的key同时到期
利用Redis集群提高服务的可用性,避免Redis服务宕机后的数据丢失和请求直达数据库
给缓存业务添加降级限流策略
给业务添加多级缓存