本篇博文主要包含:

  • OsCache与EhCache区别
  • JVM缓存的缺点
  • NoSQL介绍
  • Redis简介
  • Redis应用场景
  • Redis优势
  • Redis主从复制(部署一主多备实例)
  • Redis哨兵机制(含实例)
  • Redis持久化
    -RDB持久化
    -AOF持久化
    -AOF与RDB区别
  • Redis发布订阅

一、概述

  1. Java缓存机制
    Java中要用到缓存的地方很多,首当其冲的就是持久层缓存,针对持久层谈一下:
    要实现java缓存有很多种方式,最简单的无非就是static HashMap,这个显然是基于内存缓存,一个map就可以搞定引用对象的缓存,最简单也最不实用,首要的问题就是保存对象的有效性以及周期无法控制,这样很容易就导致内存急剧上升,周期无法控制可以采用SoftReference,WeakReference,PhantomReference这三种对象来执行,这三种都是弱引用,区别在于强度不同,至于弱引用概念个人理解就是对象的生命周期与JVM挂钩,JVM内存不够了就回收,这样能很好的控制OutOfMemoryError 异常。 常用的有Oscache,Ehcache,Jcache,Jbosscache等等很多。
  2. OsCache与EhCache区别
  • ehcache 主要是对数据库访问的缓存,相同的查询语句只需查询一次数据库,从而提高了查询的速度,使用spring的AOP可以很容易实现这一功能。hibernate二级缓存(二级缓存是在SessionFactory,所有的Session共享同一个二级Cache)机制采用的就是ehcache。
  • oscache 主要是对页面的缓存,可以整页或者指定网页某一部分缓存,同时指定他的过期时间,这样在此时间段里面访问的数据都是一样的。mybatis二级缓(mapper级别的缓存,多个sqlSession可以共享一个mapper中的二级缓存区域)存机制采用的就是oscache。
  1. JVM缓存的缺点
    1)内存容易溢出
    2)没有持久化
    3)线程不安全
    4)多服务器数据库不能共享
  2. NoSQL介绍
    NoSQL 是 Not Only SQL 的缩写,意即"不仅仅是SQL"的意思,泛指非关系型的数据库(存储在内容中而不是java内置缓存中)强调Key-Value Stores和文档数据库的优点,而不是单纯的反对RDBMS
    NoSQL产品是传统关系型数据库的功能阉割版本,通过减少用不到或很少用的功能,来大幅度提高产品性能。
    NoSQL产品 Redis(存储key-value形式)、mongodb(存储json格式)、Membase、HBase 。
  3. Redis 与Membase区别
    Redis支持数据的持久化,可以将数据存放在硬盘上。
    Memcache不支持数据的持加粗样式久存储。
    Redis数据类型丰富,支持set liset等类型
    Memcache支持简单数据类型,需要客户端自己处理复制对象
  4. Redis简介
    Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库
    Redis 与其他 key - value 缓存产品有以下三个特点
    Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
    Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
    Redis支持数据的备份,即master-slave模式的数据备份。
  5. Redis应用场景
    主要能够体现,解决数据库的访问压力
    例如:短信验证码时间有效期、session共享解决方案、token生成、分布式锁、自增id等。
  6. Redis优势
    1)性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
    2)丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
    3)原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
    4)丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

二、Redis安装
参考:

三、Redis主从复制

  1. 概述
    1)redis的复制功能是支持多个数据库之间的数据同步。一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的,并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库。
    2)通过redis的复制功能可以很好的实现数据库的读写分离,提高服务器的负载能力。主数据库主要进行写操作,而从数据库负责读操作。
    主从复制过程如下图:
  2. Java 双机环境本地缓存同步 java本地缓存和redis_Redis持久化

  3. 过程:
    (1) 当一个从数据库启动时,会向主数据库发送sync命令,
    (2) 主数据库接收到sync命令后会开始在后台保存快照(执行rdb操作),并将保存期间接收到的命令缓存起来
    (3) 当快照完成后,redis会将快照文件和所有缓存的命令发送给从数据库。
    (4) 从数据库收到后,会载入快照文件并执行收到的缓存的命令。
  4. 部署Redis主从复制
    redis主从复制是:一主多备

