Java Web数据库篇之Redis特性

Java Web系列文章汇总贴: Java Web知识总结汇总


Redis持久化机制

数据持久化方式

Redis支持两种数据持久化方式:RDB方式和AOF方式。前者会根据配置的规则定时将内存中的数据持久化到硬盘上,后者则是在每次执行写命令之后将命令记录下来。两种持久化方式可以单独使用,但是通常会将两者结合使用。

RDB方式

RDB方式的持久化是通过快照的方式完成的。当符合某种规则时,会将内存中的数据全量生成一份副本存储到硬盘上,这个过程称作”快照”,Redis会在以下几种情况下对数据进行快照:

根据配置规则进行自动快照;

  • 用户执行SAVE, BGSAVE命令;
  • 执行FLUSHALL命令;
  • 执行复制(replication)时。

快照生成原理:

快照执行的过程如下:

  • Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
  • 父进程继续处理来自客户端的请求,子进程开始将内存中的数据写入硬盘中的临时文件;
  • 当子进程写完所有的数据后,用该临时文件替换旧的RDB文件,至此,一次快照操作完成。

需要注意的是:
在执行fork的时候操作系统(类Unix操作系统)会使用写时复制(copy-on-write)策略,即fork函数发生的一刻,父进程和子进程共享同一块内存数据,当父进程需要修改其中的某片数据(如执行写命令)时,操作系统会将该片数据复制一份以保证子进程不受影响,所以RDB文件存储的是执行fork操作那一刻的内存数据。所以RDB方式理论上是会存在丢数据的情况的(fork之后修改的的那些没有写进RDB文件)。

AOF方式

在使用Redis存储非临时数据时,一般都需要打开AOF持久化来降低进程终止导致的数据丢失,AOF可以将Redis执行的每一条写命令追加到硬盘文件中,这一过程显然会降低Redis的性能,但是大部分情况下这个影响是可以接受的,另外,使用较快的硬盘能提高AOF的性能。

开启AOF

默认情况下,Redis没有开启AOF(append only file)持久化功能,可以通过在配置文件中作如下配置启用:

appendonly yes

开启之后,Redis每执行一条写命令就会将该命令写入硬盘中的AOF文件。AOF文件保存路径和RDB文件路径是一致的,都是通过dir参数配置,默认文件名是:appendonly.aof,可以通过配置appendonlyfilename参数修改,例如:

appendfilename “appendonly.aof”

AOF持久化的实现

AOF以纯文本的形式记录了Redis执行的写命令。

AOF文件重写(删除AOF中无用的命令)

AOF文件是可识别的纯文本,它的内容就是一个个的Redis标准命令,
AOF日志也不是完全按客户端的请求来生成日志的,比如命令 INCRBYFLOAT 在记AOF日志时就被记成一条SET记录,因为浮点数操作可能在不同的系统上会不同,所以为了避免同一份日志在不同的系统上生成不同的数据集,所以这里只将操作后的结果通过SET来记录。

每一条写命令都生成一条日志,AOF文件会很大。

AOF重写是重新生成一份AOF文件,新的AOF文件中一条记录的操作只会有一次,而不像一份老文件那样,可能记录了对同一个值的多次操作。其生成过程和RDB类似,也是fork一个进程,直接遍历数据,写入新的AOF临时文件。在写入新文件的过程中,所有的写操作日志还是会写到原来老的AOF文件中,同时还会记录在内存缓冲区中。当重完操作完成后,会将所有缓冲区中的日志一次性写入到临时文件中。然后调用原子性的rename命令用新的 AOF文件取代老的AOF文件。

 命令:BGREWRITEAOF

同步硬盘数据

虽然每次执行更改数据库的内容时,AOF都会记录执行的命令,但是由于操作系统本身的硬盘缓存的缘故,AOF文件的内容并没有真正地写入硬盘,在默认情况下,操作系统会每隔30s将硬盘缓存中的数据同步到硬盘,但是为了防止系统异常退出而导致丢数据的情况发生,我们还可以在Redis的配置文件中配置这个同步的频率:

