一.为什么要使用NoSQL:

1.1单机数据库遇到的问题

1.数据总量的大小,当一个机器放不下的时候。
2.数据的索引(B+Tree)一个机器的内存放不下的时候。
3.访问量(读写混合)一个实例不能承受。

1.2Memcached+MySQL+垂直拆分

随着访问量的上升,数据库无法满足性能要求,所以通过缓存来环节数据库的压力,但当访问量继续增大的时候,多台web机器通过文件缓存不能共享,这是Memcached成为下一个解决方法。下图为缓存结构:
image.png

1.3Mysql主从读写分离

由于数据库的写入压力增大,而Memcached只能缓解数据库的读取压力,所以开始使用master-slave模式来完成读写分离。
image.png

1.4分表分库+水平拆分+mysql集群

在Memcached的告诉缓存,M有SQL的主从辅助,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,由于使用表锁,在高并发下会出现严重的锁问题。所以开始流行使用分表分库来环节压力和数据增长的扩展问题。
image.png

1.5MySQL的扩展性瓶颈

数据库经常存储一些大文本字段,导致数据库表非常大,在数据库回复时速度很慢,关系型数据库不能满足所有的应用场景,扩展性差,大数据下IO压力大,表结构更改困难。

二.NoSQL的介绍

2.1NoSQL是什么

NoSQL=not only SQL,不仅仅是SQL(泛指非关系型的数据库),这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

2.2NoSQL的功能

易扩展:数据库种类繁多,共同的特点都是去掉关系型数据库的关系型特性。数据之间没有关系,这样就非常容易扩展,在架构的层面上带来了可扩展的能力。
大数据量高性能:具有非常高的读写性能,mysql使用的缓存在表的每次更新后就失效,是一种大颗粒度的Cache,性能不高,而NoSQL是记录级的,是一种细颗粒度的Cache,性能要高很多。
灵活的数据模型:Nosql无需事先为为要存储的数据建立字段,可以随时存储自定义的数据格式。

2.3“3v+3高”

大数据时代的3v:海量volume,多样variety,实时velocity。
互联网需求的三高:高并发,高可扩,高性能。

2.4NoSQL数据模型简介与四大分类

聚合模型简介:1.KV键值 2.BSON 3.列族 4.图形
BOSN:是一种json的一种二进制形势的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象。
列族:顾名思义,列族是按照列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。
图形:关系由图来表示,互相有对应的指向。
注:高并发的操作是不太建议有关联查询的,互联网公司用冗余数据来避免关联查询,分布式事务是支持不了太多的并发。

2.4.1NoSQL数据库的四大分类:

K-V键值:新浪:BerkeleyDB+redis,美团:Redis+tair,美团,百度:memcache+redis
文档型数据库(BSON格式居多):CouchDB,MongoDB:是一个基于分布式文件存储的数据库。为WEB应用提供可扩展的高性能数据存储解决方案。是一个介于关系型数据库和非关系型数据库之间的产品,是非关系数据库当中功能最丰富,最像关系型数据库的。
列存储数据库:Cassandra,HBase,分布式文件系统
图关系数据库:不是放图形,放的是关系比如朋友圈社交网络,广告推荐系统,专注于构建关系图谱。Neo4J,InfoGrid。
image.png
四大分类的对比
image.png

2.5分布式数据库中CAP原理CAP+BASE

2.5.1传统的ACID分别是什么:

A(Atomicity)原子性,C(Consistency)一致性,I(Isolation)独立性,D(Durability)持久性
1.原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚,比如银行转账。
2.一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。
3.所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另一个事务修改,只要另外一个事务未提交,它所访问的数据就不收未提交事务的影响,比如现有一个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。
4.持久性是指一旦事务提交后,他所做的修改将会永久保存在数据库上,即使出现宕机也不会丢失。

2.5.2CAP

C:Consistency(强一致性),A:Avaulability(可用性),P:Partition tolerance(分区容错性)
1.强一致性就代表数据提交内容与保存内容一定要一样
2.可用性表示你总是能够访问集群,即使集群中的某个结点宕机了
3.容忍集群持续运行,即使他们中存在分区(两个分区中的结点都是好的,只是分区之间不能通信)