2.1.部署三台服务器,如何部署Redis见环境部署——CentOS7上安装Redis
主服务器IP:192.168.27.138
从服务器IP:192.168.27.139 , 192.168.27.140

2.2 配置主服务器
修改redis-3.2.9下的redis.config文件:

daemonize no  -- 改为 daemonize yes 后台运行
# requirepass foobar  --修改密码为 requirepass 123456

2.3 配置从服务器
修改redis-3.2.9下的redis.config文件:

daemonize no  -- 改为 daemonize yes 后台运行
# requirepass foobar  --修改密码为 requirepass 123456

# slaveof <masterip> <masterport>  -- 改为 slaveof 192.168.27.138 6379
# masterauth <master-password>   -- 改为 masterauth 123456

2.4 先启动主服务器,在启动从服务器
到redis-3.2.9目录下:

[root@localhost redis-3.2.9]# src/redis-server redis.conf

四、哨兵机制

  1. 什么是哨兵机制
    Redis的哨兵(sentinel) 系统用于管理多个 Redis 服务器,该系统执行以下三个任务:
  • 监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。
  • 提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
  • 自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master; 当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。

哨兵(sentinel) 是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossipprotocols)来接收关于Master是否下线的信息,并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master

每个哨兵(sentinel) 会向其它哨兵(sentinel)、master、slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(所谓的”主观认为宕机” Subjective Down,简称sdown)。

若“哨兵群”中的多数sentinel,都报告某一master没响应,系统才认为该master"彻底死亡"(即:客观上的真正down机,Objective Down,简称odown),通过一定的vote算法,从剩下的slave节点中,选一台提升为master,然后自动修改相关配置.

虽然哨兵(sentinel) 释出为一个单独的可执行文件 redis-sentinel ,但实际上它只是一个运行在特殊模式下的 Redis 服务器,你可以在启动一个普通 Redis 服务器时通过给定 --sentinel 选项来启动哨兵(sentinel)。

哨兵(sentinel) 的一些设计思路和zookeeper非常类似

Java 双机环境本地缓存同步 java本地缓存和redis_Java 双机环境本地缓存同步_02


2. 哨兵模式修改配置

选取IP地址为:192.168.27.139 作为实现哨兵机制的服务器

2.1 修改redis-3.2.9下的sentinel.conf文件的内容:

sentinel monitor mymaster 192.168.27.138 6379 1  #主节点 名称 IP 端口号 选举次数
sentinel auth-pass mymaster 123456  #名称  密码

sentinel down-after-milliseconds mymaster 5000   #修改心跳检测 5000毫秒
4.sentinel parallel-syncs mymaster 2   #做多多少合格节点
  1. 启动哨兵模式
[root@localhost redis-3.2.9]# src/redis-server ./sentinel.conf --sentinel &
  1. 停止哨兵模式
ps aux | grep '26379'  --- 查询端口
kill -15 9886 --- 杀死重置
kill -9 9886 --- 强制杀死

五、Redis持久化

  1. 什么是Redis持久化
    将内存数据保存到硬盘,Redis 持久化存储 (AOF 与 RDB 两种模式)
  2. RDB持久化
    RDB 是在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。恢复方法:将备份的文件名改为dump.rdb 替换原来的dump.rdb文件。
  • 优点:使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能
  • 缺点:RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候。
    这里说的这个执行数据写入到临时文件的时间点是可以通过配置来自己确定的,通过配置redis 在 n 秒内如果超过 m 个 key 被修改这执行一次 RDB 操作。这个操作就类似于在这个时间点来保存一次 Redis 的所有数据,一次快照数据。所有这个持久化方法也通常叫做 snapshots。

RDB 默认开启,redis.conf 中的具体配置参数如下

#dbfilename:持久化数据存储在本地的文件
dbfilename dump.rdb

#dir:持久化数据存储在本地的路径,如果是在/redis/redis-3.0.6/src下启动的redis-cli,则数据会存储在当前src目录下
dir ./

##snapshot触发的时机,save    
##如下为900秒后,至少有一个变更操作,才会snapshot  
##对于此值的设置,需要谨慎,评估系统的变更操作密集程度  
##可以通过“save “””来关闭snapshot功能  
#save时间,以下分别表示更改了1个key时间隔900s进行持久化存储;更改了10个key300s进行存储;更改10000个key60s进行存储。
save 900 1
save 300 10
save 60 10000