# appendfsync always
appendfsync everysec
# appendfsync no
  • appendfsync always 表示每次AOF写入一个命令都会执行同步操作,这是最安全也是最慢的方式;
  • appendfsync everysec 表示每秒钟进行一次同步操作,一般来说使用这种方式已经足够;
  • appendfsync no 表示不主动进行同步操作,这是最不安全的方式。

选项:
1、appendfsync no

当设置appendfsync为no的时候,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。对大多数Linux操作系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上。

2、appendfsync everysec

当设置appendfsync为everysec的时候,Redis会默认每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。但是当这一次的fsync调用时长超过1秒时。Redis会采取延迟fsync的策略,再等一秒钟。也就是在两秒后再进行fsync,这一次的fsync就不管会执行多长时间都会进行。这时候由于在fsync时文件描述符会被阻塞,所以当前的写操作就会阻塞。所以,结论就是:在绝大多数情况下,Redis会每隔一秒进行一次fsync。在最坏的情况下,两秒钟会进行一次fsync操作。这一操作在大多数数据库系统中被称为group commit,就是组合多次写操作的数据,一次性将日志写到磁盘。

3、appednfsync always

当设置appendfsync为always时,每一次写操作都会调用一次fsync,这时数据是最安全的,当然,由于每次都会执行fsync,所以其性能也会受到影响。

建议采用 appendfsync everysec(缺省方式)

快照模式可以和AOF模式同时开启,互补影响。

RDB与AOF的区别

RDB

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
Java Web数据库篇之Redis特性_第1张图片

AOF

AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

RDB与AOF对比

RDB存在哪些优势呢?

  • 1). 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
  • 2). 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
  • 3). 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
  • 4). 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

RDB又存在哪些劣势呢?

  • 1). 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
  • 2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。

AOF的优势有哪些呢?

  • 1). 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
  • 2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
  • 3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
  • 4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。

AOF的劣势有哪些呢?

  • 1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

  • 2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。

    二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。

参考:
redis学习(九)——数据持久化
Redis实战和核心原理详解(9)RDB和AOF的优缺点对比以及如何选择

Redis AOF过大的问题

执行BGREWRITEAOF命令对redis的AOF进行重写,也可以启动一个定时脚本每天定时执行

参考:
解决redis aof文件过大的问题


手写一个LRU

继承linkedHashMap实现,构建指定最先访问的元素放到列表最后,覆写相关方法

class LRUCache extends LinkedHashMap {
    private final int CACHE_SIZE;
 
    /**
     * 传递进来最多能缓存多少数据
     *
     * @param cacheSize 缓存大小
     */
    public LRUCache(int cacheSize) {
        // true 表示让 linkedHashMap 按照访问顺序来进行排序,最近访问的放在头部,最老访问的放在尾部。
        super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
        CACHE_SIZE = cacheSize;
    }
 
    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        // 当 map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据。
        return size() > CACHE_SIZE;
    }
}

参考:
Redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现?
分享一个今日头条的面试题——LRU原理和Redis实现


Redis缓存数据库一致性

建议策略

读请求:先读缓存->无则读数据库->更新缓存
写请求:先删除缓存在更新数据库,还是先更新数据库,后删除缓存。为什么不是写完数据库后,更新缓存,请看下面的讨论。

两种方式各有优劣。但是都要解决两类问题:

  • 写请求和读请求并发,导致的缓存不一致问题(对于这个问题,如果并发量不是很大,可以使用分布式锁保证有序,但是这种方案可能因为操作都是串行,性能下降)
  • 写请求中,第一步成功,但是第二部失败了,导致的缓存不一致问题

先更新数据库,后删除缓存

先更新数据库,后删除缓存(写操作比读取慢,缓存不一致出现概率较低),解决这一问题,可以给缓存设置失效时间,或者延迟删除缓存,保证读请求发生之后再删除缓存,或者搞一个队列,把对同一条记录操作的读写请求放到同一个队列,当请求处理完毕后再删除缓存。

关于先更新数据库,后删除缓存,存在的另一大问题就是更新数据库成功,删除缓存失败了,导致缓存数据库不一致,可以

  • 把失败的消息发送到统一的消息处理系统,不断重试,直到成功。
  • 也可以使用单独的MQ模块订阅数据库如MySQL的binlog,根据binlog去清理对应的缓存。

