缓存层(redis)
数据缓存层的原理
数据缓存层实际上就是对一个巨大的存在于内存中的DataSet进行管理,其原理如下:
(1)数据缓存层维护一个大DataSet,这个DataSet以static存在于应用程序中,这是缓存数据集。
(2)客户端发起请求,数据查询请求发送到数据缓存层。
(3)数据缓存层查询缓存起来的数据查询条件,查找该查询条件是否被使用过。
(4)如果该查询条件以前使用过,则不从数据库查询数据,只从缓存数据集中查询。
(5)如果该查询条件以前没有用过 ,则调用数据访问层从数据库中查询数据,并将查询数据合并到缓存数据集中,同时缓存该查询条件。
(6)更新数据时,将要更新的数据更新到数据库中,同时更新缓存数据集中的数据。
(7)在查询或更新数据时,都在缓存数据集相应数据表的扩展属性中记录当前访问时间。
(8)每隔一段时间对缓存数据集进行清理,当其中某条数据行超过一定时间(可以在配置文件中进行配置)没有访问,则将该表释放。
定义
redis是一个key-value存储系统。它支持存储的value类型相对更多,包括string(字符串)、list(
Redis 是一个高性能的key-value数据库。
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
为什么那么快:
+ Redis嘛,就是一种并发很强的跑在内存上的NoSql数据库,支持键到五种数据类型的映射。
-
首先,采用了多路复用io阻塞机制 然后,数据结构简单,操作节省时间 最后,运行在内存中,自然速度快
redis的五大数据类型:
String 整数,浮点数或者字符串 Set 集合 Zset 有序集合 Hash 散列表 List 列表
redis持久化机制和原理
-
RDB 持久化 将某个时间点的所有数据都存放到硬盘上。 可以将快照复制到其它服务器从而创建具有相同数据的服务器副本。 如果系统发生故障,将会丢失最后一次创建快照之后的数据。 如果数据量很大,保存快照的时间会很长。 AOF 持久化 将写命令添加到 AOF 文件(Append Only File)的末尾。 使用 AOF 持久化需要设置同步选项,从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马上将内容同步到磁盘上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到磁盘。有以下同步选项: 选项同步频率always每个写命令都同步everysec每秒同步一次no让操作系统来决定何时同步
原理:
-
客户端向服务端发送写操作(数据在客户端的内存中)。
-
数据库服务端接收到写请求的数据(数据在服务端的内存中)。
-
服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。
-
操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。
-
磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。
哨兵模式:
sentinel负责持续监控主节点的健康,当主节挂掉时,自动选择一个最优的从节点切换成主节点,当主节点发生故障时,sentinel会将最新的主节点地址告诉客户端,可以实现无需重启自动切换redis。Sentinel支持集群。
雪崩,击穿,穿透:
雪崩:缓存层承载着大量请求,有效的保护了存储层,存储层的调用量会暴增,造成存储层会挂掉的情况。
穿透:缓存穿透是指查询一个一定不存在的数据,由于缓存不命中,接着查询数据库也无法查询出结果,但是这将会导致每个查询都会去请求数据库,造成缓存穿透。
击穿:缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当key失效时,大量的请求就会击穿数据库
redis集群是怎么做的:
* codis集群 codis是redis集群解决方案之一,codis是GO语言开发的代理中间件
-
官方cluster方案
-
twemproxy代理方案
-
哨兵模式
-
codis
-
客户端分片
redis事物:
redis事物是可以一次执行多个命令,本质是一组命令的集合。2. 一个事务中的所有命令都会序列化,按顺序执行就不会被其他命令插入。
redis实现悲观锁,乐观苏,分布式锁:
悲观锁 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
乐观锁 总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。
分布式锁实现原理
在进程请求执行操作前进行判断,加锁是否成功,加锁成功允许执行下步操作;
如果不成功,则判断锁的值(时间戳)是否大于当前时间,如果大于当前时间,则获取锁失败不允许执行下步操作;
如果锁的值(时间戳)小于当前时间,并且GETSET命令获取到的锁的旧值依然小于当前时间,则获取锁成功允许执行下步操作;
如果锁的值(时间戳)小于当前时间,并且GETSET命令获取到的锁的旧值大于当前时间,则获取锁失败不允许执行下步操作;
分布式锁的作用:
redis写入时不带锁定功能,为防止多个进程同时进行一个操作,出现意想不到的结果,so...对缓存进行插入更新操作时自定义加锁功能。
数据类型的结构:
1.字符串类型:可以存储任何形式的字符串,也包括二进制流数据。string类型默认支持三种数据格式:字符串,整数,浮点。
2.列表:可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素或者获得列表的某一个片段。时间复杂度为O(1)。
3.hash类型:把整体看作一个对象,每个field-value相当于对象的属性和属性值。是个典型的字典结构,在value里面不能再嵌套其他的数据类型的格式。
使用场景:hash的存储方式类似于关系型数据库,可以存储一些对象形式的信息。
4.集合类型(set):集合类型中,每个元素都是不同的,也就是不能有重复数据,同时集合类型中的数据是无序的。集合类型和列表类型的最大的区别是有序性和唯一性 集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在。由于集合类型在redis内部是使用的值 为空的散列表,所以这些操作的时间复杂度都是O(1).
5.有序集合 (sorted-set,(zset)):有序集合类型为集合中的每个元素都关联了一个分数,能获得分数最高(或最低)的前N个元素、获得指定分数范围内的元 素等与分数有关的操作。虽然集合中每个元素都是不同的,但是他们的分数却可以相同 。
哈希冲突怎么办:
1.开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列) 2.再哈希法 3.链地址法(Java hashmap就是这么做的)