##当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等  
stop-writes-on-bgsave-error yes  

##是否启用rdb文件压缩,默认为“yes”,压缩往往意味着“额外的cpu消耗”,同时也意味这较小的文件尺寸以及较短的网络传输时间  
rdbcompression yes
  1. AOF持久化
    Append-only file,将“操作 + 数据”以格式化指令的方式追加到操作日志文件的尾部,在 append 操作返回后(已经写入到文件或者即将写入),才进行实际的数据变更,“日志文件”保存了历史所有的操作过程;当 server 需要数据恢复时,可以直接 replay 此日志文件,即可还原所有的操作过程。AOF 相对可靠,它和 mysql 中 bin.log、apache.log、zookeeper 中 txn-log 简直异曲同工。AOF 文件内容是字符串,非常容易阅读和解析。
  • 优点:可以保持更高的数据完整性,如果设置追加 file 的时间是 1s,如果 redis 发生故障,最多会丢失 1s 的数据;且如果日志写入不完整支持 redis-check-aof 来进行日志修复;AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall)。
  • 缺点:AOF 文件比 RDB 文件大,且恢复速度慢。

我们可以简单的认为 AOF 就是日志文件,此文件只会记录“变更操作”(例如:set/del 等),如果 server 中持续的大量变更操作,将会导致 AOF 文件非常的庞大,意味着 server 失效后,数据恢复的过程将会很长;事实上,一条数据经过多次变更,将会产生多条 AOF 记录,其实只要保存当前的状态,历史的操作记录是可以抛弃的;因为 AOF 持久化模式还伴生了“AOF rewrite”。
AOF 的特性决定了它相对比较安全,如果你期望数据更少的丢失,那么可以采用 AOF 模式。如果 AOF 文件正在被写入时突然 server 失效,有可能导致文件的最后一次记录是不完整,你可以通过手工或者程序的方式去检测并修正不完整的记录,以便通过 aof 文件恢复能够正常;同时需要提醒,如果你的 redis 持久化手段中有 aof,那么在 server 故障失效后再次启动前,需要检测 aof 文件的完整性。

AOF 默认关闭,开启方法,修改配置文件 reds.conf:appendonly yes

##此选项为aof功能的开关,默认为“no”,可以通过“yes”来开启aof功能  
##只有在“yes”下,aof重写/文件同步等特性才会生效  
appendonly yes  

##指定aof文件名称  
appendfilename appendonly.aof  

##指定aof操作中文件同步策略,有三个合法值:always everysec no,默认为everysec  
appendfsync everysec  
##在aof-rewrite期间,appendfsync是否暂缓文件同步,"no"表示“不暂缓”,“yes”表示“暂缓”,默认为“no”  
no-appendfsync-on-rewrite no  

##aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,默认“64mb”,建议“512mb”  
auto-aof-rewrite-min-size 64mb  

##相对于“上一次”rewrite,本次rewrite触发时aof文件应该增长的百分比。  
##每一次rewrite之后,redis都会记录下此时“新aof”文件的大小(例如A),那么当aof文件增长到A*(1 + p)之后  
##触发下一次rewrite,每一次aof记录的添加,都会检测当前aof文件的尺寸。  
auto-aof-rewrite-percentage 100