具体参考:
分布式之数据库和缓存双写一致性方案解析


下面的讨论,倾向于先删除缓存,后更新数据库,因为这种方案,可以很方便的解决删除缓存成功,但是更新数据库失败的问题,因为这样不会导致缓存不一致,缓存只是被删除了,会在读请求时重新被更新。


写完数据库后是否需要马上更新缓存还是直接删除缓存

(1)、如果写数据库的值与更新到缓存值是一样的,不需要经过任何的计算,可以马上更新缓存,但是如果对于那种写数据频繁而读数据少的场景并不合适这种解决方案,因为也许还没有查询就被删除或修改了,这样会浪费时间和资源
(2)、如果写数据库的值与更新缓存的值不一致,写入缓存中的数据需要经过几个表的关联计算后得到的结果插入缓存中,那就没有必要马上更新缓存,只有删除缓存即可,等到查询的时候在去把计算后得到的结果插入到缓存中即可。
(3)、分布式锁保证有序
所以一般的策略是当更新数据时,先删除缓存数据,然后更新数据库,而不是更新缓存,等要查询的时候才把最新的数据更新到缓存

数据库与缓存双写情况下导致数据不一致问题

场景一

当更新数据时,如更新某商品的库存,当前商品的库存是100,现在要更新为99,先更新数据库更改成99,然后删除缓存,发现删除缓存失败了,这意味着数据库存的是99,而缓存是100,这导致数据库和缓存不一致。

场景一解决方案

这种情况应该是先删除缓存,然后在更新数据库,如果删除缓存失败,那就不要更新数据库,如果说删除缓存成功,而更新数据库失败,那查询的时候只是从数据库里查了旧的数据而已,这样就能保持数据库与缓存的一致性。

场景二

在高并发的情况下,如果当删除完缓存的时候,这时去更新数据库,但还没有更新完,另外一个请求来查询数据,发现缓存里没有,就去数据库里查,还是以上面商品库存为例,如果数据库中产品的库存是100,那么查询到的库存是100,然后插入缓存,插入完缓存后,原来那个更新数据库的线程把数据库更新为了99,导致数据库与缓存不一致的情况

场景二解决方案

遇到这种情况,可以用队列的去解决这个问题,创建几个队列,如20个,根据商品的ID去做hash值,然后对队列个数取摸,当有数据更新请求时,先把它丢到队列里去,当更新完后在从队列里去除,如果在更新的过程中,遇到以上场景,先去缓存里看下有没有数据,如果没有,可以先去队列里看是否有相同商品ID在做更新,如果有也把查询的请求发送到队列里去,然后同步等待缓存更新完成

这里有一个优化点,如果发现队列里有一个查询请求了,那么就不要放新的查询操作进去了,用一个while(true)循环去查询缓存,循环个200MS左右,如果缓存里还没有则直接取数据库的旧数据,一般情况下是可以取到的。
在高并发下解决场景二要注意的问题

  • (1)读请求时长阻塞
    由于读请求进行了非常轻度的异步化,所以一定要注意读超时的问题,每个读请求必须在超时间内返回,该解决方案最大的风险在于可能数据更新很频繁,导致队列中挤压了大量的更新操作在里面,然后读请求会发生大量的超时,最后导致大量的请求直接走数据库,像遇到这种情况,一般要做好足够的压力测试,如果压力过大,需要根据实际情况添加机器。
  • (2)请求并发量过高
    这里还是要做好压力测试,多模拟真实场景,并发量在最高的时候QPS多少,扛不住就要多加机器,还有就是做好读写比例是多少
  • (3)多服务实例部署的请求路由
    可能这个服务部署了多个实例,那么必须保证说,执行数据更新操作,以及执行缓存更新操作的请求,都通过nginx服务器路由到相同的服务实例上
  • (4)热点商品的路由问题,导致请求的倾斜
    某些商品的读请求特别高,全部打到了相同的机器的相同丢列里了,可能造成某台服务器压力过大,因为只有在商品数据更新的时候才会清空缓存,然后才会导致读写并发,所以更新频率不是太高的话,这个问题的影响并不是很大,但是确实有可能某些服务器的负载会高一些。