2.5.3CAP的三选二:

一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。因此,根据CAP原理将NoSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类:

CA-单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
CP-满足一致性,分区容忍必的系统,通常性能不是很高。
AP-满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
image.png
CAP理论就是说在分布式存储系统中,最多只能实现上面的两个点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的(P)
CA:传统Oracle数据库 AP:大多数网站架构的选择 CP:Redis,Mongodb

2.5.4BASE

BASE就是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。是下面三个术语的缩写:基本可用(Basically Available),软状态(Soft state),最终一致(Eventually consistent)。
他的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上的改观。为什么这么说,缘由就在于大型系统往往由于地域分布和极高的性能要求,不可能采用分布式事务来完成这些指标,要想获得这些指标,我们必须采用另一种方式来完成,这里BASE就是解决这个问题的办法。

2.5.5分布式+集群简介

分布式:不同的多台服务器上面部署不同的服务模块(工程),他们之间通过Rpc/Rmi之间通信和调用,对外提供服务和组内写作。
集群:不同的多台服务器上面部署相同的服务模块,通过分布式调度软件进行统一的调度,对外提供服务和访问。

三.Redis

3.1入门概述

是什么:Redis:REmote DIctionary Server(远程字典服务器),是完全开源免费的,用c语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行。并且支持持久化的N哦SQL数据库,是当前最热门的NoSQL数据库之一,也被称为数据结构服务器。Redis与其他Key-value缓存产品有以下三个特点:
1.Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
2.Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zest,hash等数据结构的存储。
3.Redis支持数据的备份,即master-slave模式的数据备份。

能干嘛:内存存储和持久化:redis支持异步将内存中的数据写到硬盘中,同时不影响继续服务,取最新n个的操作,模拟类似于HttpSession这种需求设定过期时间的功能,发布,订阅消息系统。定时器,计数器

去哪下:Http://redis.io/ Http://www.redis.cn

怎么用:数据结构,基本操作和配置,持久化和复制 RDB/AOF,事务的控制,复制。

windows环境下如何运行以及操作(第一个启动的dos窗口不能关闭否则无法继续使用Redis)
image.png
linux环境下
拷贝文件到/opt文件夹下,然后进行解压,进入到redis文件中查看make文件,然后进行对redis的安装
如果遇到gcc文件没有安装或者其他情况要对gcc进行安装,然后清理二次安装的残留文件make distclean指令,然后输入make安装
注:在安装gcc时推荐使用原生的源,如果用国内的源可能会遇到无法解决的问题,安装完检查依赖,然后进行make安装。然后要对redis.config进行备份,再对配置文件进行修改,将general的后台保持运行改为yes.
命令:ps -ef|grep redis 查看后台是否运行redis
sudo gedit 后面要加要更改的文本
image.png
要用更改过的redis.conf来调用redis-server然后用redis-cli -p 6379这条命令进入到6379端口来输入ping来测试redis。

3.2Redis杂项基础知识

3.2.1单进程:

单进程模型来处理客户端的请求。对读写等事件的响应是通过对epoll函数的包装来做到的。Redis的实际处理速度完全依靠主进程的执行效率。epoll是Linux内核为处理大批量文件描述符而作了改进的epoll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。

3.2.2库:

Redis默认有16个数据库,类似数组下标从0开始,初始默认使用零号库。select命令切换数据库,Dbsize是查看当前数据库的key的数量,默认带有三个key。可以使用keys —?来进行key的模糊查询。FLUSHDB是清空当前库的所有key。flushall是删除所有库的key,默认端口是6379

3.3Redis数据类型

3.3.1Redis的五大数据类型

String(字符串),Hash(哈希,类似Java里的Map),List(列表),Set(集合),Zset(sorted set:有序集合)
String:是redis最基本的类型,一个key对应一个value。String类型是二进制安全的。意思是redis的string可以包含任何数据,比如jpg图片或者序列化的对象。一个redis中字符串value最多可以是512M.
Hash:redis hash是一个键值对集合,hash是一个String类型的field和value的映射表,hash适合存储对象。
List:Redis列表是简单的字符串列表,按照插入顺序排序,可以在一个元素的头部或者尾部,是链表结构
Set:是string类型的无序集合,是通过HashTable实现的
Zset:redis的zset和set一样也是string类型元素的集合,且不允许重复的成员,不同的是每个元素都会关联一个double类型的分数,redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数却可以重复
获取redis命令参与列表:http://redisdoc.com/,

