要想了解一个知识,首先要了解是什么情景需要运用这项技术,这项技术在此情景解决了什么问题,要想要深入了解Redis,我们应先了解一下关于数据库的处理数据的历史,关键点就是数据不断变多,如何处理数据。
小李刚刚大学毕业,开始创业,建了一个购物网站,名气不大,偶尔有人登录此网站点一点
特点:
- 访问量少,
- 静态页面,前后端交互少
- 服务器压力小
随着小李的努力,访问数量急剧增加,数据库的压力也随之增加,小李开始了对数据库的本身的优化(数据结构和索引),但是,问题还是不能很好的解决
- 数据量太大,一个服务器放不下了
- 访问量(读写混合),一个服务器承受不了
- 数据的索引,一个服务器的内存也放不下
经过一番思所和分析,小李发现网站80%都是在读,每次都要查数据库的话十分麻烦,怎样能减轻数据的压力呢?
加入缓存(Memcached),用户访问时,先去缓存中(根据一定的规则,从数据库中获取数据存到缓存中)查,查到了则不去数据库查,查不到在去数据库查
加入缓存,虽然解决了一些问题,但是还是不能够应对用户的增长的速度,小李决定增加几台服务器,但是呢?又遇到一个问题,新增的服务器之间怎么通信,怎么能保证数据都一致呢?
Memcached(缓存)随之出世
- Memcached的分布方法
a.向Memcached添加数据,首先根据客户端算法利用key选择保存的服务器;
b.服务器选定后,保存数据
c.获取数据时,以相同的key,相同的算法可以定位到相同的服务器位置,从而获取数据- Memcached的分布式算法
Memcached使用的分布式算法中,我们简单介绍两种:余数哈希;一致性哈希
A.余数哈希
根据服务器台数的余数进行哈希,求得键的哈希值,再处理服务器台数,根据余数选择服务器,
缺点:当添加或者移除服务器时,缓存重组的代价太大,
当添加服务器,访问数据,Memcached命中率下降,那么就增加了数据库服务器的负载.
B.一致性哈希
一致性哈希是将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间是0~(2^32 -1)(即哈希值是一个32位的无符号整型),这个哈希空间为环
哈希空间按顺时针方向组织.为确定每台服务器在空间上的位置,按照服务器主机名或者IP地址对每台服务器进行Hash寻址.然后需要使用hash算法来判断数据应该存储在哪个服务器:首先,将数据根据key值使用相同的函数H计算出哈希值h,根据h确定数据在环上的位置,从此位置延环顺时针向下寻找,遇到的第一个服务器就是其应该存储的服务器
附带一篇关于Memcached博客
这一模式主要解决了数据库读压力
用于用户的增多,订单和物品的品种都随之增加,数据库的写入压力也倍增,而Memcached只能缓解数据库的读取压力,读写集中在一个数据库上让数据库不堪重负,小李灵机一动,运用主从复制,达到读写分离,以提高数据库的读写性能和读库的可扩展性
解决读写性能和读库的可扩展性—可以不断地增加从数据库,以减轻主数据库的压力,主写从读
小李的事业进一步发展,公司开始上市,用户,订单更是急剧增加,写入压力指数级增长,一台服务器的写入已然是杯水车薪,刚好市面上开始流行分表分库来缓解写压力和数据增长的扩展问题,而MySQL官网也推出了MySQL集群,为小李这一问题给出了解决方案
首先我们要知道MySQL的瓶颈,才能更好的理解NoSQL
MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如1000万4KB大小的文本就接近40GB的大小,如果能把这些数据从MySQL省去,MySQL将变得非常的小。关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。
归结三点
- 存大文本的时候,导致数据库表非常的大,出错之后还不易恢复
- 数据种类繁多,表结构难更改,扩展性能差,牵一发而动全身(关系型,一环套一环)
- 存在磁盘上,大数据下IO压力大,性能低下
如何解决以上的问题呢?
NoSQL = Not Only SQL (不仅仅是SQL) 关系型数据库:表格 ,行 ,列
泛指非关系型数据库的,随着web2.0互联网的诞生!传统的关系型数据库很难对付web2.0时代!尤其 是超大规模的高并发的网站! 暴露出来很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
很多的数据类型用户的个人信息,社交网络,地理位置。这些数据类型的存储不需要一个固定的格式! 不需要多余的操作就可以横向扩展的 !
应对基于海量用户和海量数据前提下的数据处理
商品的附加信息,如描述,详情,评论—MogoDB
热点信息,如抢购,秒杀—Redis
Redis(Remote Dictionary Server ),即远程字典服务
redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。
支持多种类型的数据结构:如:字符串、哈希、列表、集合、有序集合等
可用作数据库、缓存、消息中间件
Redis一共支持五种数据类型:String(字符串)、hash(哈希)、list(列表)、set(集合)和zset(sorted set有序集合)
String(字符串):Redis最基本的数据类型,一个键对应一个值,一个键值最大存储512MB
Hash(哈希):hash是一个键值对的集合,是一个String类型的field和value的映射表,适合用于存储对象
List(列表):是redis的简单的字符串列表,按插入顺序排序
Set(集合):是String字符串类型的无序集合,也不可重复
ZSet(sorted set 有序集合)是String类型的有序集合,也不可重复。有序集合中的每个元素都需要指定一个分数,根据分数对元素进行升序排序。
附带详细解释数据类型及其应用场景
情景分析:如果用户取钱,不止是一个操作就可以完成,需要多个操作一起完成才能完成一个取钱的操作,如用户余额的减少和用户余额的更新,这两个操作必须是要么一起成功,要么一起失败的—原子性
redis事务就是一个命令执行的队列,将一系列预定义命令包装程一个队列,当执行时,一次性按照添加顺序依次执行,中间不会被打断或者干扰
附加详细的事务和代码博客
情景分析:
如多个业务员同时进行补货的时候,那么一名业务员补货之后,同时操作的业务员就不可以在原来的数量上操作,应该在那一名业务员补货之后的数量操作,
要点:
- 多个用户同时对一组数据进行操作,并且一旦该数据被修改后,将不适用于在继续操作
- 在操作之前锁定要操作的数据,一旦发生变化,终止当前操作
开启事务前,设置对数据的监听(watch),EXEC时,如果发生数据发生过修改,事务会自动取消(DISCARD),事务EXEC后,无论成败,监听会被移除
每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。
场景:如果项目中使用了缓存且对缓存设置了超时时间。
当并发量比较大的时候,如果没有锁机制,那么缓存过期的瞬间,
大量并发请求会穿透缓存直接查询数据库,造成雪崩效应。
附带锁的应用情景
现实中如果遇到意外断电的情况,放置数据的意外丢失,确保数据的安全性
利用永久性存储介质将数据进行保存,在特定的事件将保存的数据进行恢复的工作机制称为持久化
详细的持久化博客
因为内存有限,有些数据不需要一直在内存中,可以设定一些规则,将一些数据设置过期,在内存中删除,当然也不是随便删除,也要考虑到CPU的繁忙与空闲,以免出现Redis各种命令执行很多,但是正好出现大量过期数据,已造成服务器宕机
创建一个定时器,当key设置有过期实践,且过期时间到达时,由定时器任务立即执行对键的删除操作
数据到达过期时间,不做处理,等下次访问该数据时进行处理,如未过期,返回数据,发现已过期,删除,返回不存在
周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占用的方式控制删除频度
附带详细的过期数据博客
情景分析,如果有新数据进入redis,但是数据都没有过期,而且内存也不足,那么这时就需要逐出算法,来腾出一些空间
maxmemory-policy volatile-lru
附带详细逐出算法博客
单个Redis存在不稳定性,当Redis服务宕机或硬盘故障,系统崩溃之后,就没有可用的服务了,还会造成数据的丢失
单个Redis的读写能力也是有限的
通过添加服务器的数量,提供相同的服务,从而让服务器达到一个稳定,高效的状态
- 主数据库可以进行读写操作,当读写操作导致数据变化时会自动将数据同步给从数据库
- 从数据库一般都是只读的,并且接收主数据库同步过来的数据
- 一个master可以拥有多个slave,但是一个slave只能对应一个master
- slave挂了不影响其他slave的读和master的读和写,重新启动后会将数据从master同步过来
- master挂了以后,不影响slave的读,但redis不再提供写服务,master重启后redis将重新对外提供写服务
- master挂了以后,不会在slave节点中重新选一个master
哨兵(sentinel)是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master
redis最开始使用主从模式做集群,若master宕机需要手动配置slave转为master;后来为了高可用提出来哨兵模式,该模式下有一个哨兵监视master和slave,若master宕机可自动将slave转为master,但它也有一个问题,就是不能动态扩充;所以在3.x提出cluster集群模式。
redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。
那么redis 是如何合理分配这些节点和数据的呢?
Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。
附带集群详细博客
原因:
短时间范围内,大量的key集中过期
解决方案:
对数据的过期时间进行调整,避免在一定时间内大面积key过期
解决方案:
预防为主,监控访问量,对自然流量激增的数据延长过期时间或设置为永久性key
解决方案:
布隆过滤器
布隆过滤器是一种非常高效的数据结构,把所有数据库的value对应的key 存储到布隆过滤器里,几乎不消耗什么空间,而且查询也是相当的快!但是请注意,它只能判断 key 是否存在(而且会有一定的误差)。
详细了解布隆过滤器