数据库与缓存数据一致性解决方案流程图


摘自:
Redis系列之数据库与缓存数据一致性解决方案
redis缓存与数据库一致性问题解决

综述

1、不一致产生的原因?

我们在是使用redis过程中,通常会这样做,先读取缓存,如果缓存不存在,则读取数据库。
不管是先写库,再删除缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。
因为写和读是并发的,没法保证顺序,如果删除了缓存,还没有来得及写库,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。
如果是redis集群,或者主从模式,写主读从,由于redis复制存在一定的时间延迟,也有可能导致数据不一致。

2、优化思路

(1)读操作优先读取redis,不存在的话就去访问MySql,并把读到的数据写回Redis中;
(2)写操作的话,直接写MySql,成功后再写入Redis,替换掉原来的旧数据(可以在MySql端定义CRUD触发器,在触发CRUD操作后写数据到Redis,也可以在Redis端解析binlog,再做相应的操作)
(3)设定合理的超时时间,即经过超时时间,自动将redis中相应的数据删除。这样最差的情况是在超时时间内,内存存在不一致。当然这种策略要考虑redis和数据库主从同步的耗时,所以在第二次删除前最好休眠一定的时间,比如500毫秒,这样无疑又增加了写请求的耗时。


缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题

缓存穿透

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

解决方案

有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

缓存雪崩

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。

解决方案

缓存失效时的雪崩效应对底层系统的冲击非常可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线 程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。这里分享一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

如果是黑客攻击,导致缓存雪崩,可采用策略如下:
事前 保证redis高可用 可恢复,使用本地缓存ehcache,限流及降级组件Hystrix
事后 进行恢复

缓存击穿

对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。

缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案

  • 使用互斥锁(mutex key)
  • 检查更新
  • 分级缓存

缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题
缓存穿透,缓存击穿,缓存雪崩解决方案分析
如何正确访问Redis中的海量数据?服务才不会挂掉
应对缓存击穿的解决方法
20万用户同时访问一个热点Key,如何优化缓存架构


Redis主从复制

概述

基本思想:读写分离 - 提高Redis的QPS,主从复制 - 保证高可用

Redis replication
主从架构-各节点使用持久化方案RDB/AOF保证高可用
读写分离
水平扩容支撑读高并发

原理:

  • 1、slave node发送PSYNC命令给master node
  • 2、如果slave node是第一次连接master node,会触发一次full resynchronization,master会启动一个后台线程,开始生成一份RDB快照文件,同时会将从客户端收到的命令缓存到内存中,RDB文件生成完毕后,master会将这个RDB发送给slave,slave先写入本地磁盘,然后从磁盘加载到内存中,然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据;
    如果不是第一次连接,master node仅赋值给slave缺少的数据即可。
  • 3、slave node如果因网络故障和master断开,会自动重连,master如果发现有多个slave都来重新连接,仅会启动一个rdb save操作,用一份数据服务所有slave

详细

Redis主从复制可以根据是否是全量分为全量同步和增量同步。

全量同步

Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:

  • 1)从服务器连接主服务器,发送SYNC命令;
  • 2)主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
  • 3)主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
  • 4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
  • 5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
  • 6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
    图示:
    Java Web数据库篇之Redis特性_第2张图片

增量同步

Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。

整体同步策略

Redis的同步策略是:主从刚刚连接的时候,进行全量同步;全量同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。


Redis哨兵机制

Redis哨兵简介

Redis-Sentinel也就是哨兵机制,是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。

它的主要功能有以下几点:

  • 不时地监控redis是否按照预期良好地运行;
  • 如果发现某个redis节点运行出现状况,能够通知另外一个进程(例如它的客户端);
  • 能够进行自动切换(进行主备切换)。当一个master节点不可用时,能够选举出master的多个slave(如果有超过一个slave的话)中的一个来作为新的master,其它的slave节点会将它所追随的master的地址改为被提升为master的slave的新地址。