3.3.2Redis的键(key)

kesy *:查看所有的key。 exists key的名字,判断某个key是否存在。move key db—>移动key到指定的库。expire key 秒:为给定的key设置过期时间(如果已经过期会直接移除)。 ttl key:查看还有多少秒国企,-1表示永不过期。-2表示已经过期。type key查看你的key是什么类型。

3.3.3Redis String的常用命令

单值单value,set是建立一个新的键值对,get:按照key取出键值对,del按照键删除键值对,append给对应的键加内容,strlen 查看对应键值对的长度,incr :给对应键值加值,decr给对应键减值(这两个后面都可以跟数字表示要操作的数字)getrange/setrange:按照一个范围进行放或者取。set是从某一位改内容。
image.pngimage.png
setex(set with expire):setex k4 10 v4,给k4设置只有十秒的存活时间。
setnx(set if not exist):setnx k1 v11,如果k1如果已经存在则不会新建。
mset/mget/msetnx:一次操作多个键值对

3.3.4Redis列表 List

单值多value,lpush从左建立list,rpush从右建立list,在进行lrange的时候,rpush是队列结构,lpush是栈结构,所以rpush在输出时也是正序的。lpop是栈顶出栈,rpop与之相反。lindex按照索引下标获得元素,llen是获取长度。lrem key 删N个value。ltrim key开始index 结束index,截取指定范围的值之后再赋值给key。rpoplpush是从底部取值然后加在头部。lset key index value是按照k改value。
总结:是一个字符串链表,left,right都可以插入添加,如果键不存在,创建新的链表,如果键已存在新增内容。如果值全移除,对应的键也就消失了。链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很差
image.png

3.3.4Redis列表Set

单值多value,sadd往set里放值,如果有重复自动去重,smembers查看set里的成员,sismember查看值是否在set里存在。scard获取集合里面的元素个数。srem key value删除集合中元素srandmember key 某个整数(随机出几个数),spop key 随机出栈,smove key1 key2在key1里某个值 作用是将key1里的某个值赋给key2.
数学集合类:差集:sdiff,按照第一个key为全集,然后后面的key与他相补。
交集:sinter,查看两个key的交集。
并集:sunion,对两个key进行并集。自动去重

3.3.5Redis哈希Hash

KV模式不变,但v是一个键值对,hset(hset user name xiaoming)新建一个user的key然后给属性name赋值,hget(hget user name)取出user的name的值。hmset一次操作多个属性。
image.png
hgetall取出这个key的所有属性和值,按照key-value的形式展示,hdel删除,hlen长度,hexists key在key里面的某个值的key。hkeys,获取这个key的所有属性。hvals获取这个key的所有属性的值。hincrby按照key的属性进行增加。hincrbyfloat增加小数。hsetnx是按照key的属性,如果不存在的话就进行赋值。

3.3.6Redis有序集合Zset