AOF 是文件操作,对于变更操作比较密集的 server,那么必将造成磁盘 IO 的负荷加重;此外 linux 对文件操作采取了“延迟写入”手段,即并非每次 write 操作都会触发实际磁盘操作,而是进入了 buffer 中,当 buffer 数据达到阀值时触发实际写入(也有其他时机),这是 linux 对文件系统的优化,但是这却有可能带来隐患,如果 buffer 没有刷新到磁盘,此时物理机器失效(比如断电),那么有可能导致最后一条或者多条 aof 记录的丢失。通过上述配置文件,可以得知 redis 提供了 3 中 aof 记录同步选项:
always:每一条 aof 记录都立即同步到文件,这是最安全的方式,也以为更多的磁盘操作和阻塞延迟,是 IO 开支较大。
everysec:每秒同步一次,性能和安全都比较中庸的方式,也是 redis 推荐的方式。如果遇到物理服务器故障,有可能导致最近一秒内 aof 记录丢失(可能为部分丢失)。
no:redis 并不直接调用文件同步,而是交给操作系统来处理,操作系统可以根据 buffer 填充情况 / 通道空闲时间等择机触发同步;这是一种普通的文件操作方式。性能较好,在物理服务器故障时,数据丢失量会因 OS 配置有关。
其实,我们可以选择的太少,everysec 是最佳的选择。如果你非常在意每个数据都极其可靠,建议你选择一款“关系性数据库”吧。
AOF 文件会不断增大,它的大小直接影响“故障恢复”的时间, 而且 AOF 文件中历史操作是可以丢弃的。AOF rewrite 操作就是“压缩”AOF 文件的过程,当然 redis 并没有采用“基于原 aof 文件”来重写的方式,而是采取了类似 snapshot 的方式:基于 copy-on-write,全量遍历内存中数据,然后逐个序列到 aof 文件中。因此 AOF rewrite 能够正确反应当前内存数据的状态,这正是我们所需要的;rewrite 过程中,对于新的变更操作将仍然被写入到原 AOF 文件中,同时这些新的变更操作也会被 redis 收集起来(buffer,copy-on-write 方式下,最极端的可能是所有的 key 都在此期间被修改,将会耗费 2 倍内存),当内存数据被全部写入到新的 aof 文件之后,收集的新的变更操作也将会一并追加到新的 aof 文件中,此后将会重命名新的 aof 文件为 appendonly.aof, 此后所有的操作都将被写入新的 aof 文件。如果在 rewrite 过程中,出现故障,将不会影响原 AOF 文件的正常工作,只有当 rewrite 完成之后才会切换文件,因为 rewrite 过程是比较可靠的。
触发 rewrite 的时机可以通过配置文件来声明,同时 redis 中可以通过 bgrewriteaof 指令人工干预。
redis-cli -h ip -p port bgrewriteaof
因为 rewrite 操作 /aof 记录同步 /snapshot 都消耗磁盘 IO,redis 采取了“schedule”策略:无论是“人工干预”还是系统触发,snapshot 和 rewrite 需要逐个被执行。
AOF rewrite 过程并不阻塞客户端请求。系统会开启一个子进程来完成。

  1. AOF与RDB区别
    OF 和 RDB 各有优缺点,这是有它们各自的特点所决定:

4.1 AOF 更加安全,可以将数据更加及时的同步到文件中,但是 AOF 需要较多的磁盘 IO 开支,AOF 文件尺寸较大,文件内容恢复数度相对较慢。

4.2 snapshot,安全性较差,它是“正常时期”数据备份以及 master-slave 数据同步的最佳手段,文件尺寸较小,恢复数度较快。

可以通过配置文件来指定它们中的一种,或者同时使用它们(不建议同时使用),或者全部禁用,在架构良好的环境中,master 通常使用 AOF,slave 使用 snapshot,主要原因是 master 需要首先确保数据完整性,它作为数据备份的第一选择;slave 提供只读服务(目前 slave 只能提供读取服务),它的主要目的就是快速响应客户端 read 请求;但是如果你的 redis 运行在网络稳定性差 / 物理环境糟糕情况下,建议你 master 和 slave 均采取 AOF,这个在 master 和 slave 角色切换时,可以减少“人工数据备份”/“人工引导数据恢复”的时间成本;如果你的环境一切非常良好,且服务需要接收密集性的 write 操作,那么建议 master 采取 snapshot,而 slave 采用 AOF。

六、Redis发布订阅

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

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

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

Java 双机环境本地缓存同步 java本地缓存和redis_Redis哨兵机制_03


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

Java 双机环境本地缓存同步 java本地缓存和redis_Redis持久化_04

实例
以下实例演示了发布订阅是如何工作的。在我们实例中我们创建了订阅频道名为 redisChat:

redis 127.0.0.1:6379> SUBSCRIBE redisChat

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

现在,我们先重新开启个 redis 客户端,然后在同一个频道 redisChat 发布两次消息,订阅者就能接收到消息。

redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"

(integer) 1

redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com"

(integer) 1

# 订阅者的客户端会显示如下消息
1) "message"
2) "redisChat"
3) "Redis is a great caching technique"
1) "message"
2) "redisChat"
3) "Learn redis by runoob.com"