Sentinel支持集群

很显然,只使用单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后(sentinel本身也有单点问题,single-point-of-failure)整个集群系统将无法按照预期的方式运行。所以有必要将sentinel集群,这样有几个好处:

  • 即使有一些sentinel进程宕掉了,依然可以进行redis集群的主备切换;
  • 如果只有一个sentinel进程,如果这个进程运行出错,或者是网络堵塞,那么将无法实现redis集群的主备切换(单点问题);
  • 如果有多个sentinel,redis的客户端可以随意地连接任意一个sentinel来获得关于redis集群中的信息。
  • 由于过半策略,一般部署3个哨兵,保证高可用

另一个相关的概念:脑裂问题
指的是一个系统中由于网络分区等原因,出现了两个master,需要关注此问题

哨兵机制的运行过程

Java Web数据库篇之Redis特性_第3张图片

如上图所示,Redis为了保证高可用性,采用Master-slave形式部署,采用AOF或RDB进行持久化,采用集群culster机制来分布式存储。多个哨兵,不仅同时监控主从数据库,而且哨兵之间互为监控,并且哨兵不会存在单点问题。哨兵会监控主从Redis服务器是否正常,当发现有问题时,会进行通知,并进行故障转移。当监控到master节点宕机后,会进行maser选举出新的master节点,并进行主从切换,并将其他节点作为新选举出的master节点的slave。哨兵Sentinel用到的分布式一致性算法是Raft分布式算法。

redis利用比较易于实现的raft协议实现了节点宕机的自动化处理,保障了集群的高可用性。Raft协议与paxos算法类似,但比paxos算法好理解,我们都知道,paxos算法是经典的分布式一致性算法,zookeeper的ZAB协议也是在其基础上设计的。ZAB,paxos,Raft都是采用过半策略。关于相关分布式算法,我会在后边的系列,Zookeeper系列进行介绍。对于Redis的监控过程,Leader选举,主备切换,数据同步等过程,跟Zookeeper类似,我们可以把zookeeper的实现方式与其进行类比

摘自:
Redis 原理及应用(3)–内存淘汰机制、主从同步原理,HA策略(哨兵机制)分析


Redis集群模式

一致性Hash

简单来说,一个物理节点与多个虚拟节点映射,在hash的时候,使用虚拟节点数目而不是物理节点数目。当物理节点变化的时候,虚拟节点的数目无需变化,只涉及到虚拟节点的重新分配。而且,调整每个物理节点对应的虚拟节点数目,也就相当于每个物理节点有不同的权重。
无虚拟节点:
Java Web数据库篇之Redis特性_第4张图片
加入虚拟节点,防止雪崩:
Java Web数据库篇之Redis特性_第5张图片

更多:
什么是一致性Hash算法

Redis集群

redis集群原理(哈希槽、主从复制等技术)

  • 设置redis服务器先经过CRC16哈希到一个指定的Node上范围是0-16384 (平均分配,不能重复也不能缺失,否则会导致对象重复存储或无法存储,比如:三台啊服务器:节点1分配0-5600,节点二分配应该书5601-12000,节点3,12001-16384).
  • 当数据要保存到redis时,通过CRC16哈希到一个指定RC16哈希值,保存在对应的节点上。
  • 获取,当要获取一个数据时,先通过key获取到RC16哈希值,再通过RC16哈希值找到对应的节点,然后就能在对应的节点马上找到kye的值了。

更多:
Redis集群方案及实现
Redis cluster集群:原理及搭建
三张图秒懂Redis集群设计原理
Redis详解之-集群方案:高性能(使用原生Redis Cluster)
Redis系列九:redis集群高可用
redis集群搭建


Redis应用场景

  • 缓存
  • 分布式消息队列
  • 分布式锁
  • 位操作(去重,统计在线人数等)
  • 排行榜
  • 共同关注

参考:
Redis 原理及应用(4)–Redis应用场景分析
分布式锁的几种使用方式(redis、zookeeper、数据库)
分布式锁简单入门以及三种实现方式介绍

你可能感兴趣的:(Java,Web知识总结)