在set的基础上,加一个score值,之前set是k1 v1现在zset是k1 score1 v1。zadd是两个是一个整体往里添加。zrange查看所有的值,withscores是显示添加的score。zrangebyscore key 开始score结束score,是按照score的范围进行取值。‘(’表示不包含,limit表示从第几个截取几位。zrem key某score下对应的value值,作用是删除元素。
image.png
zcard统计key对应的值个数,zcount统计一个范围的数,zrank 看值对应的score下标,zscore 查看value对应的score,zrevrank key value值,作用是逆序获得下标值,zrevrange逆序取值。

3.4解析配置文件 redis.conf

1.在更改配置文件的时候先进行备份。
2.GENERAL:
image.png
image.png
3.SECURITY:密码默认没有,但可以手动设置。config get requirepass查看密码,config setrequirepass “”设置密码,如果设置密码之后,在进行命令操作之前要进行解锁,auth“密码”之后才能正常进行操作。
4.LIMITS限制:maxclients最大连接用户数量,maxmemory最大内存,五种缓存过期策略
image.png
5.maxmemory-policy:几种策略
image.png
6.maxmemory-samples
image.png
总结:
image.png
image.png
image.png
image.png
image.png
image.png

3.5Redis的持久化 RDB AOF

3.5.1RDB(Redis DataBase)

是什么:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是snapshot快照,它恢复时是将快照文件直接读到内存里。Redis会单独创建一个子进程来进行持久化,会先将数据写入到一个零时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件,整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后数据可能丢失。
Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量,环境变量,程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程,子进程是在BGSAVE的时候创建出来的,作用就是进行IO操作,让主进程能够继续处理请求。在主进程这边会copy一个内存照,然后在当前里处理请求,如果这个时候内存挂掉,最后一次更新的内容就会丢失,FORK还会阻塞,会耽误时间。
配置位置:redis.conf里的snapshotting配置,自己设置切片时间还有操作次数,如果满足条件则会保存在dump.rdb中,在恢复的时候会重新把rdb文件读到内存里进行恢复,可以进行数据更改后里面save备份。
snapshotting快照:有几个常用属性,1.save 2.stop-writes-on-bgsave-error 3.rdbcompression 4.rdbchecksum 5.dbfilename 6.dir
如何触发rdb快照:1.配置文件中默认的快照配置,冷拷贝后重新使用,可以cp dump.rdb dump_new.rdb
2.命令save或者是bgsave,save时只管保存,其他不管,全部阻塞。bgsave:redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。可以通过lastsave命令获取最后一次成功执行快照的时间。3.执行flushall命令,也会产生dump.rdb文件,但里面是空的没有意义
如何恢复:将备份文件dump.rdb移动到redis安装目录并启动服务即可,config get dir 获取目录。
优势:适合大规模的数据恢复,对数据完整性和一致性要求不高。
劣势:在一定间隔时间做一次备份,所以如果redis意外down的话就会丢失最后一次快照后的所有修改。fork的时候,内存中的数据被克隆了一份,大致两倍的膨胀性需要考虑。
总结模型图
image.png

3.5.2AOF(Append Only File)

是什么:以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
Append only mode追加:相关配置。appendonly 默认时no,yes就打开aof持久化。appendfilename相关名字。appendfsync:always,同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性较好。everysec,出场默认推荐,异步操作。每秒记录,如果一秒内宕机,有数据丢失。no-appendfsync-on-rewrite:重写时是否可以运用appendfsync,用默认no即可,保证数据安全性。auto-aof-rewrite-min-size:设置重写的基准值。auto-aof-rewrite-percentage:设置重写的基准值。
AOF启动/修复/恢复:正常恢复,启动设置为yes,修改默认的appendonly no改为yes。将有数据的aof文件复制一份保存到对应目录(config get dir)。恢复:重启redis然后重新加载。异常恢复,启动设置为yes,备份被写坏的AOF文件,修复,redis-check-aof —fix进行修复,恢复,重启redis然后重新加载。
Rewrite:是什么,AOF采用文件追加方式,文件会越来越大,为了避免出现这种情况,新增了重写机制,当AOF文件的大小超过设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof。重写原理:aof文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。触发机制,Redis会记录上次重写时的aof大小,默认配置是当aof文件大小是上次rewrite后大小的一倍且文件大于64m时触发。
优势:每秒同步:appendfsync always 同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好。每修改同步:appendfsync everysec异步操作,每秒记录,如果一秒内宕机,有数据丢失。不同步:appendfsync no 从不同步
劣势:相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb,aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同。
总结框图
image.png

3.5.3两者总结

image.png
image.png
同时开启两种持久化方式的扩展内容
image.png

3.6Redis事务

是什么:可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行,执行不会被其他命令插入,不允许加塞。作用:一个队列中,一次性,顺序性,排他性的执行一系列命令。
怎么用:1.常用命令 DISCARD取消事务,放弃执行事务块内所有命令 EXEC 执行所有事务块内的命令 MULTI标记一个事务块的开始 UNWATCH取消watch命令对所有key的监视 WATCH key[key…]监视一个或者多个key,如果在事务执行之前这个或这些key被其他命令所改动,那么事务将被打断。(MULTI标记事务的开始然后进行命令的书写,命令书写完毕之后会提示入队成功,最后要在执行的时候输入EXEC)注:如果有一个语句报错失败其他的也会失败,遵循一致性。但如果在语句成功时但在EXEC时报错则会单独报错,并且放行其他的语句。

3.6.1WATCH监控

悲观锁\乐观锁\CAS(check and set)
悲观锁:当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制,在修改数据之前先锁定,再修改的方式被称之为悲观并发控制【Pessimistic Concurrency Control,缩写“PCC”,又名“悲观锁”】
共享锁【shared locks】又称为读锁,简称S锁。顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
排他锁【exclusive locks】又称为写锁,简称X锁。顾名思义,排他锁就是不能与其他锁并存,如果一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据行读取和修改。

乐观锁:乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场景,这样可以提高程序的吞吐量。
Java 中java.util.concurrent.atomic包下面的原子变量使用了乐观锁的一种 CAS 实现方式。
版本号控制:一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会+1。当线程A要更新数据值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。

总结:watch指令,类似乐观锁,事务提交时,如果key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行。通过watch命令在事务执行之前监控了多个keys,倘若在watch之后有任何key的值发生了变化,exec命令执行的事务都将被放弃,同时返回nullmulti-bulk应答以通知调用者事务执行失败。

3.6.2事务的三阶段和三特性

三阶段:1.开启,以multi开始一个事务 2.入队,将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面 3.执行,由EXEC命令触发事务。
三特性:1.单独的隔离操作,事务中所有命令都会序列化,按顺序地执行。事务在执行的过程中,不会被其他客户端发来的命令请求所打断 2.没有隔离级别的概念,队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个麻烦的问题 3.不保证原子性,redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

3.7Redis的发布订阅(了解)

是什么:进程间的一种消息通信模式,发送者pub发送消息,订阅者sub接受消息。

  1. image.png

image.png

3.8Redis的主从复制

是什么:主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,master以写为主,slave以读为主。作用:读写分离,容灾回复。
怎么用:1.只配置从库不配置主库,从库配置:slave 主库ip 主库端口(每次与master断开之后,都需要重新连接,除非配置进redis.conf文件)2.修改配置文件细节操作:1.拷贝多个redis.conf文件 2.开启daemonize yes 3.pid文件名字 4.指定端口 5.log文件名字 6.Dump.rdb名字。3.常用的三个方法1.一主二仆,info replication显示本台机器的详细信息。slaveof 主机ip 主机端口对主机进行连接并复制,如果进行配置后主机宕机后从机原地待命,等主机恢复一切照旧。如果从机在宕机之后没有重新连接,那么从机的角色恢复为master,要进行重新连接。2.薪火相传,与主仆不同的是去中心化,上一个slave可以是下一个slave的master,slave同样可以接受其他slaves的连接和同步请求,那么该slave作为了链条中下一个的master,可以有效减轻master的写压力,中途变更转向:会清除之前的数据,重新建立拷贝最新的slaveof新主库ip 新主库端口 3.反客为主,slaveof no one,让从机变为主机,数据相同,其他从机需要重新复制新的主机。
复制原理:slave启动成功连接到master后会发送一个sync命令,master接到命令启动后台的存盘进程,同时收集所有接受到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步。全量复制:而slave服务在接受到数据库文件数据后,将其存盘并加载到内存中。增量复制:master继续将新的所有收集到的修改命令依次传给slave,完成同步。但是只要是重新连接master,一次完全同步(全量复制)将被自动执行。

3.8.1哨兵模式:

怎么使用:首先调整几个主机的结构,在自定义的conf存放的目录下新建sentinel.conf,名字不能错,配置哨兵,填写内容:sentinel monitor被监控数据库名字(自己起)127.0.0.1 6379 1,最后一个数字1,表示主机宕机之后salve投票看让谁接替成为主机,得票数多少后成为主机。启动哨兵:redis-sentinel/myredis/sentinel.conf上述目录依照各自的实际情况配置,可能目录不同。在原来的master的挂了之后会重新投票新选。一组sentinel能同时监控多个master。
缺点:由于写操作都是在master上操作,然后同步更新到slave上,所以从master同步到slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,slave机器数量的增加也会使这个问题更加严重。

3.9Redis的雪崩,击穿,穿透

缓存雪崩

对于系统 A,假设每天高峰期每秒 5000 个请求,本来缓存在高峰期可以扛住每秒 4000 个请求,但是缓存机器意外发生了全盘宕机。缓存挂了,此时 1 秒 5000 个请求全部落数据库,数据库必然扛不住,它会报一下警,然后就挂了。此时,如果没有采用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。
这就是缓存雪崩。
缓存雪崩的事前事中事后的解决方案如下。

  • 事前:redis 高可用,主从+哨兵,redis cluster,避免全盘崩溃。
  • 事中:本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死。
  • 事后:redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

用户发送一个请求,系统 A 收到请求后,先查本地 ehcache 缓存,如果没查到再查 redis。如果 ehcache 和 redis 都没有,再查数据库,将数据库中的结果,写入 ehcache 和 redis 中。
限流组件,可以设置每秒的请求,有多少能通过组件,剩余的未通过的请求,怎么办?走降级!可以返回一些默认的值,或者友情提示,或者空白的值。
好处:

  • 数据库绝对不会死,限流组件确保了每秒只有多少个请求能通过。
  • 只要数据库不死,就是说,对用户来说,2/5 的请求都是可以被处理的。
  • 只要有 2/5 的请求可以被处理,就意味着你的系统没死,对用户来说,可能就是点击几次刷不出来页面,但是多点几次,就可以刷出来一次。

    缓存穿透

    对于系统A,假设一秒 5000 个请求,结果其中 4000 个请求是黑客发出的恶意攻击。
    黑客发出的那 4000 个攻击,缓存中查不到,每次你去数据库里查,也查不到。
    举个栗子。数据库 id 是从 1 开始的,结果黑客发过来的请求 id 全部都是负数。这样的话,缓存中不会有,请求每次都“视缓存于无物”,直接查询数据库。这种恶意攻击场景的缓存穿透就会直接把数据库给打死。
    解决方式很简单,每次系统 A 从数据库中只要没查到,就写一个空值到缓存里去,比如 set -999 UNKNOWN。然后设置一个过期时间,这样的话,下次有相同的 key 来访问的时候,在缓存失效之前,都可以直接从缓存中取数据。

    缓存击穿

    缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。
    解决方式也很简单,可以将热点数据设置为永远不过期;或者基于 redis or zookeeper 实现互斥锁,等待第一个请求构建完缓存之后,再释放锁,进而其它请求才能通过该 key 访问数据。

    四.Redis_Jedis

    与Java对redis进行整合,如果是在本机或者虚拟机中只需要new一个jedis对象进行测试,填写ip和端口号即可
    image.png
    事务:jedis.multi的返回值是一个transaction,用redis的transaction接收,在最后进行exec命令提交
    image.png
    jedis_jedispool:单例模式的双端检索写法
    1. public class JedisPoolUtil
    2. {
    3. private static volatile JedisPool jedisPool =null;
    4. private JedisPoolUtil(){} //构造方法私有化
    5. public static JedisPool getJedisPoolInstance(){
    6. if(null==jedisPool){
    7. synchronized(JedisPoolUtil.class){//首先进行判断是否为空,如果不为空则给连接池上锁
    8. if(null==jedisPool){
    9. JedisPoolConfig poolConfig =new JedisPoolConfig();
    10. poolConfig.setMaxActive(1000);
    11. poolConfig.serMaxIdle(32);
    12. poolConfig.setMaxWait(100*1000);
    13. poolConfig.setTestOnBorrow(true);//池化的初始化设置
    14. jedisPool=new JedisPool(poolConfig,主机ip,端口)
    15. }
    16. }
    17. }
    18. return jedisPool;
    19. }
    20. public static void release(JedisPool jedisPool,Jedis jedis){//释放
    21. if(null !=jedis){
    22. jedisPool.returnRsourceObject(jedis);
    23. }
    24. }
    25. }
    image.png